아이디 저장은 구현을 했지만 로그인 유지도 해보고 싶어서 로그인 유지도 구현해 보았습니다.
Spring Security 설정에 작성한 코드입니다.
http.rememberMe()
.key("personalKey")
.tokenValiditySeconds(60 * 60 * 24)
.userDetailsService(principalDetailsService)
.authenticationSuccessHandler(loginSuccessHandler());
@Bean
public AuthenticationSuccessHandler loginSuccessHandler(){
SimpleUrlAuthenticationSuccessHandler simpleUrlAuthenticationSuccessHandler = new SimpleUrlAuthenticationSuccessHandler();
simpleUrlAuthenticationSuccessHandler.setDefaultTargetUrl("/main");
return simpleUrlAuthenticationSuccessHandler;
}
key : 인증받은 사용자의 정보로 token을 생성하는 데 사용되는 그때 사용되는 값입니다.
tokenValiditySeconds : remember-me token의 유효 시간입니다.
userDetailService : 인증하는데 필요한 UserDetailService를 넣어줘야 합니다.
authenticationSuccessHandler : 성공적으로 인증될 때 사용자가 응답을 제어할 수 있습니다.
@Slf4j
@Service
@RequiredArgsConstructor
public class PrincipalDetailsService implements UserDetailsService{
private final UserRepository userRepository;
@Log
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User userEntity = null;
try {
userEntity = userRepository.findUserByUserId(username);
} catch (Exception e) {
e.printStackTrace();
throw new UsernameNotFoundException(username);
}
if(userEntity == null) {
throw new UsernameNotFoundException(username + "사용자이름은 사용 할 수 없습니다.");
}
return new PrincipalDetails(userEntity);
}
}
UserDetailsService의 구현체입니다.
로그인전의 쿠키입니다.
로그인 유지를 선택 후 로그인 후 쿠키입니다.
remember-me라는 쿠키가 하나 생겼습니다.
이 상태에서 JSESSIONID를 삭제해보겠습니다.
삭제 후 새로고침을 해보면
JSESSIONID가 다시 생겼습니다.
원래는 로그인 정보가 사라져 로그아웃이 되어야 하지만 remember-me 토큰이 유효하기 때문에
토큰을 확인하고 정상이면 새로운 인증 객체를 만들어 줍니다.
여기서 한가지 걸리는 부분이 있는데 처음 로그인 유지를 하고 로그인을 하게 되고 권한이 없는 상태에서
권한이 필요한 요청을 하면 403 에러가 정상적으로 나오지만
세션을 종료한 후 remember-me 토큰으로 새로운 인증 객체를 받은 상태로 권한이 필요한 요청을 하면
로그인 페이지로 넘어가버립니다.
문제점
AccessDeniedException는 권한이 없다는 예외인데, isAnonymous()나 isRememberMe()인지 검사를 하고
만약 isRememberMe()가 true이면 RequestCahce를 가지고 AuthenticationException취급하여 로그인 페이지로 이동을 시킨다고 합니다.
익명의 사용자인 isAnonymous()도 마찬가지로, 권한이 없어서 요청이 거부당하지 않고 인증 예외로 로그인 페이지로 이동시킵니다.
rememberMe경우에도 모든 권한을 가지고 있지 않고 특정 권한만 가질 수 있다 보니, USER가 ADMIN에 접근하는 등의 상황에서 ADMIN 권한을 가진 계정으로 로그인을 요청을 한다고 합니다.
그런데 또 이상한 것은 저는 분명 authenticationSuccessHandler는
성공적으로 인증되었을 때 응답을 해줄 수 있는데 저 설정을 해주면 /main으로 보내버립니다.
분명 인증 예외가 발생해서 로그인 페이지로 보내지는 과정인데 인증되었을 때 발생하는 authenticationSuccessHandler가 응답되는지 이것도 모르겠습니다.
그래서 Security 설정을 저렇게 하고 세션을 종료하고 다시 인증 객체를 받고 나서 권한이 필요한 요청을 한다면 로그인 페이지가 아닌 /main으로 넘어갑니다.
이것에 대한 해결방법을 아직 찾지 못했습니다...
임시방편 - 2022/11/22 추가
세션 종료 후 권한이 필요한 요청에 실패하였을 경우 AuthenticationException이 발생을 하는데
이때 직접 만들어준 CustomAuthenticationEntryPoint에서 Manager, Admin 권한을 필요로 한 URI를 확인하고
직접 alert창을 띄어주고 강제로 /main으로 이동시키면 될 것 같습니다.
String uri = request.getRequestURI();
stringBuilder.append("<html><head></head><body><script>");
if(uri.contains("/manager/")){
stringBuilder.append("alert(\'접근 권한이 없습니다.\');");
stringBuilder.append("location.href=\'/main\';");
}
stringBuilder.append("</script></body></html>");
response.getWriter().print(stringBuilder.toString());
'Spring boot > 위니아에이드 클론코딩 프로젝트' 카테고리의 다른 글
[위니아에이드] 팀 프로젝트 - AWS S3 이미지 업로드 (1) | 2022.11.17 |
---|---|
[위니아에이드] 팀 프로젝트 - 이미지 삽입과 업로드 (0) | 2022.11.11 |
[위니아에이드] 팀 프로젝트 - 쿠키를 이용한 아이디 저장 (0) | 2022.10.27 |
[위니아에이드] 팀 프로젝트 - 인증 실패 설정 (0) | 2022.10.26 |
[위니아에이드] 팀 프로젝트 - AOP를 활용한 Validation 체크 (0) | 2022.10.26 |
댓글