Skip to content
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 @@ -4,7 +4,6 @@
import com.api.tokbaro.domain.apns.web.dto.ApnsRes;
import com.api.tokbaro.domain.apns.web.dto.StateReq;
import com.eatthepath.pushy.apns.*;
import com.eatthepath.pushy.apns.util.SimpleApnsPushNotification;
import com.eatthepath.pushy.apns.util.TokenUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ public interface AuthService {
SignInUserRes signIn(SignInUserReq signInUserReq);
AppleLoginRes appleLogin(AppleIdReq appleIdReq);
SignInUserRes reissue(ReissueReq reissueReq);
void logout(Long userId, String token);
void logout(Long userId, String authorizationHeader);
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package com.api.tokbaro.domain.auth.service;

import com.api.tokbaro.domain.auth.web.dto.*;
import com.api.tokbaro.domain.user.entity.Role;
import com.api.tokbaro.domain.user.entity.User;
import com.api.tokbaro.domain.user.repository.UserRepository;
import com.api.tokbaro.domain.user.service.UserService;
import com.api.tokbaro.global.constant.StaticValue;
import com.api.tokbaro.global.exception.CustomException;
import com.api.tokbaro.global.jwt.AppleJwtVerifier;
import com.api.tokbaro.global.jwt.JwtTokenProvider;
Expand Down Expand Up @@ -37,7 +37,6 @@ public class AuthServiceImpl implements AuthService {
private final AppleJwtVerifier appleJwtVerifier;
private final UserService userService;
private final RedisService redisService;
private static final String REFRESH_TOKEN_KEY_PREFIX = "RT:";

//์ผ๋ฐ˜ ๋กœ๊ทธ์ธ
@Override
Expand All @@ -53,7 +52,7 @@ public SignInUserRes signIn(SignInUserReq signInUserReq) {
User user = userRepository.findById(userPrincipal.getId())
.orElseThrow(()->new CustomException(UserErrorResponseCode.USER_NOT_FOUND_404));

redisService.setValue(REFRESH_TOKEN_KEY_PREFIX + user.getId(), tokens.refreshToken(), Duration.ofMillis(jwtTokenProvider.getRefreshTokenValidity()));
redisService.setValue(StaticValue.REFRESH_TOKEN_KEY_PREFIX + user.getId(), tokens.refreshToken(), Duration.ofMillis(jwtTokenProvider.getRefreshTokenValidity()));
return tokens;
}

Expand Down Expand Up @@ -106,7 +105,7 @@ public AppleLoginRes appleLogin(AppleIdReq appleIdReq) {

//accessToken, refreshํ† ํฐ ์ƒ์„ฑ
SignInUserRes tokens = jwtTokenProvider.createTokens(authentication);
redisService.setValue(REFRESH_TOKEN_KEY_PREFIX + user.getId(), tokens.refreshToken(),
redisService.setValue(StaticValue.REFRESH_TOKEN_KEY_PREFIX + user.getId(), tokens.refreshToken(),
Duration.ofMillis(jwtTokenProvider.getRefreshTokenValidity()));
return AppleLoginRes.builder()
.grantType(tokens.grantType())
Expand All @@ -127,7 +126,7 @@ public SignInUserRes reissue(ReissueReq reissueReq) {

//2. RefreshToken์œผ๋กœ ์‚ฌ์šฉ์ž ID ์ถ”์ถœ ๋ฐ Redis์—์„œ ๊ฒ€์ฆ
Long userId = jwtTokenProvider.getUserIdFromToken(reissueReq.getRefreshToken());
String storedRefreshToken = redisService.getValue(REFRESH_TOKEN_KEY_PREFIX + userId);
String storedRefreshToken = redisService.getValue(StaticValue.REFRESH_TOKEN_KEY_PREFIX + userId);

if(storedRefreshToken == null || !storedRefreshToken.equals(reissueReq.getRefreshToken())){
throw new CustomException(UserErrorResponseCode.INVALID_REFRESH_TOKEN_401);
Expand All @@ -144,7 +143,7 @@ public SignInUserRes reissue(ReissueReq reissueReq) {
Collections.singleton(new SimpleGrantedAuthority("ROLE_" + user.getRole().name()))
);

redisService.deleteValue(REFRESH_TOKEN_KEY_PREFIX + userId);
redisService.deleteValue(StaticValue.REFRESH_TOKEN_KEY_PREFIX + userId);

Authentication authentication = new UsernamePasswordAuthenticationToken(
userPrincipal,
Expand All @@ -153,21 +152,23 @@ public SignInUserRes reissue(ReissueReq reissueReq) {

//์ƒˆ๋กœ์šด ํ† ํฐ ์ƒ์„ฑ
SignInUserRes newTokens = jwtTokenProvider.createTokens(authentication);
redisService.setValue(REFRESH_TOKEN_KEY_PREFIX + user.getId(), newTokens.refreshToken(), Duration.ofMillis(jwtTokenProvider.getRefreshTokenValidity()));
redisService.setValue(StaticValue.REFRESH_TOKEN_KEY_PREFIX + user.getId(), newTokens.refreshToken(), Duration.ofMillis(jwtTokenProvider.getRefreshTokenValidity()));

return newTokens;
}

//๋กœ๊ทธ์•„์›ƒ
@Override
@Transactional
public void logout(Long userId, String accessToken) {
public void logout(Long userId, String authorizationHeader) {
User user = userRepository.findById(userId)
.orElseThrow(()->new CustomException(UserErrorResponseCode.USER_NOT_FOUND_404));

log.info("๋กœ๊ทธ์•„์›ƒ ์š”์ฒญ ์‚ฌ์šฉ์ž: {}", user.getUsername());

redisService.deleteValue(REFRESH_TOKEN_KEY_PREFIX + userId);
String accessToken = authorizationHeader.substring(StaticValue.BEARER_PREFIX.length());

redisService.deleteValue(StaticValue.REFRESH_TOKEN_KEY_PREFIX + userId);
log.info("Redis์—์„œ ์‚ฌ์šฉ์ž {}์˜ Refresh Token์„ ์ œ๊ฑฐ ํ•˜์˜€์Šต๋‹ˆ๋‹ค.", user.getUsername());

Long expiration = jwtTokenProvider.getExpiration(accessToken);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ public ResponseEntity<SuccessResponse<?>> signIn(@RequestBody SignInUserReq sign
@PostMapping("/logout")
public ResponseEntity<SuccessResponse<?>> logout(@AuthenticationPrincipal UserPrincipal userPrincipal,
@RequestHeader("Authorization")String authorizationHeader) {
String accessToken = authorizationHeader.substring(JwtExtractor.BEARER_PREFIX.length());
authService.logout(userPrincipal.getId(),accessToken);

authService.logout(userPrincipal.getId(),authorizationHeader);
return ResponseEntity
.status(HttpStatus.OK)
.body(SuccessResponse.emptyCustom("๋กœ๊ทธ์•„์›ƒ์— ์„ฑ๊ณตํ•˜์˜€์Šต๋‹ˆ๋‹ค."));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import com.api.tokbaro.domain.apns.web.dto.StateReq;
import com.api.tokbaro.domain.content.web.dto.ReactionReq;
import com.api.tokbaro.domain.content.web.dto.ReactionVelocityRes;
import com.api.tokbaro.global.jwt.UserPrincipal;

import java.util.List;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@ public interface UserService {

MyInfoRes getMyInfo(Long userId);

void deleteUser(Long userId, String accessToken);
void deleteUser(Long userId, String authorizationHeader);
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
package com.api.tokbaro.domain.user.service;

import com.api.tokbaro.domain.apns.service.ApnsService;
import com.api.tokbaro.domain.apns.web.dto.ApnsRes;
import com.api.tokbaro.domain.apns.web.dto.StateReq;
import com.api.tokbaro.domain.content.entity.ContentData;
import com.api.tokbaro.domain.content.repository.ContentDataRepository;
import com.api.tokbaro.domain.user.entity.Role;
import com.api.tokbaro.domain.user.entity.User;
import com.api.tokbaro.domain.user.repository.UserRepository;
import com.api.tokbaro.domain.user.web.dto.*;
import com.api.tokbaro.global.constant.StaticValue;
import com.api.tokbaro.global.exception.CustomException;
import com.api.tokbaro.global.jwt.JwtTokenProvider;
import com.api.tokbaro.global.redis.RedisService;
Expand All @@ -27,8 +23,6 @@ public class UserServiceImpl implements UserService {

private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
private final ContentDataRepository contentDataRepository;
private final ApnsService apnsService;
private final JwtTokenProvider jwtTokenProvider;
private final RedisService redisService;

Expand Down Expand Up @@ -82,14 +76,17 @@ public MyInfoRes getMyInfo(Long userId) {

@Override
@Transactional
public void deleteUser(Long userId, String accessToken) {
public void deleteUser(Long userId, String authorizationHeader) {
User user = userRepository.findById(userId)
.orElseThrow(() -> new CustomException(UserErrorResponseCode.USER_NOT_FOUND_404));

log.info("ํšŒ์› ํƒˆํ‡ด ์š”์ฒญ ์‚ฌ์šฉ์ž : {}", user.getUsername());

String accessToken = authorizationHeader.substring(StaticValue.BEARER_PREFIX.length());

Long expiration = jwtTokenProvider.getExpiration(accessToken);
redisService.addTokenToBlacklist(accessToken, expiration);
redisService.deleteValue("RT:" + user.getId());
redisService.deleteValue(StaticValue.REFRESH_TOKEN_KEY_PREFIX + user.getId());
log.info("์•ก์„ธ์Šค ํ† ํฐ์ด ๋ธ”๋ž™๋ฆฌ์ŠคํŠธ์— ์ถ”๊ฐ€ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. (๋งŒ๋ฃŒ์‹œ๊ฐ„ : {}์ดˆ)", expiration);

userRepository.delete(user);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,13 @@
import com.api.tokbaro.domain.user.service.UserService;
import com.api.tokbaro.domain.user.web.dto.*;
import com.api.tokbaro.global.jwt.JwtExtractor;
import com.api.tokbaro.global.jwt.JwtTokenProvider;
import com.api.tokbaro.global.jwt.UserPrincipal;
import com.api.tokbaro.global.response.SuccessResponse;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.core.parameters.P;
import org.springframework.web.bind.annotation.*;

@RestController
Expand All @@ -25,7 +19,6 @@
public class UserController {

private final UserService userService;
private final JwtExtractor jwtExtractor;

//ํšŒ์›๊ฐ€์ž…
@PostMapping("/users")
Expand All @@ -49,8 +42,7 @@ public ResponseEntity<SuccessResponse<?>> getMyInfo(@AuthenticationPrincipal Use
@DeleteMapping("/users")
public ResponseEntity<SuccessResponse<?>> deleteUser(@AuthenticationPrincipal UserPrincipal userPrincipal,
@RequestHeader("Authorization")String authorizationHeader){
String accessToken = authorizationHeader.substring(JwtExtractor.BEARER_PREFIX.length());
userService.deleteUser(userPrincipal.getId(), accessToken);
userService.deleteUser(userPrincipal.getId(), authorizationHeader);
return ResponseEntity
.status(HttpStatus.OK)
.body(SuccessResponse.okCustom(null,"ํšŒ์›ํƒˆํ‡ด์— ์„ฑ๊ณตํ•˜์˜€์Šต๋‹ˆ๋‹ค"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,10 @@ public class StaticValue { // ๊ณตํ†ต ์‘๋‹ต enum ์ •์˜ ํด๋ž˜์Šค
public static final int METHOD_NOT_ALLOWED = 405; // ํ—ˆ์šฉ๋˜์ง€ ์•Š๋Š” ๋ฉ”์„œ๋“œ
public static final int CONFLICT = 409; // ์ถฉ๋Œ ๋ฐœ์ƒ
public static final int INTERNAL_SERVER_ERROR = 500; // ์„œ๋ฒ„ ๋‚ด๋ถ€ ์˜ค๋ฅ˜

//JWT and Security Constants
public static final String AUTHORIZATION_HEADER = "Authorization";
public static final String BEARER_PREFIX = "Bearer ";
public static final String ID_CLAIM_KEY = "id";
public static final String REFRESH_TOKEN_KEY_PREFIX = "RT:";
}
10 changes: 4 additions & 6 deletions src/main/java/com/api/tokbaro/global/jwt/JwtExtractor.java
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
package com.api.tokbaro.global.jwt;

import com.api.tokbaro.global.constant.StaticValue;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

@Component
public class JwtExtractor {

public static final String AUTHORIZATION_HEADER = "Authorization";
public static final String BEARER_PREFIX = "Bearer ";

public String extractAccessToken(HttpServletRequest request) {
String bearerToken = request.getHeader(AUTHORIZATION_HEADER);
if(StringUtils.hasText(bearerToken) && bearerToken.startsWith(BEARER_PREFIX)) {
return bearerToken.substring(BEARER_PREFIX.length());
String bearerToken = request.getHeader(StaticValue.AUTHORIZATION_HEADER);
if(StringUtils.hasText(bearerToken) && bearerToken.startsWith(StaticValue.BEARER_PREFIX)) {
return bearerToken.substring(StaticValue.BEARER_PREFIX.length());
}
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,13 +111,13 @@ public boolean validateToken(String token){
.parseClaimsJws(token);
return true;
} catch (io.jsonwebtoken.security.SignatureException | MalformedJwtException e){
logger.info("์ž˜๋ชป๋œ JWT ์„œ๋ช…์ž…๋‹ˆ๋‹ค.");
logger.warn("์ž˜๋ชป๋œ JWT ์„œ๋ช…์ž…๋‹ˆ๋‹ค.");
} catch (ExpiredJwtException e){
logger.info("๋งŒ๋ฃŒ๋œ JWT ํ† ํฐ์ž…๋‹ˆ๋‹ค.");
logger.warn("๋งŒ๋ฃŒ๋œ JWT ํ† ํฐ์ž…๋‹ˆ๋‹ค.");
} catch (UnsupportedJwtException e){
logger.info("์ง€์›๋˜์ง€ ์•Š๋Š” JWT ํ† ํฐ์ž…๋‹ˆ๋‹ค.");
logger.warn("์ง€์›๋˜์ง€ ์•Š๋Š” JWT ํ† ํฐ์ž…๋‹ˆ๋‹ค.");
} catch (IllegalArgumentException e){
logger.info("JWT ํ† ํฐ์ด ์ž˜๋ชป๋˜์—ˆ์Šต๋‹ˆ๋‹ค.");
logger.warn("JWT ํ† ํฐ์ด ์ž˜๋ชป๋˜์—ˆ์Šต๋‹ˆ๋‹ค.");
}
return false;
}
Expand Down
33 changes: 0 additions & 33 deletions src/main/resources/application-local.properties

This file was deleted.