Skip to content

Commit

Permalink
[merge] 호스트 승인 시 토큰 만료되도록 구현
Browse files Browse the repository at this point in the history
[feat] 호스트 승인 시 토큰 만료되도록 구현
  • Loading branch information
bo-ram-bo-ram authored Sep 24, 2024
2 parents bc2be49 + 64544d5 commit a68f30b
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
import com.pickple.server.api.submitter.dto.request.SubmitterCreateRequest;
import com.pickple.server.api.submitter.repository.SubmitterRepository;
import com.pickple.server.api.user.domain.Role;
import com.pickple.server.global.auth.jwt.repository.TokenRepository;
import com.pickple.server.global.auth.redis.domain.Token;
import com.pickple.server.global.exception.CustomException;
import com.pickple.server.global.response.enums.ErrorCode;
import jakarta.transaction.Transactional;
Expand All @@ -24,6 +26,7 @@ public class SubmitterCommandService {
private final GuestRepository guestRepository;
private final SubmitterRepository submitterRepository;
private final HostRepository hostRepository;
private final TokenRepository tokenRepository;

public void createSubmitter(Long guestId, SubmitterCreateRequest request) {
Guest guest = guestRepository.findGuestByIdOrThrow(guestId);
Expand Down Expand Up @@ -64,6 +67,13 @@ public void approveSubmitter(Long submitterId) {
.build();

hostRepository.save(host);

//재로그인으로 연결을 위한 리프레시 토큰 만료
Token token = tokenRepository.findById(submitter.getGuest().getId())
.orElseThrow(
() -> new CustomException(ErrorCode.REFRESH_TOKEN_NOT_FOUND)
);
tokenRepository.delete(token);
}

private void isDuplicatedSubmission(Guest guest) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.pickple.server.api.user.service;

import static com.pickple.server.global.auth.jwt.provider.JwtValidationType.EXPIRED_JWT_TOKEN;

import com.pickple.server.api.guest.domain.Guest;
import com.pickple.server.api.guest.repository.GuestRepository;
import com.pickple.server.api.host.domain.Host;
Expand Down Expand Up @@ -98,6 +100,11 @@ public User getBySocialId(
public AccessTokenGetSuccess refreshToken(
final String refreshToken
) {
if (jwtTokenProvider.validateToken(refreshToken) == EXPIRED_JWT_TOKEN) {
// 리프레시 토큰이 만료된 경우
throw new CustomException(ErrorCode.REFRESH_TOKEN_EXPIRED);
}

Long userId = jwtTokenProvider.getUserFromJwt(refreshToken);
if (!userId.equals(tokenService.findIdByRefreshToken(refreshToken))) {
throw new CustomException(ErrorCode.TOKEN_INCORRECT_ERROR);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
package com.pickple.server.global.auth.jwt.filter;

import static com.pickple.server.global.auth.jwt.provider.JwtValidationType.EXPIRED_JWT_TOKEN;
import static com.pickple.server.global.auth.jwt.provider.JwtValidationType.VALID_JWT;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.pickple.server.global.auth.jwt.provider.JwtTokenProvider;
import com.pickple.server.global.auth.security.UserAuthentication;
import com.pickple.server.global.exception.CustomException;
import com.pickple.server.global.response.ApiResponseDto;
import com.pickple.server.global.response.enums.ErrorCode;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
Expand Down Expand Up @@ -32,6 +37,7 @@ protected void doFilterInternal(@NonNull HttpServletRequest request,
@NonNull FilterChain filterChain) throws ServletException, IOException {
try {
final String token = getJwtFromRequest(request);

if (token != null && jwtTokenProvider.validateToken(token) == VALID_JWT) {
Long memberId = jwtTokenProvider.getUserFromJwt(token);

Expand All @@ -44,23 +50,41 @@ protected void doFilterInternal(@NonNull HttpServletRequest request,
UserAuthentication authentication = new UserAuthentication(memberId.toString(), null, authorities);
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
} else if (jwtTokenProvider.validateToken(token) == EXPIRED_JWT_TOKEN) {
// 토큰이 만료된 경우 CustomException 던짐
throw new CustomException(ErrorCode.ACCESS_TOKEN_EXPIRED);
}
} catch (Exception exception) {
try {
throw new Exception();
} catch (Exception e) {
throw new RuntimeException(e);
}

// 다음 필터로 요청 전달
filterChain.doFilter(request, response);

} catch (CustomException e) {
// CustomException을 잡아서 클라이언트에게 응답
handleException(response, e.getErrorCode());
}
// 다음 필터로 요청 전달
filterChain.doFilter(request, response);
}

// 예외 처리 및 응답
private void handleException(HttpServletResponse response, ErrorCode errorCode) throws IOException {
response.setStatus(errorCode.getHttpStatus().value());
response.setContentType("application/json; charset=UTF-8");

// ObjectMapper는 예외 처리시에만 생성하여 메모리 최적화
ObjectMapper objectMapper = new ObjectMapper();

// 실패 응답 생성
ApiResponseDto<?> apiResponse = ApiResponseDto.fail(errorCode);

// 응답을 JSON 형식으로 변환 후 출력
response.getWriter().write(objectMapper.writeValueAsString(apiResponse));
}

// JWT를 요청 헤더에서 추출
private String getJwtFromRequest(HttpServletRequest request) {
String bearerToken = request.getHeader("Authorization");
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
return bearerToken.substring("Bearer ".length());
}
return null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,11 @@ public enum ErrorCode {
NO_SUBMISSION_FOUND_FOR_REVIEW(40011, HttpStatus.BAD_REQUEST, "리뷰를 작성할 수 있는 신청이 없습니다"),
NOT_AUTHOR(40012, HttpStatus.BAD_REQUEST, "해당 댓글의 작성자가 아닙니다."),
DUPLICATION_APPROVE_SUBMITTER(40013, HttpStatus.BAD_REQUEST, "이미 호스트입니다."),

// 401 Unauthorized
ACCESS_TOKEN_EXPIRED(40100, HttpStatus.UNAUTHORIZED, "액세스 토큰이 만료되었습니다."), //code 건들지 말것, 클라 분기처리함
TOKEN_INCORRECT_ERROR(40101, HttpStatus.UNAUTHORIZED, "리프레시 토큰이 유효하지 않습니다."), //code 건들지 말것, 클라 분기처리함
REFRESH_TOKEN_EXPIRED(40101, HttpStatus.UNAUTHORIZED, "리프레시 토큰이 만료되었습니다."), //code 건들지 말것, 클라 분기처리함
TOKEN_INCORRECT_ERROR(40102, HttpStatus.UNAUTHORIZED, "리프레시 토큰이 유효하지 않습니다."),
EMPTY_PRINCIPAL(40103, HttpStatus.UNAUTHORIZED, "유효하지 않은 토큰입니다."),

//403 Forbidden
Expand Down

0 comments on commit a68f30b

Please sign in to comment.