Spring Security + JWT 6

johaS2·2025년 2월 4일

암호화 키 properties에 저장

spring.jwt.secret=afdsjlakfjskalrjkljsakrjaskldrl > 아무거나

JwtUtil - JWT 발급과 검증 클래스

@Component
public class JWTUtil {

    private SecretKey secretKey;

    // SecretKeySpec은 SecretKey를 생성하기 위한 구체적인 방법
    public JWTUtil(@Value("${spring.jwt.secret}")String secret) {
        secretKey = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), Jwts.SIG.HS256.key().build().getAlgorithm());
    }

    // JWT 토큰에서 username을 추출하는 메서드
    // 토큰을 검증하고, 토큰 안에 담긴 정보를 파싱해서 가져옴
    // 파싱된 내용 중 username 키 값을 찾아 사용자 이름을 반환!
    public String getUsername(String token) {
        return Jwts.parser().verifyWith(secretKey).build()
                .parseSignedClaims(token).getPayload().get("username", String.class);
    }
    // Jwts는 JWT 처리 라이브러리에서 제공하는 클래스
    // parser()는 토큰을 검증하고 파싱하는 메서드

    // role을 추출
    public String getRole(String token) {

        return Jwts.parser().verifyWith(secretKey).build().parseSignedClaims(token).getPayload().get("role", String.class);
    }

    // JWT 토큰이 만료되었는지 체크 !
    public Boolean isExpired(String token) {

        return Jwts.parser().verifyWith(secretKey).build().parseSignedClaims(token).getPayload().getExpiration().before(new Date());
    }

    // 새로운 JWT 토큰 생성 메소드
    public  String createJwt(String username, String role, Long expiredMs) {
        return Jwts.builder()
                .claim("username", username) // claim으로 추가!
                .claim("role", role)
                .issuedAt(new Date(System.currentTimeMillis())) // issuedAt()은 토큰 발급 시간
                .expiration(new Date(System.currentTimeMillis() + expiredMs)) // expiration()은 만료 시간
                .signWith(secretKey) // signWith(secretKey)는 비밀 키를 사용하여 서명을 하여 JWT 토큰을 생성
                .compact();
    } }

로그인 성공시 JWT 발급 구현

  • LoginFilter 에 JWTUtil을 주입
private final JWTUtil jwtUtil;

    public LoginFilter(AuthenticationManager authenticationManager, JWTUtil jwtUtil) {
        this.authenticationManager = authenticationManager;
        this.jwtUtil = jwtUtil;
    }
  • SecurityConfig에 JWTUtil 주입, Filter에도

    private final JWTUtil jwtUtil;
    
       public SecurityConfig(AuthenticationConfiguration authenticationConfiguration, JWTUtil jwtUtil) {
    
           this.authenticationConfiguration = authenticationConfiguration;
           this.jwtUtil = jwtUtil;
       }
       //...
       http
                   .addFilterAt(new LoginFilter(authenticationManager(authenticationConfiguration), jwtUtil), UsernamePasswordAuthenticationFilter.class);
    
  • 성공시

//로그인 성공시 실행하는 메소드 (여기서 JWT를 발급하면 됨)
    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authentication) {
        // 현재 인증된 사용자의 정보를 가져옴
        CustomUserDetails customUserDetails = (CustomUserDetails) authentication.getPrincipal();

        // 사용자 정보 추출
        String username = customUserDetails.getUsername();

        // 사용자 권한 추출
        Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
        Iterator<? extends GrantedAuthority> iterator = authorities.iterator();
        // iterator.next()를 통해 첫 번째 권한을 추출
        GrantedAuthority auth = iterator.next();
        // 문자열 형태로 가져온다 ROLE_ADMIN 처럼
        String role = auth.getAuthority();

        // JWT 생성
        String token = jwtUtil.createJwt(username, role, 60*60*10L);

        // JWT를 Response Header에 추가
        response.addHeader("Authorization", "Bearer " + token);
    }
  • 실패시
//로그인 실패시 실행하는 메소드
    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) {
        response.setStatus(401);
    }
profile
passionate !!

0개의 댓글