Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEAT] JWT 검증,발급 로직 수정 #26

Merged
merged 3 commits into from
Jan 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ private void addTokenToCookie(String cookieName, String token, HttpServletRespon
Cookie cookie = new Cookie(cookieName, token);
//cookie.setSecure(true); //TODO: HTTPS 설정 후에 주석 해제
cookie.setHttpOnly(true);
cookie.setMaxAge(1);

response.addCookie(cookie);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import com.nice.petudio.common.config.redis.constant.RedisKey;
import com.nice.petudio.common.exception.error.ErrorCode;
import com.nice.petudio.common.exception.model.UnAuthorizedException;
import com.nice.petudio.common.exception.model.ValidationException;
import com.nice.petudio.domain.member.Member;
import com.nice.petudio.domain.member.repository.MemberRepository;
import java.util.List;
Expand Down Expand Up @@ -35,7 +36,8 @@ public TokenVO createTokenInfo(Long memberId) {

public TokenVO reissueToken(ReissueRequest request) {
Long memberId = jwtUtils.parseMemberId(request.getAccessToken())
.orElseThrow();
.orElseThrow(() -> new ValidationException(ErrorCode.INVALID_JWT_TOKEN_EXCEPTION,
String.format("JWT AccessToken 내에 MemberId가 존재하지 않습니다.")));
Member member = MemberServiceUtils.findMemberById(memberRepository, memberId);

if (!jwtUtils.validateToken(request.getRefreshToken())) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@
@RestControllerAdvice
public class ExceptionControllerAdvice {

/**
* 400 Bad Request
*/
// 사용자가 요청 값 전달은 성공했지만, 해당 값이 유효하지 않은 경우 발생
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(ValidationException.class)
Expand Down Expand Up @@ -76,7 +79,7 @@ protected ApiResponse<Object> handleInvalidFormatException(final Exception excep
* 401 UnAuthorized
*/
// 회원 인증에 실패했을 경우 발생
@ResponseStatus(HttpStatus.NOT_FOUND)
@ResponseStatus(HttpStatus.UNAUTHORIZED)
@ExceptionHandler(UnAuthorizedException.class)
protected ApiResponse<Object> handleUnAuthorizedException(
UnAuthorizedException exception) {
Expand All @@ -88,7 +91,7 @@ protected ApiResponse<Object> handleUnAuthorizedException(
* 403 Forbidden
*/
// 요청에 대한 권한이 존재하지 않는 경우 발생
@ResponseStatus(HttpStatus.NOT_FOUND)
@ResponseStatus(HttpStatus.FORBIDDEN)
@ExceptionHandler(ForbiddenException.class)
protected ApiResponse<Object> handleForbiddenException(
ForbiddenException exception) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ public boolean hasAuthority(String jwtAccessToken, List<MemberRole> requiredRole
this.memberId = memberId.get();
return isRoleMatch(member, requiredRoles);
}
throw new ValidationException(ErrorCode.INVALID_JWT_TOKEN_EXCEPTION,
String.format("JWT AccessToken 내에 MemberId가 존재하지 않습니다."));
}
throw new UnAuthorizedException(ErrorCode.UNAUTHORIZED_JWT_EXCEPTION,
ErrorCode.UNAUTHORIZED_JWT_EXCEPTION.getMessage());
Expand Down
22 changes: 17 additions & 5 deletions src/main/java/com/nice/petudio/common/auth/jwt/JwtUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import com.nice.petudio.common.auth.jwt.constant.JwtKey;
import com.nice.petudio.common.config.redis.constant.RedisKey;
import com.nice.petudio.common.exception.error.ErrorCode;
import com.nice.petudio.common.exception.model.UnAuthorizedException;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
Expand All @@ -11,6 +13,7 @@
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.io.DecodingException;
import io.jsonwebtoken.security.Keys;
import io.jsonwebtoken.security.SignatureException;
import java.util.Date;
import java.util.List;
import java.util.Optional;
Expand Down Expand Up @@ -56,7 +59,8 @@ public List<String> createTokenInfo(Long memberId) {
.compact();

redisTemplate.opsForValue()
.set(RedisKey.REFRESH_TOKEN.getKey() + memberId, refreshToken, REFRESH_TOKEN_EXPIRE_TIME, TimeUnit.MILLISECONDS);
.set(RedisKey.REFRESH_TOKEN.getKey() + memberId, refreshToken, REFRESH_TOKEN_EXPIRE_TIME,
TimeUnit.MILLISECONDS);

return List.of(accessToken, refreshToken);
}
Expand All @@ -70,12 +74,20 @@ public Optional<Long> parseMemberId(String accessToken) {
return Optional.ofNullable(parseClaims(accessToken).get(JwtKey.MEMBER_ID.getKey(), Long.class));
}

private Claims parseClaims(String token) {
private Claims parseClaims(String accessToken) {
try {
validateAccessToken(accessToken);
return Jwts.parserBuilder().setSigningKey(secretKey).build()
.parseClaimsJws(token).getBody();
} catch (ExpiredJwtException e) {
return e.getClaims();
.parseClaimsJws(accessToken).getBody();
} catch (ExpiredJwtException exception) {
return exception.getClaims();
}
}

private void validateAccessToken(String accessToken) {
if (!validateToken(accessToken)) {
throw new UnAuthorizedException(ErrorCode.UNAUTHORIZED_JWT_EXCEPTION,
String.format("입력받은 JWT 토큰이 유효하지 않습니다. (ACCESS_TOKEN: %s)", accessToken));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ public enum ErrorCode {
BAD_REQUEST_EXCEPTION("V002", "잘못된 요청입니다."),
METHOD_NOT_ALLOWED_EXCEPTION("V003", "지원하지 않는 HTTP 메소드입니다."),
UNSUPPORTED_MEDIA_TYPE("V004", "허용하지 않는 미디어 타입입니다."),
INVALID_JWT_TOKEN_EXCEPTION("V005", "존재하지 않거나 잘못된 JWT 토큰 형식입니다."),
INVALID_JWT_TOKEN_EXCEPTION("V005", "존재하지 않거나 잘못된 JWT 토큰 형식입니다."), // JWT 토큰 값에 이상이 있을 경우
INVALID_OAUTH2_ACCESS_TOKEN_EXCEPTION("V006", "존재하지 않거나 잘못된 OAuth2 Access 토큰 입니다."),
NO_RESOURCE_FOUND_EXCEPTION("V007", "존재하지 않는 API 주소입니다."),

// UnAuthorized Exception
UNAUTHORIZED_JWT_EXCEPTION("U001", "JWT 토큰이 유효하지 않습니다. 다시 로그인 해주세요."),
UNAUTHORIZED_JWT_EXCEPTION("U001", "JWT 토큰이 유효하지 않습니다. 다시 로그인 해주세요."), // 인증에 실패했을 경우

// Forbidden Exception
FORBIDDEN_EXCEPTION("F001", "접근 권한이 존재하지 않습니다."),
Expand Down