Spring boot/Blog 프로젝트 만들기(JPA)
JwtUtil 만들어 보기
치치ㅤ
2024. 11. 5. 15:04
의존성 추가
implementation 'com.auth0:java-jwt:4.4.0'
dependencies {
// Java jwt lib 가져오기
implementation 'com.auth0:java-jwt:4.4.0'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-mustache'
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
runtimeOnly 'com.h2database:h2'
runtimeOnly 'com.mysql:mysql-connector-j'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
Jwt lib 추가 (java-jwt)
https://github.com/auth0/java-jwt?tab=readme-ov-file
GitHub - auth0/java-jwt: Java implementation of JSON Web Token (JWT)
Java implementation of JSON Web Token (JWT). Contribute to auth0/java-jwt development by creating an account on GitHub.
github.com
implementation group: 'com.auth0', name: 'java-jwt', version: '4.3.0'
💡 학습 목표
1. JWT를 사용하여 사용자 정보를 안전하게 전달하고 검증하는 방법을 배운다.
💡 Gradle의 캐시 파일이 문제가 되어 라이브러리를 인식하지 못할 수 있습니다. 이 경우, 터미널에서 다음 명령어를 실행하여 Gradle 캐시를 정리할 수 있습니다.
./gradlew clean --refresh-dependencies
JwtUtil 클래스 만들기
package com.tenco.blog_v3.common.utils;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.tenco.blog_v3.user.User;
import java.util.Date;
/**
* JWT 토큰의 생성 및 검증을 위한 유틸 클래스 이다.
* 여기서는 알고리즘 HMAC512 알고리즘을 사용한다.
*/
public class JwtUtil {
/**
*
* 주어진 사용자 정보(USER)로 JWT 토큰을 생성한다.
*
* return 생성된 JWT String
*/
public static String create(User user) {
return JWT.create()
// 헤더
.withSubject("blog")
.withExpiresAt(new Date(System.currentTimeMillis() + 1000 * 60 * 60))
// 페이로드 - 데이터 조각 클레임(사용자 id, 사용자 이름)
.withClaim("id", user.getId())
.withClaim("username", user.getUsername())
// 서명
.sign(Algorithm.HMAC512("tencoding"));
}
public static User verify(String token) {
// JWT 디코딩
DecodedJWT decodedJWT = JWT.require(Algorithm.HMAC512("tencoding"))
.build().verify(token);
// 검증된 JWT 에서 사용자 ID 와 이름 추출 해보자
int id = decodedJWT.getClaim("id").asInt();
String username = decodedJWT.getClaim("username").asString();
return User.builder().id(id).username(username).build();
}
}
UserService
/**
* 로그인 서비스
*
*/
public String signIn(UserRequest.LoginDTO reqDTO) {
User seessionUser = userJPARepository
.findByUsernameAndPassword(reqDTO.getUsername(), reqDTO.getPassword())
.orElseThrow( () -> new Exception401("인증되지 않았습니다"));
return JwtUtil.create(seessionUser);
}
UserController
@PostMapping("/login")
public ResponseEntity<ApiUtil<UserResponse.DTO>> login(@RequestBody UserRequest.LoginDTO reqDto) {
String jwt = userService.signIn(reqDto);
return ResponseEntity.ok()
.header(Define.AUTHORIZATION, Define.BEARER + jwt)
.body(new ApiUtil<>(null));
}
회원 정보 수정
- UserController
/**
* 회원 정보 수정
*/
@PutMapping("/api/users/{id}")
public ResponseEntity<?> update(@PathVariable(name = "id") Integer id, @RequestBody UserRequest.UpdateDTO reqDTO, HttpServletRequest request) {
// 헤더에 있는 JWT 토큰을 가져 오기
// 토큰에서 사용자 정보 추출
// 사용자 정보 수정 로직일 그대로 사용
String authorizationHeader = request.getHeader(Define.AUTHORIZATION);
if (authorizationHeader == null || !authorizationHeader.startsWith(Define.BEARER)) {
throw new Exception401("인증 정보가 유효하지 않습니다");
}
// BEARER 문자열과 공백 한칸 제거 처리
String token = authorizationHeader.replace(Define.BEARER, "");
User sessionUser = JwtUtil.verify(token);
if(sessionUser == null) {
throw new Exception401("인증 토큰이 유효하지 않습니다");
}
if(sessionUser.getId() != id) {
throw new Exception403("해당 사용자를 수정할 권한이 없습니다.");
}
// 서비스에 사용자 정보 수정 요청
UserResponse.DTO resDTO = userService.updateUser(id, reqDTO);
return ResponseEntity.ok(new ApiUtil<>(resDTO));
}
UserService
@Transactional // 트랜잭션 관리
public UserResponse.DTO updateUser(int id, UserRequest.UpdateDTO reqDTO){
// 1. 사용자 조회 및 예외 처리
User user = userJPARepository.findById(id)
.orElseThrow(() -> new Exception404("회원정보를 찾을 수 없습니다"));
// 2. 사용자 정보 수정
user.setPassword(reqDTO.getPassword());
user.setEmail(reqDTO.getEmail());
// 더티 체킹을 통해 변경 사항이 자동으로 반영됩니다.
return new UserResponse.DTO(user);
}
포스트맨 활용