스프링부트 - Spring Security JWT인증하기

2025. 5. 15. 02:21·Spring
728x90
반응형
SMALL

JWT는 이전 포스트에서 다뤘기 때문에 간단하게 소개만 하겠다.

사용자 인증 정보를 JSON형태로 담아 서명한 토큰

 

세션을 사용하여 로그인 할 때

로그인 정보가 서버(세션)에 저장되어 있다.

JWT로그인을 사용하여 인증할 때

로그인 정보가 클라이언트(브라우저)에 저장되어있다.

그래서 서버 입장에서 요청을 보내는 사람이 누구인지 알 수 없다.

클라이언트가 스스로 누구인지 증명을 해야하는데 이 JWT를 이용해서 증명한다.

 

보통 4가지의 파일을 가지고 가야된다.

  • JwtUtil.java ( 토큰 생성 및 검증 도구 클래스)
  • JwtAuthFilter.java (요청마다 토큰을 꺼내서 검증하는 필터)
  • JwtLoginController.java (로그인 시 토큰 발급하는 컨트롤러)
  • SecurityConfig.java (필터 등록 및 시큐리티 설정 수정)
                <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt-api</artifactId>
        <version>0.11.5</version>
        </dependency>
        <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt-impl</artifactId>
        <version>0.11.5</version>
        <scope>runtime</scope>
        </dependency>
        <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt-jackson</artifactId>
        <version>0.11.5</version>
        <scope>runtime</scope>
        </dependency>

젤 처음에는 pom.xml에 해당 의존성을 주입시켜준다.

 

package com.example.security.util;

import io.jsonwebtoken.*;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
import org.springframework.stereotype.Component;
import java.security.Key;
import java.util.Date;

@Component
public class JwtUtil {
    // 256비트(32바이트) 이상의 키를 필요
    // Base64는 문자 1개가 6비트로 처리 (3바이트 == Base64 문자 4개)
    // 문자 4개당 3바이트를 표현하므로 32바이트를 넘기려면 최소 43자 이상 필요
    // (40개 == 30바이트, 43자 == 32.25바이트, 44자 == 33바이트)
    private final String SECRET = "1234567890123456789012345678901234567890123";
    private final long EXPIRATION = 1000 * 60 * 60; // 1시간

    private Key getSigningKey() {
        byte[] keyBytes = Decoders.BASE64.decode(SECRET);
        return Keys.hmacShaKeyFor(keyBytes);
    }

    public String createToken(String username) { // JWT 생성
        return Jwts.builder()
                .setSubject(username)
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION))
                .signWith(getSigningKey(), SignatureAlgorithm.HS256)
                .compact();
    }

    public String extractUsername(String token) { // 정보 추출
        return Jwts.parserBuilder()
                .setSigningKey(getSigningKey()).build()
                .parseClaimsJws(token)
                .getBody().getSubject();
    }

    public boolean validate(String token) { // 유효성 검사
        try {
            Jwts.parserBuilder().setSigningKey(getSigningKey()).build().parseClaimsJws(token);
            return true;
        } catch (JwtException e) {
            return false;
        }
    }
}

이 코드는 JWT를 생성 정보 추출 유효성 검사하는 도구이다.

 

@Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
            FilterChain filterChain)
            throws ServletException, IOException{
        String authHeader = request.getHeader("Authorization");
        if (authHeader != null && authHeader.startsWith("Bearer ")) {
            String token = authHeader.substring(7);
            if (jwtUtil.validate(token)) {
                String username = jwtUtil.extractUsername(token);
                //이부분은 아무나 인증을 해주고, DB를 연결안하는 코드이다.
                UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
                        username, null, List.of());
                // UserDetails userDetails = userDetailsService.loadUserByUsername(username);
                // UsernamePasswordAuthenticationToken authentication =
                // new UsernamePasswordAuthenticationToken(
                // userDetails, null, List.of());
                SecurityContextHolder.getContext().setAuthentication(authentication);
            }
        }
        filterChain.doFilter(request, response);
    }

요청할때 마다 JWT를 서버로 전달하는 역할을 하는 코드이다.

그리고 전달받은 코드가 정말로 유효한 값인지 유효성 검사까지 한다.

왜냐하면 JWT는 토큰 유효기간이 있기때문이다.

SecurityContextHolder.getContext().setAuthentication(authentication);

SecurityContextHolder에서 로그인 한 것처럼 만들어준다.(이 필터의 핵심코드이다.)

.addFilterBefore(new JwtAuthFilter(jwtUtil, userDetailsService),
                        UsernamePasswordAuthenticationFilter.class)
                .csrf(csrf -> csrf.disable())

SecurityConfig파일에 해당 addFilterBefore메서드에 넣어주고 테스트를 진행해보면 된다.

그럼 이제 POST방식으로 login을 해보겠다.

다음과 같이 토큰이 발행이 된 것을 볼 수 있다.

 

그럼 이 값으로 인증절차까지 해보겠다.

인증은 GET방식으로 해야되는데 이유는 이미 인증된 사용자의 토큰을 가지고 URL에 접근하는 것이니까 

Header에 인증받은 토큰값만 넘겨주면 되는 것이기 때문

Header에 Authorization과 Value에 

무조건 Bearer + 발급받은 Token값으로 해주면

위와 같이 JWT인증된 사용자만 접근 가능한 영역입니다. 라고 뜨게된다.

728x90
반응형
LIST

'Spring' 카테고리의 다른 글

스프링 부트 - 스프링 시큐리티 JWT로 DB와 연동해서 인증하기  (1) 2025.05.16
스프링부트 - CORS / CSRF  (0) 2025.05.15
스프링부트 - 타임리프(Thymeleaf)  (1) 2025.05.13
스프링부트 - 스프링 시큐리티  (0) 2025.05.11
스프링부트 - JWT(Json Web Token)이란?  (0) 2025.05.11
'Spring' 카테고리의 다른 글
  • 스프링 부트 - 스프링 시큐리티 JWT로 DB와 연동해서 인증하기
  • 스프링부트 - CORS / CSRF
  • 스프링부트 - 타임리프(Thymeleaf)
  • 스프링부트 - 스프링 시큐리티
주우우우우우우욱
주우우우우우우욱
    반응형
    250x250
  • 주우우우우우우욱
    주우우우우우우욱의 블로그
    주우우우우우우욱
  • 전체
    오늘
    어제
    • 분류 전체보기 (131) N
      • 백준[파이썬] (57) N
      • Spring (31)
      • CS (1)
      • 자바 (4)
      • 백준[자바] (20)
      • 프로그래머스 (5)
      • 토이프로젝트 (1)
      • SWEA (2)
      • MSA (8)
      • CI&CD (1) N
      • AWS (0)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    AOP
    스프링부트
    Java
    프로그래머스
    SpringBoot
    스프링 부트와 AWS로 혼자 구현하는 웹 서비스
    코딩테스트
    테스트코드
    JPA
    JWT
    재귀
    자바
    스프링
    MSA
    백준
    스프링 클라우드
    누적합
    SWEA
    spring
    파이썬
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
주우우우우우우욱
스프링부트 - Spring Security JWT인증하기
상단으로

티스토리툴바