2024-06-12 오늘의 TIL jwt(4)

이재성·2024년 6월 13일
post-thumbnail

토큰 재발급 서비스 부분

하면서 조금씩 전의 코드가 변경되었음..

로그인

/**
 * 로그인 인증 관련 서비스
 */
@Slf4j
@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class AuthService implements LogoutHandler {

    /**
     * 관련 클래스 호출
     */
    private final UserRepository userRepository;
    private final BCryptPasswordEncoder bCryptPasswordEncoder;
    private final TokenProvider tokenProvider;
    private final AuthenticationManagerBuilder authenticationManagerBuilder;
    private final MailManager mailManager;
    private static String magickey="";

    /**
     * 로그인 메서드
     * @param username
     * @param password
     * @return
     */
    @Transactional
    public TokenDto login(String username, String password) {
        if (!userRepository.existsByUsername(username)) {
            throw new UsernameNotFoundException(username);
        }
        Optional<User> user = userRepository.findUserByUsernameAndStatus(username, StatusEnum.ACTIVE);

        bCryptPasswordEncoder.matches(password, user.get().getPassword());
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
                username,password);
        // false가 활성화임
        user.get().setExpired(false);

        Authentication authentication = authenticationManagerBuilder.getObject()
                .authenticate(authenticationToken);
        SecurityContext context = SecurityContextHolder.createEmptyContext();
        TokenDto tokenDto = tokenProvider.generateToken(authentication);
        context.setAuthentication(authentication);
        SecurityContextHolder.setContext(context);
        user.get().updateToken(tokenDto.getRefreshToken());

        return tokenDto;
    }

토큰 재발급

리프레시 토큰을 비교하여 새 엑세스 토큰과 리프레시 토큰을 발급함

/**
     * 토큰 재발급 메서드
     * @param refreshToken
     * @return
     */
    @Transactional
    public TokenDto reissue(String refreshToken) {
        Optional<User> user = userRepository.findByRefreshToken(refreshToken);
        if(user!=null && !user.get().getRefreshToken().equals(refreshToken)){
            throw new RuntimeException("잘못된 토큰입니다.");
        }else if(user.get().isExpired()){
            throw new RuntimeException("폐지된 토큰입니다.");
        }
        Authentication authentication = tokenProvider.getAuthentication(refreshToken.substring(7));
        TokenDto tokenDto = tokenProvider.generateToken(authentication);
        user.get().updateToken(tokenDto.getRefreshToken());
        return tokenDto;
    }

헤더의 토큰을 가져와서 비교해서 새 토큰을 발급하는 매서드
"bearer "이 앞에 붙어 있기 때문에 잘라서 비교하지 않으면 에러가 난다
(공백을 받으면 에러가남)

로그아웃 추가

 /**
     * 로그아웃 메서드
     * @param request
     * @param response
     * @param authentication
     */
    @Transactional
    @Override
    public void logout(HttpServletRequest request, HttpServletResponse response , Authentication authentication) {
        String authHeader = request.getHeader(AuthEnum.ACCESS_TOKEN.getValue());

        if (authHeader == null && !authHeader.startsWith(AuthEnum.GRANT_TYPE.getValue())) {
            throw new RuntimeException("알수 없는 access token.");
        }
        String accessToken = authHeader.substring(7);
        String username = tokenProvider.getUsername(accessToken);
        User refreshToken = userRepository.findByUsername(username).orElse(null);
        refreshToken.setExpired(true);
    }

로그아웃 엑세스 토큰을 검증하고 검증에 성공시 유저아이디를 비교해서
맞다면 expired 의 값을 true로 변경시켜 로그아웃 처리를 진행한다.

이에 따라 추가적으로 config파일에 추가해본게 있다.

   /**
         *  로그아웃 URL시 호출성공시
         *  SecurityContextHolder를 비움
         */
        http.logout(auth -> auth
                .logoutUrl("/api/auth/logout")
                .addLogoutHandler(authService)
                .logoutSuccessHandler(
                        (((request, response, authentication) -> SecurityContextHolder.clearContext()))));
        

시큐리티에서 제공하는 기능인데 url의 메서드가 성공적으로 마쳤을 경우
SecurityContextHolder를 비워 주는 기능이다.
테스트 해본 결과 정상적으로 다 비워 주지만 http status도 출력이 되지 않았다...
메세지를 보내야 되는 경우에는 다른 방법을 알아봐야겠다...

profile
하이요

0개의 댓글