토큰을 세션에 저장할 수 있다. 세션을 임시로 쓰면 stateless 방식으로 쓸 수 있다.
1. 토큰 생성
package shop.mtcoding.blog._core.utils;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import shop.mtcoding.blog.user.User;
import java.util.Date;
public class JwtUtill {
//토큰 생성
public static String create(User user){
String jwt = JWT.create()
.withSubject("blog")
.withExpiresAt(new Date(System.currentTimeMillis()+1000*60*60))
.withClaim("id",user.getId())
.withClaim("username",user.getUsername())
.sign(Algorithm.HMAC512("metacoding"));
return jwt;
}
}
JUnit 테스트
package shop.mtcoding.blog._core.utils;
import org.junit.jupiter.api.Test;
import shop.mtcoding.blog.user.User;
public class JwtUtillTest {
@Test
public void create_test(){
User user = User.builder()
.id(1)
.username("ssar")
.build();
String jwt = JwtUtill.create(user);
System.out.println(jwt);
}
}


2. 검증하기
public static void verify(String jwt){
DecodedJWT decodedJWT = JWT.require(Algorithm.HMAC512("metacoding"))
.build().verify(jwt);
}
User/SessionUser
package shop.mtcoding.blog.user;
import jakarta.persistence.criteria.CriteriaBuilder;
import lombok.Builder;
import lombok.Data;
//서비스는 엔티티를 리턴하지 않는다. 엔티티를 이 클래스에 담아서 리턴하기 위해 만듬
import java.sql.Timestamp;
@Data
public class SessionUser {
private Integer id;
private String username;
private String email;
private Timestamp createdAt;
public SessionUser(User user) {
this.id = user.getId();
this.username = user.getUsername();
this.email = user.getEmail();
this.createdAt = user.getCreatedAt();
}
@Builder
public SessionUser(Integer id, String username, String email, Timestamp createdAt) {
this.id = id;
this.username = username;
this.email = email;
this.createdAt = createdAt;
}
}
public static SessionUser verify(String jwt){
DecodedJWT decodedJWT = JWT.require(Algorithm.HMAC512("metacoding"))
.build().verify(jwt);
int id = decodedJWT.getClaim("id").asInt();
String username = decodedJWT.getClaim("username").asString();
//검증 하고 세션 유저에 담아서 리턴. 이 객체를 세선에 저장. 접근할 떄마다 새로운 세션에 저장.
// 옛날 방식은 같은 세션에 저장하기 때문에 서버가 달라지면 세션에 값이 없었음
// 이 방식은 토큰을 가지고 인증되면 임시 세션에 값을 저장해서 종료되기 전까지만 사용하고 새로운
//서버에 접근하면 새로운 세션을 씀
return SessionUser.builder()
.id(id)
.username(username)
.build();
}
_core/interceptor/LoginInterceptor
package shop.mtcoding.blog._core.interceptor;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import org.springframework.web.servlet.HandlerInterceptor;
import shop.mtcoding.blog._core.errors.exception.Exception401;
import shop.mtcoding.blog._core.utils.JwtUtill;
import shop.mtcoding.blog.user.SessionUser;
// /api/** 인증 필요 주소
public class LoginInterceptor implements HandlerInterceptor{
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//Bearer jwt 토큰
String jwt = request.getHeader("Authorization");
if(jwt ==null){
throw new Exception401("jwt 토큰을 전달해주세요");
}
jwt = jwt.replace("Bearer ","") ; //Bearer 뒤에 한칸 띄움
try {
SessionUser sessionUser = JwtUtill.verify(jwt);
//임시 세션(jsessionId 는 필요없음)
HttpSession session = request.getSession();
session.setAttribute("sessionUser",sessionUser);
return true;
} catch (Exception e) {
return false;
}
}
}

public String 로그인(UserRequest.LoginDTO reqDTO){
User user = userJPARepository.findByUsernameAndPassword(reqDTO.getUsername(), reqDTO.getPassword())
.orElseThrow(() -> new Exception401("인증되지 않았습니다"));
String jwt = JwtUtill.create(user);
return jwt; // 엔티티를 응답하는 것보다 dto 나 클래스를 만들어서 리턴하는게 좋음. 엔티티는 정보가 많아 위험
}
Share article