main 홈페이지가 있고 admin 홈페이지가 있다고 가정하자.
admin 홈페이지에 접근하기 위해선 관리자 역할이 필요한데,
현재 내가 가지고 있는 역할이 admin인지 아닌지 검증하는 필터가 필요하다.
1. 커스텀 JWT 필터 등록:
Spring Security의 필터 체인에 사용자 정의 필터를 추가합니다.
이 필터는 일반적으로 OncePerRequestFilter를 상속받아 구현합니다.
SecurityConfig 클래스에서 이 필터를 등록합니다.
2. JWT 검증 과정:
필터는 모든 요청에 대해 실행됩니다.
HTTP 요청 헤더에서 "Authorization" 키를 확인합니다.
"Authorization" 헤더가 "Bearer "로 시작하는 JWT 토큰을 포함하고 있는지 확인합니다.
3. SecurityContext 설정:
JWT가 유효하다면, 토큰에서 사용자 정보를 추출합니다.
이 정보를 사용하여 Authentication 객체를 생성합니다.
생성된 Authentication 객체를 SecurityContextHolder에 설정합니다.
4. STATELESS 세션 관리:
JWT를 사용하면 서버 측에서 세션 상태를 유지할 필요가 없습니다.
SecurityContextHolder에 설정된 인증 정보는 해당 요청 처리 동안만 유지됩니다.
요청 처리가 끝나면 SecurityContextHolder가 자동으로 클리어됩니다.
5. 필터 체인 계속 실행:
JWT 처리가 완료되면 필터 체인의 다음 필터로 요청을 전달합니다.
JWTFilter 구현
package com.example.jpamysql.jwt;
import com.example.jpamysql.domain.UserEntity;
import com.example.jpamysql.dto.CustomUserDetails;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
public class JWTFilter extends OncePerRequestFilter {
private final JWTUtil jwtUtil;
public JWTFilter(JWTUtil jwtUtil) {
this.jwtUtil = jwtUtil;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
//request에서 Authorization 헤더를 찾아옴
String authorization = request.getHeader("Authorization");
//Authorization 헤더 검증
if (authorization == null || !authorization.startsWith("Bearer ")) {
System.out.println("token null");
filterChain.doFilter(request, response);
//조건이 해당되면 메소드 종료 (필수)
return;
}
System.out.println("authorization now");
//Bearer 부분 제거 후 순수 토큰만 획득
String token = authorization.split(" ")[1];
// 토큰 소멸 시간 검증
if(jwtUtil.isExpired(token)){
System.out.println("token expired");
filterChain.doFilter(request, response);
//조건이 해당되면 메소드 종료 (필수)
return;
}
//토큰에서 username과 role 획득
String username = jwtUtil.getUsername(token);
String role = jwtUtil.getRole(token);
//userEntity를 생성하여 값 set
UserEntity userEntity = new UserEntity();
userEntity.setUsername(username);
userEntity.setPassword("temppassword");
userEntity.setRole(role);
//UserDetails에 회원 정보 객체 담기
CustomUserDetails customUserDetails = new CustomUserDetails(userEntity);
//스프링 시큐리티 인증 토큰 생성
Authentication authToken = new UsernamePasswordAuthenticationToken(customUserDetails, null, customUserDetails.getAuthorities());
//세션에 사용자 등록
SecurityContextHolder.getContext().setAuthentication(authToken);
filterChain.doFilter(request, response);
}
}
<Authorization 헤더 검증>
String authorization = request.getHeader("Authorization");
//Authorization 헤더 검증
if (authorization == null || !authorization.startsWith("Bearer ")) {
System.out.println("token null");
filterChain.doFilter(request, response);
//조건이 해당되면 메소드 종료 (필수)
return;
}
- "Authorization" 헤더를 확인하고, "Bearer " 접두사가 있는지 검증합니다.
- 유효하지 않으면 다음 필터로 넘어갑니다.
<토큰 추출 및 검증>
//Authorization 헤더 검증
if (authorization == null || !authorization.startsWith("Bearer ")) {
System.out.println("token null");
filterChain.doFilter(request, response);
//조건이 해당되면 메소드 종료 (필수)
return;
}
- "Bearer " 접두사를 제거하고 순수 토큰을 추출합니다.
- 토큰의 만료 여부를 확인합니다.
< Spring Security 인증 객체 생성>
CustomUserDetails customUserDetails = new CustomUserDetails(userEntity);
Authentication authToken = new UsernamePasswordAuthenticationToken(customUserDetails, null, customUserDetails.getAuthorities());
- CustomUserDetails 객체를 생성하고, 이를 바탕으로 Authentication 객체를 만듭니다.
<SecurityContext에 인증 정보 설정:>
SecurityContextHolder.getContext().setAuthentication(authToken);
- 생성한 인증 정보를 Spring Security의 SecurityContext에 설정합니다.
<필터 체인 계속 실행>
filterChain.doFilter(request, response);
- filterChain.doFilter(request, response)는 현재 필터의 처리를 완료하고 다음 필터로 요청을 전달하는 역할을 합니다.
- 이 메서드를 호출하면 필터 체인의 다음 필터로 제어가 넘어가거나, 모든 필터의 처리가 완료된 경우 최종적으로 대상 서블릿이나 리소스로 요청이 전달됩니다.
- 현재 코드에서는 Authorization 헤더가 없거나 "Bearer"로 시작하지 않을 때 doFilter를 호출하고 있습니다. 이는 인증이 필요하지 않거나 실패한 경우 요청을 그대로 다음 단계로 전달한다는 의미입니다.
- doFilter를 호출하지 않으면 요청 처리가 중단되고 클라이언트에 즉시 응답이 반환됩니다.
<테스트>
- Authorization 생성 (토큰 생성)
- admin 조회할 때 head에 생성된 토큰을 복붙해주면

접속 성공!
'JAVA > Spring Security JWT' 카테고리의 다른 글
로그인 성공 시 jwt 발급 (0) | 2024.07.04 |
---|---|
JWT 발급 및 검증 클래스 (0) | 2024.07.04 |
DB기반 로그인 검증 로직 (0) | 2024.07.03 |