feat(user-service): JWT 토큰 관련 로직 변경

- access token 재발급 시 response body에 만료 시간 추가
- 페이지 이동 시 사용할 access token check 로직 추가
This commit is contained in:
bum12ark
2022-02-28 16:54:16 +09:00
parent b6b3e39380
commit 5f46d73a22
9 changed files with 70 additions and 25 deletions

View File

@@ -6,6 +6,6 @@ import org.springframework.http.HttpStatus;
public class AccessTokenNotValidException extends CustomException { public class AccessTokenNotValidException extends CustomException {
public AccessTokenNotValidException(String message) { public AccessTokenNotValidException(String message) {
super(HttpStatus.FORBIDDEN, message); super(HttpStatus.UNAUTHORIZED, message);
} }
} }

View File

@@ -0,0 +1,6 @@
package com.justpickup.userservice.domain.jwt.service;
public interface AccessTokenService {
void checkAccessToken(String authorizationHeader);
}

View File

@@ -0,0 +1,23 @@
package com.justpickup.userservice.domain.jwt.service;
import com.justpickup.userservice.domain.jwt.exception.AccessTokenNotValidException;
import com.justpickup.userservice.global.utils.JwtTokenProvider;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
public class AccessTokenServiceImpl implements AccessTokenService {
private final JwtTokenProvider tokenProvider;
@Override
public void checkAccessToken(String authorizationHeader) {
String token = authorizationHeader.replace("Bearer", "");
if (!tokenProvider.validateJwtToken(token)) {
throw new AccessTokenNotValidException("Access Token is not Valid");
}
}
}

View File

@@ -19,6 +19,7 @@ import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -69,9 +70,11 @@ public class RefreshTokenServiceImpl implements RefreshTokenService {
.stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList()); .stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList());
String newAccessToken = jwtTokenProvider.createJwtAccessToken(userId, "/refreshToken", roles); String newAccessToken = jwtTokenProvider.createJwtAccessToken(userId, "/refreshToken", roles);
Date expiredTime = jwtTokenProvider.getExpiredTime(newAccessToken);
return JwtTokenDto.builder() return JwtTokenDto.builder()
.accessToken(newAccessToken) .accessToken(newAccessToken)
.accessTokenExpiredDate(expiredTime)
.refreshToken(refreshToken) .refreshToken(refreshToken)
.build(); .build();
} }

View File

