하면서 조금씩 전의 코드가 변경되었음..
/**
* 로그인 인증 관련 서비스
*/
@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도 출력이 되지 않았다...
메세지를 보내야 되는 경우에는 다른 방법을 알아봐야겠다...