[Spring] JWT 적용하기

류재성's avatar
Apr 15, 2024
[Spring] JWT 적용하기
 
 
💡
토큰을 세션에 저장할 수 있다. 세션을 임시로 쓰면 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); } }
 
notion image
 
notion image
 

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; } } }
 
 
notion image
 
 
 
 
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

{CODE-RYU};