Spring Security JWT

김정현·4일 전
0

Spring

목록 보기
15/15

JWT란 무엇인가?

JWT(Json Web Token)는 사용자 인증과 권한 부여를 위해 사용되는 토큰 기반 인증 방식
일반적으로 사용자가 로그인하면 서버는 JWT를 발급하고, 이후 요청마다 클라이언트는 이 토큰을 포함하여 서버에 보냄
서버는 이 토큰을 검증하여 사용자를 인증하고 권한을 확인할 수 있음.

  • 구조
헤더(Header).페이로드(Payload).서명(Signature)

Header(헤더): 토큰 타입(JWT)과 해싱 알고리즘(HMAC, RSA 등) 정보 포함

Payload(페이로드): 사용자 정보(예: ID, 권한, 만료 시간) 포함

Signature(서명): 토큰 위조 방지를 위한 서명

ex)

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiIxMjMiLCJyb2xlIjoiVVNFUiIsImV4cCI6MTcwOTAwMDAwMH0.abc123xyz456

Spring Security JWT

일반적으로 Spring Security에서 UsernamePasswordAuthenticationFilter를 사용하여 로그인 처리를 함.
하지만 JWT를 사용할 경우, 서버가 사용자 세션을 관리하지 않고, 클라이언트가 인증 정보를 자체적으로 보유하게 됨.
따라서 요청이 들어올 때마다 JWT를 검증하고, 해당 정보를 기반으로 사용자를 인증하는 커스텀 필터를 구현해야함.

필터 클래스 생성

Spring Security의 GenericFilterBean을 상속하여 필터를 구현

@Component
@RequiredArgsConstructor
public class LoginFilter extends GenericFilterBean {
    
    private final RestTemplate restTemplate;
    private final ObjectMapper objectMapper;
    private final Utils utils;

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        
        String token = getToken(request);
        if (StringUtils.hasText(token)) {
            loginProcess(token);
        }
        
        chain.doFilter(request, response);
    }
}

JWT 토큰 추출

클라이언트가 보낸 요청에서 JWT 토큰을 추출하는 메서드를 작성

private String getToken(ServletRequest request) {
    HttpServletRequest req = (HttpServletRequest) request;
    String bearerToken = req.getHeader("Authorization");
    if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
        return bearerToken.substring(7).trim();
    }
    return req.getParameter("token");
}
  • Authorization 헤더에서 Bearer 토큰을 추출함.
  • 헤더가 없는 경우, URL의 token 파라미터 값을 검사함.

JWT 검증 및 사용자 인증 처리

JWT를 검증하고, 사용자 정보를 SecurityContextHolder에 저장하는 로직을 작성

private void loginProcess(String token) {
    try {
        String apiUrl = utils.url("/account", "memberservice");
        
        HttpHeaders headers = new HttpHeaders();
        headers.setBearerAuth(token);
        HttpEntity<Void> entity = new HttpEntity<>(headers);
        ResponseEntity<JSONData> response = restTemplate.exchange(apiUrl, HttpMethod.GET, entity, JSONData.class);

        if (response.getStatusCode().is2xxSuccessful()) {
            JSONData data = response.getBody();
            if (data != null && data.isSuccess()) {
                String json = objectMapper.writeValueAsString(data.getData());
                Member member = objectMapper.readValue(json, Member.class);
                
                List<SimpleGrantedAuthority> authorities = List.of(new SimpleGrantedAuthority(member.getAuthority().name()));
                
                MemberInfo memberInfo = MemberInfo.builder()
                        .email(member.getEmail())
                        .password(member.getPassword())
                        .member(member)
                        .authorities(authorities)
                        .build();

                Authentication authentication = new UsernamePasswordAuthenticationToken(memberInfo, token, memberInfo.getAuthorities());
                SecurityContextHolder.getContext().setAuthentication(authentication);
            }
        }
    } catch (JsonProcessingException e) {
        e.printStackTrace();
    }
}
  • JWT를 이용해 회원 정보를 가져온다.
  • 회원의 Authority 정보를 SimpleGrantedAuthority 리스트에 추가한다.
  • SecurityContextHolder에 인증 객체를 저장하여 로그인 처리를 완료한다.

-SimpleGrantedAuthority는 Spring Security에서 제공하는 클래스,
Spring Security에서 권한을 설정하고 체크할 때 필수적으로 사용

필터 등록 및 적용

Spring Security에서 LoginFilter가 실행되도록 필터 체인에 등록해야 한다.

@Configuration
public class SecurityConfig {
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http, LoginFilter loginFilter) throws Exception {
        return http
                .addFilterBefore(loginFilter, UsernamePasswordAuthenticationFilter.class)
                .authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
                .build();
    }
}
  • addFilterBefore(loginFilter, UsernamePasswordAuthenticationFilter.class)을 사용하여 로그인 필터가 Spring Security 필터 체인에서 먼저 실행되도록 설정한다.

  • 모든 요청을 인증된 사용자만 접근할 수 있도록 설정한다.

0개의 댓글

관련 채용 정보