
src/main/java/ohahsis/dailydirector/auth/model/AuthUser.java
@Data
public class AuthUser {
private final Long id;
public Long getId() {
return this.id;
}
}
src/main/java/ohahsis/dailydirector/auth/dto/request/AuthLoginRequest.java
@Data
public class AuthLoginRequest {
private String email;
private String password;
}
src/main/java/ohahsis/dailydirector/auth/dto/request/AuthLoginResponse.java
@Data
@AllArgsConstructor
public class AuthLoginResponse {
private String nickname;
private String token;
}
src/main/resources/application.yml
jwt:
secret:
key: (생성한 코드 작성)
openssl rand -hex 64
src/main/java/ohahsis/dailydirector/auth/model/AuthToken.java
@Data
public class AuthToken {
private final String key;
private final String token;
public AuthToken(String token) {
this.key = AUTH_TOKEN_HEADER_KEY;
this.token = token;
}
}
src/main/java/ohahsis/dailydirector/auth/AuthConstants.java
public class AuthConstants {
public static final String AUTH_TOKEN_HEADER_KEY = "X-FP-AUTH-TOKEN";
}
src/main/java/ohahsis/dailydirector/auth/application/TokenService.java
@Slf4j
@Component
@RequiredArgsConstructor
public class TokenService {
private final UserRepository userRepository;
private String key;
@Value("${jwt.secret.key}")
public void getSecretKey(String secretKey) {
key = secretKey;
}
// login api 에 적용
public String jwtBuilder(Long id, String nickname) {
Claims claims = Jwts.claims();
claims.put("nickname", nickname);
claims.put("uid", id);
Date now = new Date();
return Jwts.builder()
.setClaims(claims)
// TODO : 유효기간 설정은 다음 MVC에서 진행한다.
// .setExpiration(new Date(now.getTime() + accessTokenValidMillisecond))
.signWith(SignatureAlgorithm.HS256, key.getBytes())
.compact();
}
}
src/main/java/ohahsis/dailydirector/auth/application/AuthService.java
@Service
@RequiredArgsConstructor
public class AuthService {
private final UserRepository userRepository;
private final TokenService tokenService;
public AuthLoginResponse login(AuthLoginRequest request) {
var user = userRepository.findByEmailAndPassword(request.getEmail(), request.getPassword())
.orElseThrow(() -> new AuthLoginException(ErrorType.FAIL_TO_LOGIN_ERROR));
var token = tokenService.jwtBuilder(user.getId(), user.getNickname());
return new AuthLoginResponse(user.getNickname(), token);
}
}
public class AuthLoginException extends BusinessException {
public AuthLoginException(ErrorType errorType) {
super(errorType);
}
}
src/main/java/ohahsis/dailydirector/auth/presentation/AuthController.java
@RestController
@RequestMapping(path = "/api/auth", produces = MediaType.APPLICATION_JSON_VALUE)
@RequiredArgsConstructor
public class AuthController {
private final AuthService authService;
@PostMapping("/login")
public ResponseEntity<?> login(@RequestBody AuthLoginRequest request) {
var response = authService.login(request);
return ResponseDto.ok(response);
}
}
@Data
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class ResponseDto<T> implements Serializable {
private T data;
public static <T> ResponseEntity<ResponseDto<T>> ok(T data) {
return ResponseEntity.ok(new ResponseDto<T>(data));
}
public static <T> ResponseEntity<ResponseDto<T>> created(T data) {
return ResponseEntity.status(HttpStatus.CREATED).body(new ResponseDto<T>(data));
}
public static ResponseEntity<Void> noContent() {
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
}
}
src/main/java/ohahsis/dailydirector/auth/application/TokenService.java
@Slf4j
@Component
@RequiredArgsConstructor
public class TokenService {
private final UserRepository userRepository;
private String key;
@Value("${jwt.secret.key}")
public void getSecretKey(String secretKey) {
key = secretKey;
}
public void verifyToken(String token) {
// 토큰을 파싱해서 해당 토큰을 얻고, 토큰이 만료되었으면 에러 발생시킴
try {
Jwts.parser().setSigningKey(key.getBytes()).parseClaimsJws(token);
} catch (Exception e) {
if (e.getMessage().contains("JWT expired")) {
throw new AuthorizationException(ErrorType.AUTHORIZATION_ERROR);
}
throw new AuthorizationException(ErrorType.AUTHORIZATION_ERROR);
}
Long uid = getUserIdFromToken(token); // token 으로 유저의 id 를 찾아서
if (!userRepository.existsById(uid)) { // id 로 DB 조회를 통해 존재 여부 확인
throw new AuthorizationException(ErrorType.AUTHORIZATION_ERROR);
}
}
// login 외 타 api 에서 AuthUser 검증 시 적용
public AuthUser getAuthUser(AuthToken token) {
verifyToken(token.getToken()); // 토큰 관련 문제가 생길 경우 error
var id = getUserIdFromToken(token.getToken());
var user =
userRepository
.findById(id)
.orElseThrow(
() -> new AuthorizationException(ErrorType.AUTHORIZATION_ERROR));
return new AuthUser(id);
}
public Long getUserIdFromToken(String token) {
return Long.valueOf(
(Integer)
Jwts.parser()
.setSigningKey(key.getBytes())
.parseClaimsJws(token)
.getBody()
.get("uid"));
}
// login api 에 적용
public String jwtBuilder(Long id, String nickname) {
Claims claims = Jwts.claims();
claims.put("nickname", nickname);
claims.put("uid", id);
Date now = new Date();
return Jwts.builder()
.setClaims(claims)
// TODO : 유효기간 설정은 다음 MVC에서 진행한다.
// .setExpiration(new Date(now.getTime() + accessTokenValidMillisecond))
.signWith(SignatureAlgorithm.HS256, key.getBytes())
.compact();
}
}
public class AuthorizationException extends BusinessException {
public AuthorizationException(ErrorType errorType) {
super(errorType);
}
}
src/main/java/ohahsis/dailydirector/config/resolver/UserArgumentResolver.java
@Component
@RequiredArgsConstructor
public class UserArgumentResolver implements HandlerMethodArgumentResolver {
private final TokenService tokenService;
// 파라미터 타입에 AuthUser 가 있으면 잡아채서 동작하는 resolver
@Override
public boolean supportsParameter(MethodParameter parameter) { // 개념: 해당 메서드의 매개변수에 대해, 해당 resolver 가 지원하는 것인지를 체크한다.
return parameter.getParameterType().equals(AuthUser.class); // 사용: 파라미터가 AuthUser.class 를 가지고 있으면 true 를, 아니면 false 를 반환
}
@Override
public Object resolveArgument( // 개념: 매개변수로 넣어줄 값을 제공한다.
MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
var httpServletRequest = (HttpServletRequest) webRequest.getNativeRequest();
var accessToken = httpServletRequest.getHeader(AUTH_TOKEN_HEADER_KEY); // request 의 헤더에서 토큰을 꺼낸다.
if (accessToken == null) {
if (parameter.isOptional()) {
return null;
}
accessToken = "";
}
var token = new AuthToken(accessToken);
return tokenService.getAuthUser(token); // 사용: token 을 통해 얻은 AuthUser 객체를 반환한다.
}
}
Argument Resolversrc/main/java/ohahsis/dailydirector/config/web/WebConfig.java
@Configuration
@RequiredArgsConstructor
public class WebConfig implements WebMvcConfigurer {
private final UserArgumentResolver userArgumentResolver;
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(userArgumentResolver);
}
}