Skip to content

Commit

Permalink
Merge pull request #85 from Team-Growthook/fix/#84-auth-token-reissue
Browse files Browse the repository at this point in the history
[FIX] 토큰 재발급 API 에러 수정
  • Loading branch information
yeseul106 authored Jan 22, 2024
2 parents 574c036 + f3f8588 commit 63fca73
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,7 @@ public AuthResponseDto socialLogin(AuthRequestDto authRequestDto) throws NoSuchA
// socialId를 통해서 등록된 유저 찾기
Member signedMember = memberRepository.findMemberBySocialIdOrThrow(socialData.getId());

Authentication authentication = new UserAuthentication(signedMember.getId(), null, null);

String accessToken = jwtTokenProvider.generateAccessToken(authentication);
String accessToken = jwtTokenProvider.generateAccessToken(signedMember.getId());

return AuthResponseDto.of(signedMember.getNickname(), signedMember.getId(), accessToken, signedMember.getRefreshToken());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.example.growthookserver.api.member.domain.Member;
import com.example.growthookserver.common.exception.BadRequestException;
import com.example.growthookserver.common.exception.NotFoundException;
import com.example.growthookserver.common.exception.UnAuthorizedException;
import com.example.growthookserver.common.response.ErrorStatus;
import org.springframework.data.jpa.repository.JpaRepository;

Expand All @@ -12,7 +13,7 @@ public interface MemberRepository extends JpaRepository<Member, Long> {
Optional<Member> findMemberById(Long id);

boolean existsBySocialId(String socialId);
Optional<Member> findByIdAndRefreshToken(Long memberId, String refreshToken);
Optional<Member> findByRefreshToken(String refreshToken);

Optional<Member> findBySocialId(String socialId);

Expand All @@ -25,4 +26,9 @@ default Member findMemberBySocialIdOrThrow(String socialId) {
return findBySocialId(socialId)
.orElseThrow(() -> new BadRequestException(ErrorStatus.INVALID_MEMBER.getMessage()));
}

default Member findByRefreshTokenOrThrow(String refreshToken) {
return findByRefreshToken(refreshToken)
.orElseThrow(() -> new UnAuthorizedException(ErrorStatus.INVALID_MEMBER.getMessage()));
}
}
Original file line number Diff line number Diff line change
@@ -1,25 +1,34 @@
package com.example.growthookserver.common.config.jwt;

import com.example.growthookserver.common.response.ApiResponse;
import com.example.growthookserver.common.response.ErrorStatus;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;

@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {

private final ObjectMapper mapper = new ObjectMapper();

@Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException {
setResponse(response);
setResponse(response, HttpStatus.UNAUTHORIZED, ErrorStatus.UNAUTHORIZED_TOKEN);
}


public void setResponse(HttpServletResponse response) throws IOException {
public void setResponse(HttpServletResponse response, HttpStatus statusCode, ErrorStatus status) throws IOException {
response.setContentType("application/json;charset=UTF-8");
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);

ApiResponse apiResponse = ApiResponse.fail(statusCode.value(), status.getMessage());
response.getWriter().println(mapper.writeValueAsString(apiResponse));
}

}
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
package com.example.growthookserver.common.config.jwt;


import static com.example.growthookserver.common.config.jwt.JwtExceptionType.VALID_JWT_TOKEN;

import com.example.growthookserver.common.exception.UnAuthorizedException;
import com.example.growthookserver.common.response.ErrorStatus;
import io.jsonwebtoken.Claims;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import lombok.RequiredArgsConstructor;

import org.springframework.security.core.AuthenticationException;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

Expand All @@ -24,28 +23,60 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
private final JwtTokenProvider jwtTokenProvider;
private final JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;

