[Spring Security] RememberMe로그인 유지하기

Junseo Kim·2020년 4월 17일
1

간단한 Tip

목록 보기
8/20

로그인 시, jsessionid(tomcat 컨테이너에서 세션을 유지하기 위해 발급하는 키)가 생긴다. 이것을 통해 웹브라우저와 서버가 연결된다.

이 id에 해당하는 서버 쪽에 세션이라는 메모리가 있다.

만약 이것에 해당하는 객체가 서버 쪽에 없거나, 클라이언트가 키값을 보내지 않으면 세션을 찾지 못한다. 즉 세션에 넣어논 정보는 무의미하다.

스프링부트의 기본 세션 타임은 30분이다. 만약 이 값이 많이 커지면 불필요한 메모리 낭비가 심하다.

메모리 낭비를 막으면서 로그인을 유지하고 싶으면 Remember-me라는 것을 이용해야한다.

Remember-Me

Remember-me는 쿠키를 하나 더 사용하는 것이다. 인증을 했을 때, 쿠키에 암호화한 인증정보를 담아서 넣어놓는다. 이 값은 세션이 만료되었거나, 세션이 없을 때 사용한다. 즉, 해당 요청에 해당하는 세션을 찾지 못할 때, 같이 보내온 Remember-me 쿠키가 있으면 그 쿠키에 들어있는 인증정보로 인증을 시도한다. 인증이 성공하면, 새로운 세션 id와 쿠키가 발급이된다.

이러한 경우 문제점이 하나 있다. 로그인 시 쿠키를 탈취 당할 수 있다. 로그아웃시 세션과 쿠키를 모두 날려줘야한다.

좀 더 안전한 방법이 있다. 랜덤한 토큰값(매번 바뀜)을 사용하고, 랜덤한 시리즈(고정)라는 것을 사용한다. 토큰은 매번 인증할 때마다 새로 바뀌고, 시리즈는 인증을 해도 바뀌지 않는다.

이 경우 해커가 쿠키를 탈취하면, 사용자가 인증하려고 할 때, 유효하지 않은 토큰과 유효한 시리즈의 username으로 접속한다. 이 경우 토큰이 유효하지 않기 때문에 모든 토큰을 삭제하여 해커가 더 이상 탈취한 쿠키를 사용하지 못하도록 방지해준다. 그 후, form 기반으로 다시 로그인한다.

Spring Security 설정

http.rememberMe()에 userDetailsService(DB에서 유저 정보를 가져오는 역할)의 구현체와 JdbcTokenRepositoryImpl(dataSource)타입을 값으로 준다.

@Configuration
@EnableWebSecurity // spring security 설정을 개발자가 하겠다는 뜻
@RequiredArgsConstructor
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private final AccountService accountService; // UserDetailsService 구현체
    private final DataSource dataSource;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
    
       // ...

        http.rememberMe()
                .userDetailsService(accountService)
                .tokenRepository(tokenRepository()); // username, 토큰, 시리즈를 조합한 토큰 정보를 DB에 저장(rememberMe 쿠키랑 일치하는 지 확인하기 위함)
    }

    // tokenRepository의 구현체
    @Bean
    public PersistentTokenRepository tokenRepository() {
        JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
        jdbcTokenRepository.setDataSource(dataSource);
        return jdbcTokenRepository;
    }


}

설정을 해주는 게 끝이 아니라, 쿠키값을 사용하기 위한 엔티티도 만들어줘야한다.

@Table(name = "persistent_logins")
@Entity
@Getter @Setter
public class PersistentLogins {

    @Id
    @Column(length = 64)
    private String series;

    @Column(nullable = false, length = 64)
    private String username;

    @Column(nullable = false, length = 64)
    private String token;

    @Column(name = "last_used", nullable = false, length = 64)
    private LocalDateTime lastUsed;
}

마지막으로, 로그인 뷰에 로그인 유지 체크박스를 만들어준다.

                <!-- 이 값이 true여야지 rememberme 쿠키를 만들어준다. -->
                <div class="form-group form-check">
                    <input type="checkbox" class="form-check-input" id="rememberMe" name="remember-me" checked>
                    <label class="form-check-label" for="rememberMe" aria-describedby="rememberMeHelp">로그인 유지</label>
                </div>

0개의 댓글