본문 바로가기

ETC

BookStore 로그아웃 동작 (Springboot Vue)

 

//Vue.js
	Logout(){
      this.$axios.post("/logout")
        .then(() => {
              this.$store.dispatch('logout').then(()=> {
                this.dialogMsg = "로그아웃 성공. 로그인 페이지로 이동합니다"
                this.dialog = true
              })
        }).catch(error =>{
              console.log("error : " + error.response);
        })

    },

1. Vue에서 로그아웃 요청시 WebSecurityConfig에서 다음과 같은 방법으로 로그아웃이 처리된다.

 

//WebSecurityConfig.java
	public void configure(HttpSecurity http) throws Exception {
            http
           
            ...
		.logout()
                .logoutUrl("/logout")
                .logoutSuccessUrl("/")
                .logoutSuccessHandler(logoutSuccessHandler())
                .invalidateHttpSession(true)
    		.deleteCookies("viewCookie")

 

logoutSuccessUrl은 Handler로 따로 지정해줘서 무시된다.

여기서의 로그아웃 핸들러에서는 로그아웃시 토큰을 처리하는 기능을 한다.

invalidateHttpSession 는 로그아웃시 인증정보를 지우하고 세션을 무효화

 

2. 로그아웃 핸들러

    @Bean
    public LogoutSuccessHandler logoutSuccessHandler() {
        CustomLogoutSuccessHandler logoutSuccessHandler = new CustomLogoutSuccessHandler();
        logoutSuccessHandler.setDefaultTargetUrl("/");
        return logoutSuccessHandler;
    }

로그아웃 핸들러 실행

 

@Slf4j
public class CustomLogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler{

    @Autowired
    public TokenService tokenService;

    @Override public void onLogoutSuccess(HttpServletRequest request,
                                          HttpServletResponse response,
                                          Authentication authentication) throws IOException, ServletException {
        log.debug("CustomLogoutSuccessHandler.onLogoutSuccess ::::");

        String requestTokenHeader = request.getHeader("Authorization");
        if (requestTokenHeader != null && requestTokenHeader.startsWith("Bearer ")) {
            String jwtToken = requestTokenHeader.substring(7);
            LocalTime jwtTokenExpTime = getExpTime(jwtToken);		
            Token data = tokenService.insertToken(jwtToken,jwtTokenExpTime);
            log.debug("final : " + data);
        }else {
            log.warn("JWT Token does not begin with Bearer String");
        }
        super.onLogoutSuccess(request, response, authentication);
    }

    public LocalTime getExpTime(String jwtToken){
        JwtTokenUtil jwtTokenUtil = new JwtTokenUtil();
        Date jwtTokenExp = jwtTokenUtil.getExpirationDateFromToken(jwtToken); //jwtTokenUtil 에서 구한 Date
        LocalDateTime time2 = LocalDateTime.ofInstant(jwtTokenExp.toInstant(), ZoneId.systemDefault()); //data -> LocalDataTime
        LocalTime JwtTokenTime = LocalTime.of(time2.getHour(), time2.getMinute(), time2.getSecond()); //LocalDataTime -> LocalTime
        log.debug("time :: " + JwtTokenTime);
        return JwtTokenTime;
    }
}

필터에서 jwtToken을 구하는 것 처럼 Bearer 을 분리해 토큰을 얻은 후 

 

 2-1. requestHeader 에서 토큰을 얻어서 만료시간을 구하는 getExpTime으로 보낸다.

 2-2. getExpTime에서 jwtTokenUtil로 토큰을 보내 만료시간(jwtTokenExp) 을 구한다.

 2-3. jwtTokenExp 객체는 Date이고, 우리가 사용할 데이터는 LocalTime이므로 

    java.util.Date -> java.time.LocalTime 으로 변경한다.

 2-4. 토큰과 getExpTime에서 구한 LocalTime을 DB에 저장하기위해 tokenService로 보낸다. 

 

 

3. 로그아웃된 토큰을 처리하기위해 토큰 서비스로

// tokenService    
    public Token insertToken(String jwtToken, LocalTime jwtTokenExpTime){
        log.debug("token service : " + jwtToken+" && " + jwtTokenExpTime);
        Token tokenInsert = Token.builder()
                .token(jwtToken)
                .expirationTime(jwtTokenExpTime)
                .build();
        return tokenRepository.save(tokenInsert);
    }

 

넘어온 토큰을 토큰과 만료시간을 담아 DB에 저장한다.

토큰과 만료시간이 저장된 DB

 

 DB에서는 받은 토큰과 만료시간을 이벤트 스케줄러를 통해 관리한다.

-- DB
CREATE EVENT IF NOT EXISTS my_delete_event 
ON SCHEDULE EVERY '1' MINUTE STARTS '2022-01-01' 
DO DELETE FROM token  WHERE expirationTime < now();

현재시간이 토큰의 만료시간을 지나면 그 토큰은 스케쥴러에 의해 삭제된다

 

    @Bean
    public LogoutSuccessHandler logoutSuccessHandler() {
        CustomLogoutSuccessHandler logoutSuccessHandler = new CustomLogoutSuccessHandler();
        logoutSuccessHandler.setDefaultTargetUrl("/");
        return logoutSuccessHandler;
    }

그리고 로그아웃 핸들러를 처리 후 setDefaultTargetUrl를 설정해 이동할 경로를 정해준다.