diff --git a/src/main/java/com/kyonggi/teampu/domain/auth/controller/ReissueController.java b/src/main/java/com/kyonggi/teampu/domain/auth/controller/ReissueController.java new file mode 100644 index 0000000..a6d0510 --- /dev/null +++ b/src/main/java/com/kyonggi/teampu/domain/auth/controller/ReissueController.java @@ -0,0 +1,24 @@ +package com.kyonggi.teampu.domain.auth.controller; + +import com.kyonggi.teampu.domain.auth.service.ReissueService; +import com.kyonggi.teampu.global.response.ApiResponse; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api") +public class ReissueController { + private final ReissueService reissueService; + @PostMapping("/reissue") + ApiResponse reissue(HttpServletRequest request, HttpServletResponse response){ + String newAccess = reissueService.createNewAccessToken(request, response); + response.addHeader("Authorization", "Bearer " + newAccess); + + return ApiResponse.ok(); + } +} diff --git a/src/main/java/com/kyonggi/teampu/domain/auth/service/CustomMemberDetailsService.java b/src/main/java/com/kyonggi/teampu/domain/auth/service/CustomMemberDetailsService.java index 10ff653..221e55e 100644 --- a/src/main/java/com/kyonggi/teampu/domain/auth/service/CustomMemberDetailsService.java +++ b/src/main/java/com/kyonggi/teampu/domain/auth/service/CustomMemberDetailsService.java @@ -9,8 +9,6 @@ import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; -import java.util.Optional; - @Service @RequiredArgsConstructor public class CustomMemberDetailsService implements UserDetailsService { @@ -18,18 +16,10 @@ public class CustomMemberDetailsService implements UserDetailsService { @Override public UserDetails loadUserByUsername(String loginId) throws UsernameNotFoundException { - Optional member = memberRepository.findByLoginId(loginId); - - if (member.isEmpty()) { - throw new UsernameNotFoundException("해당 유저를 찾을 수 없습니다: " + loginId); - //UserDetails에 담아서 return하면 AutneticationManager가 검증 함 - } - - System.out.println("**************Found user***************"); - System.out.println(" loginId : " + member.get().getLoginId()); - System.out.println(" password : " + member.get().getPassword()); - System.out.println("***************************************"); + //UserDetails에 담아서 return하면 AutneticationManager가 검증 함 + Member member = memberRepository.findByLoginId(loginId) + .orElseThrow(() -> new UsernameNotFoundException("해당 유저를 찾을 수 없습니다: " + loginId)); - return new CustomMemberDetails(member.get()); + return new CustomMemberDetails(member); } } diff --git a/src/main/java/com/kyonggi/teampu/domain/auth/service/ReissueService.java b/src/main/java/com/kyonggi/teampu/domain/auth/service/ReissueService.java new file mode 100644 index 0000000..12363e3 --- /dev/null +++ b/src/main/java/com/kyonggi/teampu/domain/auth/service/ReissueService.java @@ -0,0 +1,73 @@ +package com.kyonggi.teampu.domain.auth.service; + +import com.kyonggi.teampu.domain.auth.domain.RefreshToken; +import com.kyonggi.teampu.domain.auth.repository.RefreshTokenRepository; +import com.kyonggi.teampu.global.util.JwtUtil; +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseCookie; +import org.springframework.stereotype.Service; + +import java.util.Arrays; + +import static com.kyonggi.teampu.global.exception.ErrorCode.*; + +@Service +@RequiredArgsConstructor +public class ReissueService { + private final JwtUtil jwtUtil; + private final RefreshTokenRepository refreshTokenRepository; + + public String createNewAccessToken(HttpServletRequest request, HttpServletResponse response) { + String refreshToken = getRefreshTokenFromCookies(request); + String loginId = validateAndGetLoginId(refreshToken); + + refreshTokenRepository.deleteById(refreshToken); + String newAccessJwt = jwtUtil.createJwt("access", loginId, 30 * 60 * 1000L); + String newRefreshJwt = jwtUtil.createJwt("refresh", "fakeLoginId", 24 * 60 * 60 * 1000L); + RefreshToken newRefreshToken = new RefreshToken(newRefreshJwt, loginId); + refreshTokenRepository.save(newRefreshToken); + + response.addHeader("Set-Cookie", createCookie("refresh", newRefreshJwt).toString()); + + return newAccessJwt; + } + + private String getRefreshTokenFromCookies(HttpServletRequest request) { + return Arrays.stream(request.getCookies()) + .filter(cookie -> cookie.getName().equals("refresh")) + .map(Cookie::getValue) + .findAny() + .orElseThrow(() -> new IllegalArgumentException(NOT_FOUND_REFRESH_TOKEN.getMessage())); + } + + private String validateAndGetLoginId(String refreshToken) { + if (!jwtUtil.validateToken(refreshToken)) { + throw new IllegalStateException(INVALID_REFRESH_TOKEN.getMessage()); + } + if (jwtUtil.isExpired(refreshToken)) { + throw new IllegalStateException(EXPIRED_REFRESH_TOKEN.getMessage()); + } + if (!jwtUtil.getCategory(refreshToken).equals("refresh")) { + throw new IllegalStateException(INVALID_REFRESH_TOKEN.getMessage()); + } + + RefreshToken refreshTokenEntity = refreshTokenRepository.findById(refreshToken) + .orElseThrow(() -> new IllegalStateException(INVALID_REFRESH_TOKEN.getMessage())); + + return refreshTokenEntity.getLoginId(); + } + + private ResponseCookie createCookie(String key, String value) { + return ResponseCookie.from(key, value) + .path("/") //쿠키 경로 설정(=도메인 내 모든경로) + .sameSite("None") //sameSite 설정 (크롬에서 사용하려면 해당 설정이 필요함) + .httpOnly(false) //JS에서 쿠키 접근 가능하도록함 + .secure(true) // HTTPS 연결에서만 쿠키 사용 sameSite 설정시 필요 + .maxAge(24 * 60 * 60)// 쿠키 유효기간 설정 (=refresh 토큰 만료주기) + .build(); + } + +} diff --git a/src/main/java/com/kyonggi/teampu/domain/myPage/repository/MemberRepository.java b/src/main/java/com/kyonggi/teampu/domain/myPage/repository/MemberRepository.java deleted file mode 100644 index 28ecc05..0000000 --- a/src/main/java/com/kyonggi/teampu/domain/myPage/repository/MemberRepository.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.kyonggi.teampu.domain.myPage.repository; - -import com.kyonggi.teampu.domain.member.domain.Member; -import org.springframework.data.jpa.repository.JpaRepository; - -import java.util.Optional; - -public interface MemberRepository extends JpaRepository { - Optional findByLoginId(String loginId); -} diff --git a/src/main/java/com/kyonggi/teampu/domain/myPage/service/MyPageService.java b/src/main/java/com/kyonggi/teampu/domain/myPage/service/MyPageService.java index ad33642..38a29f9 100644 --- a/src/main/java/com/kyonggi/teampu/domain/myPage/service/MyPageService.java +++ b/src/main/java/com/kyonggi/teampu/domain/myPage/service/MyPageService.java @@ -1,9 +1,9 @@ package com.kyonggi.teampu.domain.myPage.service; import com.kyonggi.teampu.domain.member.domain.Member; +import com.kyonggi.teampu.domain.member.repository.MemberRepository; import com.kyonggi.teampu.domain.myPage.dto.MyPageRequest; import com.kyonggi.teampu.domain.myPage.dto.MyPageResponse.MyPageDTO; -import com.kyonggi.teampu.domain.myPage.repository.MemberRepository; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; diff --git a/src/main/java/com/kyonggi/teampu/global/config/RedisConfig.java b/src/main/java/com/kyonggi/teampu/global/config/RedisConfig.java new file mode 100644 index 0000000..03e6d6e --- /dev/null +++ b/src/main/java/com/kyonggi/teampu/global/config/RedisConfig.java @@ -0,0 +1,34 @@ +package com.kyonggi.teampu.global.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.serializer.StringRedisSerializer; + +@Configuration +public class RedisConfig { + + @Value("${spring.data.redis.port}") + private int port; + + @Value("${spring.data.redis.host}") + private String host; + + @Bean + public RedisConnectionFactory redisConnectionFactory() { + return new LettuceConnectionFactory(host, port); + } + + @Bean + public RedisTemplate redisTemplate() { + RedisTemplate redisTemplate = new RedisTemplate<>(); + redisTemplate.setKeySerializer(new StringRedisSerializer()); + redisTemplate.setValueSerializer(new StringRedisSerializer()); + redisTemplate.setConnectionFactory(redisConnectionFactory()); + + return redisTemplate; + } +} diff --git a/src/main/java/com/kyonggi/teampu/global/config/SecurityConfig.java b/src/main/java/com/kyonggi/teampu/global/config/SecurityConfig.java index 4228fb0..ac66d54 100644 --- a/src/main/java/com/kyonggi/teampu/global/config/SecurityConfig.java +++ b/src/main/java/com/kyonggi/teampu/global/config/SecurityConfig.java @@ -52,7 +52,6 @@ public BCryptPasswordEncoder bCryptPasswordEncoder() { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - //CORS 설정 http.cors((cors) -> cors .configurationSource(request -> { CorsConfiguration configuration = new CorsConfiguration(); @@ -70,24 +69,28 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.httpBasic(AbstractHttpConfigurer::disable); http.authorizeHttpRequests(auth -> auth - .requestMatchers(PUBLIC_URLS).permitAll() - .anyRequest().authenticated()); + .requestMatchers(PUBLIC_URLS).permitAll() + .anyRequest().authenticated()); http.exceptionHandling(exceptionHandling -> exceptionHandling .authenticationEntryPoint(customEntryPoint)); - //소셜 로그인시 무한 루프 문제 해결을 위해 인가 검증필터는 로그인 필터 이후에 삽입 + http.addFilterAfter(new JwtFilter(jwtUtil, memberRepository), UsernamePasswordAuthenticationFilter.class) - //인증 필터 자리에 커스텀한 로그인 필터 삽입 .addFilterAt( - new LoginFilter(authenticationManager(authenticationConfiguration), refreshTokenRepository, jwtUtil, - memberRepository, "/api/login"), - UsernamePasswordAuthenticationFilter.class) - //로그아웃 전에 커스텀한 로그아웃 필터 적용 + new LoginFilter( + authenticationManager(authenticationConfiguration), + refreshTokenRepository, + jwtUtil, + memberRepository, + "/api/login"), + //소셜 로그인시 무한 루프 문제 해결을 위해 인가 검증필터는 로그인 필터 이후에 삽입 + UsernamePasswordAuthenticationFilter.class + ) .addFilterBefore(new CustomLogoutFilter(jwtUtil, refreshTokenRepository), LogoutFilter.class); http.sessionManagement((session) -> session - .sessionCreationPolicy(SessionCreationPolicy.STATELESS)); + .sessionCreationPolicy(SessionCreationPolicy.STATELESS)); return http.build(); } diff --git a/src/main/java/com/kyonggi/teampu/global/filter/CustomEntryPoint.java b/src/main/java/com/kyonggi/teampu/global/filter/CustomEntryPoint.java index 5627247..82932a1 100644 --- a/src/main/java/com/kyonggi/teampu/global/filter/CustomEntryPoint.java +++ b/src/main/java/com/kyonggi/teampu/global/filter/CustomEntryPoint.java @@ -3,7 +3,6 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.kyonggi.teampu.global.exception.ErrorCode; import com.kyonggi.teampu.global.response.ApiResponse; -import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import lombok.extern.slf4j.Slf4j; @@ -14,7 +13,7 @@ import java.io.IOException; -import static com.kyonggi.teampu.global.exception.ErrorCode.*; +import static com.kyonggi.teampu.global.exception.ErrorCode.MEMBER_NOT_AUTHENTICATED; @Slf4j @Component @@ -24,7 +23,7 @@ public void commence( HttpServletRequest request, HttpServletResponse response, AuthenticationException e - ) throws IOException, ServletException { + ) throws IOException { createAPIResponse(response, MEMBER_NOT_AUTHENTICATED); } diff --git a/src/main/java/com/kyonggi/teampu/global/filter/CustomLogoutFilter.java b/src/main/java/com/kyonggi/teampu/global/filter/CustomLogoutFilter.java index 2977df8..9f87483 100644 --- a/src/main/java/com/kyonggi/teampu/global/filter/CustomLogoutFilter.java +++ b/src/main/java/com/kyonggi/teampu/global/filter/CustomLogoutFilter.java @@ -6,7 +6,6 @@ import com.kyonggi.teampu.global.exception.ErrorCode; import com.kyonggi.teampu.global.response.ApiResponse; import com.kyonggi.teampu.global.util.JwtUtil; -import com.sun.jdi.request.InvalidRequestStateException; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.ServletRequest; @@ -20,6 +19,7 @@ import org.springframework.web.filter.GenericFilterBean; import java.io.IOException; +import java.util.Arrays; import java.util.Optional; import static com.kyonggi.teampu.global.exception.ErrorCode.*; @@ -43,81 +43,63 @@ private void doFilter( HttpServletResponse response, FilterChain filterChain ) throws IOException, ServletException { - - //요청 url이 "/api/logout" 이 아닌 경우 다음 필터로 넘김 String requestUri = request.getRequestURI(); if (!requestUri.matches("^\\/api/logout$")) { filterChain.doFilter(request, response); return; } - // 요청 메서드가 POST 가 아닌 경우 다음 필터로 넘김 String requestMethod = request.getMethod(); if (!requestMethod.equals("POST")) { filterChain.doFilter(request, response); return; } - //토큰 추출 String refreshToken = getRefreshTokenFromCookies(request); - //토큰 검증 실패시 다음 필터로 넘김 if (!isTokenValid(refreshToken, response)) { return; } - //Redis에 저장되어있는 토큰 삭제 - refreshTokenRepository.deleteById(refreshToken); - //Refresh 토큰 Cookie 값 0 + refreshTokenRepository.deleteById(refreshToken); Cookie cookie = new Cookie("refresh", null); cookie.setMaxAge(0); cookie.setPath("/"); cookie.setHttpOnly(false); response.addCookie(cookie); - //API 응답 생성 및 다음 필터로 넘기지 않음 - createAPIResponse(response); + createSuccessResponse(response); } + private String getRefreshTokenFromCookies(HttpServletRequest request) { - // 쿠키에서 리프레쉬 토큰을 찾아옴 - String refresh = null; - Cookie[] cookies = request.getCookies(); - for (Cookie cookie : cookies) { - if (cookie.getName().equals("refresh")) { - refresh = cookie.getValue(); - } - } - // 찾을 수 없으면 예외처리 - if (refresh == null) { - throw new InvalidRequestStateException("쿠키에 refresh token 을 찾아올 수 없습니다"); - } - return refresh; + return Arrays.stream(request.getCookies()) + .filter(cookie -> cookie.getName().equals("refresh")) + .map(Cookie::getValue) + .findAny() + .orElseThrow(() -> new IllegalArgumentException(NOT_FOUND_REFRESH_TOKEN.getMessage())); } + private boolean isTokenValid(String refreshToken, HttpServletResponse response) throws IOException { if (!jwtUtil.validateToken(refreshToken)) { - createAPIResponse(response, INVALID_REFRESH_TOKEN); + createExceptionResponse(response, INVALID_REFRESH_TOKEN); return false; } - // refresh 토큰 만료 시 예외처리 if (jwtUtil.isExpired(refreshToken)) { - createAPIResponse(response, EXPIRED_REFRESH_TOKEN); + createExceptionResponse(response, EXPIRED_REFRESH_TOKEN); return false; } - // 페이로드에 refresh 토큰이 아니면 예외처리 (ex access token) - String category = jwtUtil.getCategory(refreshToken); - if (!category.equals("refresh")) { - createAPIResponse(response, INVALID_REFRESH_TOKEN); + if (!jwtUtil.getCategory(refreshToken).equals("refresh")) { + createExceptionResponse(response, INVALID_REFRESH_TOKEN); return false; } - // 해당 토큰이 Redis에 저장되어 있지 않으면 예외처리 + Optional refreshTokenEntity = refreshTokenRepository.findById(refreshToken); if (refreshTokenEntity.isEmpty()) { - createAPIResponse(response, INVALID_REFRESH_TOKEN); + createExceptionResponse(response, INVALID_REFRESH_TOKEN); return false; } + return true; - // 위 상황 처럼 refresh token 에 문제가 있으면 로그아웃을 못하나요?? - // -> refresh 토큰에 문제가 있으면 access 토큰 재발급 자체가 안됨 (=이미 로그아웃된 상태) } - private void createAPIResponse(HttpServletResponse response, ErrorCode errorCode) throws IOException { + private void createExceptionResponse(HttpServletResponse response, ErrorCode errorCode) throws IOException { ApiResponse apiResponse = ApiResponse.exception(errorCode); response.setStatus(errorCode.getHttpStatus().value()); response.setContentType(MediaType.APPLICATION_JSON_VALUE); @@ -126,7 +108,7 @@ private void createAPIResponse(HttpServletResponse response, ErrorCode errorCode mapper.writeValue(response.getWriter(), apiResponse); } - private void createAPIResponse(HttpServletResponse response) throws IOException { + private void createSuccessResponse(HttpServletResponse response) throws IOException { ApiResponse apiResponse = ApiResponse.ok(); response.setStatus(HttpStatus.OK.value()); response.setContentType(MediaType.APPLICATION_JSON_VALUE); diff --git a/src/main/java/com/kyonggi/teampu/global/filter/JwtFilter.java b/src/main/java/com/kyonggi/teampu/global/filter/JwtFilter.java index 7a76545..ebcd45a 100644 --- a/src/main/java/com/kyonggi/teampu/global/filter/JwtFilter.java +++ b/src/main/java/com/kyonggi/teampu/global/filter/JwtFilter.java @@ -42,40 +42,31 @@ protected void doFilterInternal( if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) { accessToken = authorizationHeader.substring(7); } - // 토큰이 없다면 다음 필터로 넘김 if (!StringUtils.hasText(accessToken)) { filterChain.doFilter(request, response); return; } - //이하 토큰 검증 실패시 다음 필터로 넘기지 않음 - // 올바르지 않은 토큰(=토큰 검증 실패) 인지 확인 if (!jwtUtil.validateToken(accessToken)) { - createAPIResponse(response, INVALID_AUTH_TOKEN); + createExceptionResponse(response, INVALID_AUTH_TOKEN); return; } - // 토큰 만료 여부 확인 if (jwtUtil.isExpired(accessToken)) { - createAPIResponse(response, EXPIRED_AUTH_TOKEN); + createExceptionResponse(response, EXPIRED_AUTH_TOKEN); return; } - //access 토큰인지 확인 - String category = jwtUtil.getCategory(accessToken); - if (!category.equals("access")) { - createAPIResponse(response, INVALID_AUTH_TOKEN); + if (!jwtUtil.getCategory(accessToken).equals("access")) { + createExceptionResponse(response, INVALID_AUTH_TOKEN); return; } - //토큰에서 유저 이메일 정보 추출 String loginId = jwtUtil.getLoginId(accessToken); Optional member = memberRepository.findByLoginId(loginId); - //해당 이메일로 가입한 유저가 존재하는지 확인 if (member.isEmpty()) { - createAPIResponse(response, MEMBER_NOT_FOUND); + createExceptionResponse(response, MEMBER_NOT_FOUND); return; } - // 찾은 유저 정보로 UserDetails 생성 CustomMemberDetails customMemberDetails = new CustomMemberDetails(member.get()); //스프링 시큐리티 인증 토큰 생성 Authentication authToken = new UsernamePasswordAuthenticationToken(customMemberDetails, null, @@ -86,7 +77,7 @@ protected void doFilterInternal( filterChain.doFilter(request, response); } - private void createAPIResponse(HttpServletResponse response, ErrorCode errorCode) throws IOException { + private void createExceptionResponse(HttpServletResponse response, ErrorCode errorCode) throws IOException { ApiResponse apiResponse = ApiResponse.exception(errorCode); response.setStatus(errorCode.getHttpStatus().value()); response.setContentType(MediaType.APPLICATION_JSON_VALUE); diff --git a/src/main/java/com/kyonggi/teampu/global/filter/LoginFilter.java b/src/main/java/com/kyonggi/teampu/global/filter/LoginFilter.java index 996aacd..214c88e 100644 --- a/src/main/java/com/kyonggi/teampu/global/filter/LoginFilter.java +++ b/src/main/java/com/kyonggi/teampu/global/filter/LoginFilter.java @@ -51,17 +51,15 @@ public LoginFilter( setFilterProcessesUrl(url); } - //로그인 시도시 작동 @Override - public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws - AuthenticationException { - //request 받은 json 값을 추출함 + public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) + throws AuthenticationException { Map loginInfo = getLoginInfoFromJson(request); String loginId = loginInfo.get("loginId"); String password = loginInfo.get("password"); - //해당 값이 없을시 예외처리 + if (loginId == null) { - throw new InvalidRequestStateException("이메일을 입력해 주세요"); + throw new InvalidRequestStateException("아이디을 입력해 주세요"); } if (password == null) { throw new InvalidRequestStateException("비밀번호를 입력해 주세요"); @@ -73,41 +71,35 @@ public Authentication attemptAuthentication(HttpServletRequest request, HttpServ return authenticationManager.authenticate(authToken); } - //로그인 성공시 작동 - 토큰을 생성하고 해당 내용을 프론ㅌ @Override protected void successfulAuthentication( - HttpServletRequest request, - HttpServletResponse response, - FilterChain chain, - Authentication authResult - ) throws IOException, ServletException { - //인증에 성공한 loginId 받아오기 + HttpServletRequest request, + HttpServletResponse response, + FilterChain chain, + Authentication authResult + ) throws IOException { String loginId = authResult.getName(); Member member = memberRepository.findByLoginId(loginId) - .orElseThrow(() -> new InvalidRequestStateException("존재하지 않는 사용자입니다.")); + .orElseThrow(() -> new InvalidRequestStateException("존재하지 않는 사용자입니다.")); - //토큰 생성 - access 토큰 유효기간 30분 - String accessToken = jwtUtil.createJwt("access", loginId, 30 * 60 * 1000L); - //토큰 생성 - refresh 토큰 유효기간 1일 (refresh 토큰에서는 사용자 정보를 포함하지 않음) + String accessToken = jwtUtil.createJwt("access", loginId, 7 * 24 * 60 * 60 * 1000L); String refresh = jwtUtil.createJwt("refresh", "fakeLoginId", 24 * 60 * 60 * 1000L); - response.addHeader("Authorization", "Bearer " + accessToken);// 헤더에 access 토큰 넣기 - response.addHeader("Set-Cookie", createCookie("refresh", refresh).toString()); //쿠키 생성밒 추가 - // refresh 토큰 객체 생성 및 Redis 저장 + response.addHeader("Authorization", "Bearer " + accessToken); + response.addHeader("Set-Cookie", createCookie("refresh", refresh).toString()); + RefreshToken refreshToken = new RefreshToken(refresh, loginId); refreshTokenRepository.save(refreshToken); - //API 응답 생성 - // createAPIResponse(response, REQUEST_OK); - createUserResponse(response, member); + createLoginSuccessResponse(response, member); } - //로그인 실패시 작동 - 실패시 json 응답을 작성해 보내는것이 목적 @Override - protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, - AuthenticationException failed) throws IOException, ServletException { - - //API 응답 생성 - failed 예외는 BadCredentialsException 하나로만 처리함 - createAPIResponse(response, INCORRECT_AUTH_INFO); + protected void unsuccessfulAuthentication( + HttpServletRequest request, + HttpServletResponse response, + AuthenticationException failed + ) throws IOException { + createLoginFailResponse(response, INCORRECT_AUTH_INFO); } private ResponseCookie createCookie(String key, String value) { @@ -120,7 +112,7 @@ private ResponseCookie createCookie(String key, String value) { .build(); } - private void createAPIResponse(HttpServletResponse response, ErrorCode errorCode) throws IOException { + private void createLoginFailResponse(HttpServletResponse response, ErrorCode errorCode) throws IOException { ApiResponse apiResponse = ApiResponse.exception(errorCode); response.setStatus(errorCode.getHttpStatus().value()); response.setContentType(MediaType.APPLICATION_JSON_VALUE); @@ -130,7 +122,7 @@ private void createAPIResponse(HttpServletResponse response, ErrorCode errorCode } @Transactional - protected void createUserResponse(HttpServletResponse response, Member member) throws IOException { + protected void createLoginSuccessResponse(HttpServletResponse response, Member member) throws IOException { MemberInfoResponse memberInfoResponse = new MemberInfoResponse(member); ApiResponse apiResponse = ApiResponse.ok(memberInfoResponse); response.setStatus(200); @@ -140,7 +132,6 @@ protected void createUserResponse(HttpServletResponse response, Member member) t mapper.writeValue(response.getWriter(), apiResponse); } - // JSON 파일을 읽고 반환하는 역할 private Map getLoginInfoFromJson(HttpServletRequest request) { if (!"application/json".equals(request.getContentType())) { throw new InvalidRequestStateException("JSON 형식이 아닙니다"); diff --git a/src/main/java/com/kyonggi/teampu/global/util/JwtUtil.java b/src/main/java/com/kyonggi/teampu/global/util/JwtUtil.java index 2a6350d..633da8f 100644 --- a/src/main/java/com/kyonggi/teampu/global/util/JwtUtil.java +++ b/src/main/java/com/kyonggi/teampu/global/util/JwtUtil.java @@ -19,7 +19,7 @@ public JwtUtil(@Value("${spring.jwt.secret}") String secret) { Jwts.SIG.HS256.key().build().getAlgorithm()); } - //claim 에서 email 정보 추출 + //claim 에서 loginId 정보 추출 public String getLoginId(String token) { return Jwts.parser() .verifyWith(secretKey) @@ -49,7 +49,7 @@ public boolean isExpired(String token) { } } - //JWT 토큰 생성 Claim 에는 토큰 종류와 email 만 담음 + //JWT 토큰 생성 Claim 에는 토큰 종류와 loginId 만 담음 public String createJwt(String category, String loginId, Long expiredMs) { return Jwts.builder() .claim("category", category)