@@ -1,6 +1,7 @@
package com.justpickup.userservice.domain.jwt.web; package com.justpickup.userservice.domain.jwt.web;
import com.justpickup.userservice.domain.jwt.service.RefreshTokenServiceImpl; import com.justpickup.userservice.domain.jwt.service.AccessTokenService;
import com.justpickup.userservice.domain.jwt.service.RefreshTokenService;
import com.justpickup.userservice.domain.user.dto.JwtTokenDto; import com.justpickup.userservice.domain.user.dto.JwtTokenDto;
import com.justpickup.userservice.global.dto.Result; import com.justpickup.userservice.global.dto.Result;
import com.justpickup.userservice.global.utils.CookieProvider; import com.justpickup.userservice.global.utils.CookieProvider;
@@ -15,20 +16,22 @@ import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.HttpHeaders;
import java.text.SimpleDateFormat;
@RestController @RestController
@RequiredArgsConstructor @RequiredArgsConstructor
@RequestMapping("/auth")
@Slf4j @Slf4j
public class AuthController { public class AuthController {
private final RefreshTokenServiceImpl refreshTokenServiceImpl; private final RefreshTokenService refreshTokenService;
private final AccessTokenService accessTokenService;
private final CookieProvider cookieProvider; private final CookieProvider cookieProvider;
@GetMapping("/refreshToken") @GetMapping("/reissue")
public ResponseEntity<Result> refreshToken(@RequestHeader("X-AUTH-TOKEN") String accessToken, public ResponseEntity<Result> refreshToken(@RequestHeader("X-AUTH-TOKEN") String accessToken,
@CookieValue("refresh-token") String refreshToken) { @CookieValue("refresh-token") String refreshToken) {
JwtTokenDto jwtTokenDto = refreshTokenService.refreshJwtToken(accessToken, refreshToken);
JwtTokenDto jwtTokenDto = refreshTokenServiceImpl.refreshJwtToken(accessToken, refreshToken);
ResponseCookie responseCookie = cookieProvider.createRefreshTokenCookie(refreshToken); ResponseCookie responseCookie = cookieProvider.createRefreshTokenCookie(refreshToken);
@@ -42,9 +45,12 @@ public class AuthController {
@AllArgsConstructor @AllArgsConstructor
static class RefreshTokenResponse { static class RefreshTokenResponse {
private String accessToken; private String accessToken;
private String expiredTime;
public RefreshTokenResponse(JwtTokenDto jwtTokenDto) { public RefreshTokenResponse(JwtTokenDto jwtTokenDto) {
this.accessToken = jwtTokenDto.getAccessToken(); this.accessToken = jwtTokenDto.getAccessToken();
this.expiredTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
.format(jwtTokenDto.getAccessTokenExpiredDate());
} }
} }
@@ -52,7 +58,7 @@ public class AuthController {
public ResponseEntity<Result> logout(@RequestHeader("X-AUTH-TOKEN") String accessToken, public ResponseEntity<Result> logout(@RequestHeader("X-AUTH-TOKEN") String accessToken,
@RequestHeader("REFRESH-TOKEN") String refreshToken) { @RequestHeader("REFRESH-TOKEN") String refreshToken) {
refreshTokenServiceImpl.logoutToken(accessToken); refreshTokenService.logoutToken(accessToken);
ResponseCookie refreshCookie = cookieProvider.removeRefreshTokenCookie(); ResponseCookie refreshCookie = cookieProvider.removeRefreshTokenCookie();
@@ -60,4 +66,13 @@ public class AuthController {
.header(HttpHeaders.SET_COOKIE, refreshCookie.toString()) .header(HttpHeaders.SET_COOKIE, refreshCookie.toString())
.body(Result.createErrorResult("")); .body(Result.createErrorResult(""));
} }
@GetMapping("/check/access-token")
public ResponseEntity<Result> checkAccessToken(@RequestHeader(name = "Authorization") String authorization) {
accessTokenService.checkAccessToken(authorization);
return ResponseEntity.status(HttpStatus.OK)
.body(Result.createSuccessResult(null));
}
} }

View File

@@ -3,14 +3,18 @@ package com.justpickup.userservice.domain.user.dto;
import lombok.Builder; import lombok.Builder;
import lombok.Getter; import lombok.Getter;
import java.util.Date;
@Getter @Getter
public class JwtTokenDto { public class JwtTokenDto {
private String accessToken; private String accessToken;
private Date accessTokenExpiredDate;
private String refreshToken; private String refreshToken;
@Builder @Builder
public JwtTokenDto(String accessToken, String refreshToken) { public JwtTokenDto(String accessToken, String refreshToken, Date accessTokenExpiredDate) {
this.accessToken = accessToken; this.accessToken = accessToken;
this.refreshToken = refreshToken; this.refreshToken = refreshToken;
this.accessTokenExpiredDate = accessTokenExpiredDate;
} }
} }

View File

@@ -36,7 +36,7 @@ public class GlobalExceptionHandler {
// 쿠키 삭제 // 쿠키 삭제
ResponseCookie responseCookie = cookieProvider.removeRefreshTokenCookie(); ResponseCookie responseCookie = cookieProvider.removeRefreshTokenCookie();
return ResponseEntity.status(HttpStatus.FORBIDDEN) return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
.header(HttpHeaders.SET_COOKIE, responseCookie.toString()) .header(HttpHeaders.SET_COOKIE, responseCookie.toString())
.body(e.getResult()); .body(e.getResult());
} }

View File

@@ -18,11 +18,12 @@ import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import javax.servlet.FilterChain; import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie; import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import java.io.IOException; import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -70,6 +71,7 @@ public class LoginAuthenticationFilter extends UsernamePasswordAuthenticationFil
String userId = user.getUsername(); String userId = user.getUsername();
String accessToken = jwtTokenProvider.createJwtAccessToken(userId, request.getRequestURI(), roles); String accessToken = jwtTokenProvider.createJwtAccessToken(userId, request.getRequestURI(), roles);
Date expiredTime = jwtTokenProvider.getExpiredTime(accessToken);
String refreshToken = jwtTokenProvider.createJwtRefreshToken(); String refreshToken = jwtTokenProvider.createJwtRefreshToken();
refreshTokenServiceImpl.updateRefreshToken(Long.valueOf(userId), jwtTokenProvider.getRefreshTokenId(refreshToken)); refreshTokenServiceImpl.updateRefreshToken(Long.valueOf(userId), jwtTokenProvider.getRefreshTokenId(refreshToken));
@@ -83,17 +85,11 @@ public class LoginAuthenticationFilter extends UsernamePasswordAuthenticationFil
response.addCookie(cookie); response.addCookie(cookie);
// body 설정 // body 설정
Map<String, String> tokens = Map.of( Map<String, Object> tokens = Map.of(
"access_token", accessToken "accessToken", accessToken,
"expiredTime", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(expiredTime)
); );
new ObjectMapper().writeValue(response.getOutputStream(), Result.createSuccessResult(tokens)); new ObjectMapper().writeValue(response.getOutputStream(), Result.createSuccessResult(tokens));
} }
@Override
protected void unsuccessfulAuthentication
(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed)
throws IOException, ServletException {
log.warn("로그인 실패!!");
}
} }

View File

@@ -5,10 +5,6 @@ import io.jsonwebtoken.*;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.Date; import java.util.Date;
@@ -57,8 +53,6 @@ public class JwtTokenProvider {
.compact(); .compact();
} }
public String getUserId(String token) { public String getUserId(String token) {
return getClaimsFromJwtToken(token).getSubject(); return getClaimsFromJwtToken(token).getSubject();
} }
@@ -75,6 +69,10 @@ public class JwtTokenProvider {
return getClaimsFromJwtToken(token).get("value").toString(); return getClaimsFromJwtToken(token).get("value").toString();
} }
public Date getExpiredTime(String token) {
return getClaimsFromJwtToken(token).getExpiration();
}
public List<String> getRoles(String token) { public List<String> getRoles(String token) {
return (List<String>) getClaimsFromJwtToken(token).get("roles"); return (List<String>) getClaimsFromJwtToken(token).get("roles");
} }