티스토리 뷰
remember-me.. 나를 기억해 라는 영화가 문득 떠올랐다. 뭔 내용인지는 거의 90프로 까먹는것 같다. 머리가 점점 휘발성이 되어가는것 같다. 무튼.. 우리가 일상에서 많이 사용하는 자동로그인, 로그인유지 등등의 표현으로 많이 사용하고 있는 remember-me 라는 Spring Security의 기능에 대해 살펴보도록 하겠다.
remember-me가 무슨 기능이냐? 로그인시에 위와 같이 '로그인 유지'라고 되어 있는 체크박스에 체크를 하고 로그인을 하면 내가 브라우저를 닫거나 개발자도구에서 세션을 끊어버리는 등 직접 로그아웃 버튼을 눌러 로그아웃을 하지 않는 이상 remember-me라는 기능이 계속 로그인을 유지시켜준다.
잘 하시는 분들은 이런 기능들을 설명할때도 시퀀스 다이어그램이나 클래스 다이어그램 등을 그리며 멋지게 설명을 해주시지만 나는 잘 못하기에 내가 만들어본 기능을 예제로 보여주며 설명을 하도록 하겠다.
remember-me는 크게 db에 보관하는 방식과 token에 보관하는 방식이 있는데 필자는 token에 보관하는 방식이다.
Login Page (html)
일단은 저 체크박스를 만들어야 한다.
<p>
<label for="remember-me" style>로그인 유지</label>
<input type="checkbox" id="remember-me" name="remember-me" />
</p>
로그인 하는 부분에 살포시 이 체크박스를 껴 넣어주자. 다른건 맘대로 해도 checkbox의 name은 remember-me로 하도록 하자. (바꿀수도 있지만 굳이.. 그냥 기본값을 사용하자.)
Security Config
Spring Security 설정에는 다음 부분을 추가해주도록 하자.
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private RemembermeUserDetailsService remembermeUserDetailsService;
... 생략 ...
@Override
public void configure(HttpSecurity http) throws Exception {
... 생략 ...
http.rememberMe()
.key("oingdaddy!")
.rememberMeParameter("remember-me")
.tokenValiditySeconds(86400 * 30)
.userDetailsService(remembermeUserDetailsService)
.authenticationSuccessHandler(loginSuccessHandler());
}
@Bean
public LoginSuccessHandler loginSuccessHandler() {
LoginSuccessHandler handler = new LoginSuccessHandler();
handler.setDefaultTargetUrl("/main");
return handler;
}
Security의 설정을 하는 부분 중 configure 메소드를 수정한다. http.rememberMe 라는 메소드가 있고 이곳에서 remember-me에 대한 설정을 할 수 있다.
- key : 인증받은 사용자의 정보로 token을 생성하는데 사용되는그때 사용되는 값이다. 필수이다.
- rememberMeParameter : html에서 checkbox name에 해당하는 값이다. 쓰지 않으면 remember-me가 적용된다.
- tokenValiditySeconds : remember-me token의 유효 시간이다. 필자는 한달을 설정해 놓은것이다.
- userDetailService : 인증하는데 필요한 UserDetailService를 넣어줘야 한다. 없다면 만들어야 한다. 필수다!
- authenticationSuccessHandler : remember-me로 로그인 성공 했을때 액션에 대해서 정의해줄수 있는 handler이다.
이렇게 설정을 해주면 설정은 모두 끝난다. Spring Security로 로그인을 여러가지 방식으로 구현할 수 있는데 필자는 UserDetailService를 사용하지 않는 방식이었다. 그래서 이번에 UserDetailService도 하나 만들었다. 왜냐면 없으면 remember-me 기능을 사용할 수 없다.
RemembermeUserDetailService.java
@Service
public class RemembermeUserDetailsService implements UserDetailsService {
@Autowired
private AuthService authService;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Map<String, Object> user = authService.getUser(username);
if (user == null) {
throw new UsernameNotFoundException(username + "is not found.");
}
CustomUserDetails customUserDetails = new CustomUserDetails(username, user.get("USER_PWD").toString());
customUserDetails.setRoles((List<GrantedAuthority>) getAuthorities(username));
return customUserDetails;
}
public Collection<GrantedAuthority> getAuthorities(String username) {
List<Object> authList = authService.getUserRolesList(username);
List<GrantedAuthority> roles = new ArrayList<GrantedAuthority>();
for(int inx = 0 ; inx < authList.size() ; inx ++) {
Map<String, String> auth = (Map<String, String>) authList.get(inx);
roles.add(new SimpleGrantedAuthority(auth.get("AUTHORITY")));
}
return roles;
}
}
username 가지고 CustomUserDetails를 만들어주는 것이라고 보면 된다. 권한 정보까지 모두 가지고 있어야 remember-me로 로그인을 한다고 해도 온전하게 권한에 따라 컨트롤이 가능하다.
CustomUserDetail은 무엇이냐?
public class CustomUserDetails implements UserDetails {
private String username;
private String password;
private List<Map<String,String>> authenticatedMenu = new ArrayList<Map<String,String>>();
private List<GrantedAuthority> roles = new ArrayList<GrantedAuthority>();
이런 인증/인가에 관련된 핵심적인 모델이라고 생각하면 된다. 즉 UserDetailService에서 이 UserDetail에 값을 채워줘야 한다.
그럼 remember-me를 사용하기 위한 모든 준비는 끝이 났다.
테스트
일단 크롬을 열어서 개발자도구를 열어준다.
Application > Cookie tab으로 들어가서 Session을 볼 수 있도록 해주자. 로그인 화면만 열어서 일단 값이 없는 세션이 하나 들어간 것을 확인할 수 있따.
그리고 로그인 화면에서 만든 remember-me 체크박스에 체크를 하고 로그인을 하자.
이걸 체크하고 로그인 한다는건 remember-me 기능을 활용하겠다는 것이다. 로그인!
로그인을 하면 아래에 remember-me라는 쿠키가 생성된것을 확인할 수 있다. 정상적으로 잘 생성이 되었다.
그럼 이제 유효한 세션을 날려보도록 하자. remember-me 아래에 JSESSIONID를 우클릭 하고 Delete 해준다.
그럼 이제 remember-me 쿠키만 남아있다. 이 상태에서 화면을 새로고침 해보자.
그럼 새로운 유효한 세션이 생성이 되며 화면이 정상적으로 나온다.
성공적으로 잘 적용이 되었다.
끝!
'Framework > Security' 카테고리의 다른 글
Spring boot Security 기본 로그인 방법 및 계정 (0) | 2022.02.09 |
---|---|
OWASP Top 10 2021 한글 version (0) | 2021.09.08 |
KeyCloak Session, Token Timeout 설정하기 (0) | 2021.01.14 |
JasperException : security/tags cannot be resolved in either web.xml or the jar files deployed with this application 오류 (0) | 2021.01.13 |
KeyCloak OAuth2를 활용해서 SSO 로그인 하기 (google) (5) | 2021.01.12 |