private static final String ISSUE_TOKEN_API_URL = "/api/v1/auth/token";

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain chain) throws ServletException, IOException {
String accessToken = jwtTokenProvider.resolveToken(request);

if (accessToken != null) {
// 토큰 검증
if (jwtTokenProvider.validateToken(accessToken)
== VALID_JWT_TOKEN) { // 토큰이 존재하고 유효한 토큰일 때만
Integer userId = jwtTokenProvider.getAccessTokenPayload(accessToken);
UserAuthentication authentication = new UserAuthentication(userId, null,
null); //사용자 객체 생성
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(
request)); // request 정보로 사용자 객체 디테일 설정
SecurityContextHolder.getContext().setAuthentication(authentication);
} else {
jwtAuthenticationEntryPoint.commence(request, response,
new AuthenticationException(ErrorStatus.UNAUTHORIZED_TOKEN.getMessage()) {
});
return;
try {
String accessToken = jwtTokenProvider.resolveToken(request);
if (ISSUE_TOKEN_API_URL.equals(request.getRequestURI())) {
String refreshToken = jwtTokenProvider.resolveRefreshToken(request);

if (jwtTokenProvider.validateToken(refreshToken) == JwtExceptionType.EMPTY_JWT || jwtTokenProvider.validateToken(accessToken) == JwtExceptionType.EMPTY_JWT) {
jwtAuthenticationEntryPoint.setResponse(response, HttpStatus.BAD_REQUEST, ErrorStatus.NO_TOKEN);
return;
} else if (jwtTokenProvider.validateToken(accessToken) == JwtExceptionType.EXPIRED_JWT_TOKEN) {
if (jwtTokenProvider.validateToken(refreshToken) == JwtExceptionType.EXPIRED_JWT_TOKEN) {
// access, refresh 둘 다 만료
jwtAuthenticationEntryPoint.setResponse(response, HttpStatus.UNAUTHORIZED, ErrorStatus.SIGNIN_REQUIRED);
return;
} else if (jwtTokenProvider.validateToken(refreshToken) == JwtExceptionType.VALID_JWT_TOKEN) {
// 토큰 재발급
Long memberId = jwtTokenProvider.validateMemberRefreshToken(refreshToken);

String newAccessToken = jwtTokenProvider.generateAccessToken(memberId);

setAuthentication(newAccessToken);
request.setAttribute("newAccessToken", newAccessToken);
}
} else if (jwtTokenProvider.validateToken(accessToken) == JwtExceptionType.VALID_JWT_TOKEN) {
jwtAuthenticationEntryPoint.setResponse(response, HttpStatus.UNAUTHORIZED, ErrorStatus.VALID_ACCESS_TOKEN);
return;
} else {
throw new UnAuthorizedException(ErrorStatus.UNAUTHORIZED_TOKEN.getMessage());
}
}
else {
JwtExceptionType jwtException = jwtTokenProvider.validateToken(accessToken);

if (accessToken != null) {
// 토큰 검증
if (jwtException == JwtExceptionType.VALID_JWT_TOKEN) {
setAuthentication(accessToken);
}
}
}
} catch (Exception e) {
throw new UnAuthorizedException(ErrorStatus.UNAUTHORIZED_TOKEN.getMessage());
}

chain.doFilter(request, response);
}

private void setAuthentication(String token) {
Claims claims = jwtTokenProvider.getAccessTokenPayload(token);
Authentication authentication = new UserAuthentication(Long.valueOf(String.valueOf(claims.get("id"))), null, null);
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.example.growthookserver.common.config.jwt;

import com.example.growthookserver.api.member.domain.Member;
import com.example.growthookserver.api.member.repository.MemberRepository;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Header;
Expand All @@ -23,6 +25,8 @@
@RequiredArgsConstructor
public class JwtTokenProvider {

private final MemberRepository memberRepository;

@Value("${jwt.secret}")
private String secretKey;

Expand All @@ -33,17 +37,17 @@ public class JwtTokenProvider {
private Long refreshTokenExpireLength;

private static final String AUTHORIZATION_HEADER = "Authorization";
private static final String REFRESH_AUTHORIZATION_HEADER = "Refresh";
private static final String REFRESH_AUTHORIZATION_HEADER = "refreshToken";

public String generateAccessToken(Authentication authentication) {
public String generateAccessToken(Long memberId) {
Date now = new Date();
Date expiration = new Date(now.getTime() + accessTokenExpireLength);

final Claims claims = Jwts.claims()
.setIssuedAt(now)
.setExpiration(expiration);

claims.put("id", authentication.getPrincipal());
claims.put("id", memberId);

return Jwts.builder()
.setHeaderParam(Header.TYPE, Header.JWT_TYPE)
Expand All @@ -63,10 +67,9 @@ public String generateRefreshToken() {
.compact();
}

public Integer getAccessTokenPayload(String token) {
return Integer.parseInt(
Jwts.parserBuilder().setSigningKey(getSignKey()).build().parseClaimsJws(token)
.getBody().get("id").toString());
public Claims getAccessTokenPayload(String token) {
return Jwts.parserBuilder().setSigningKey(getSignKey()).build().parseClaimsJws(token)
.getBody();
}

public String resolveToken(HttpServletRequest request) {
Expand Down Expand Up @@ -117,4 +120,9 @@ private Key getSignKey() {
byte[] keyBytes = secretKey.getBytes(StandardCharsets.UTF_8);
return new SecretKeySpec(keyBytes, "HmacSHA256");
}

public Long validateMemberRefreshToken(String refreshToken) {
Member member = memberRepository.findByRefreshTokenOrThrow(refreshToken);
return member.getId();
}
}

0 comments on commit 63fca73

Please sign in to comment.