첫 로그인 시 구조
JWT 토큰 발급 이후의 구조
첫 로그인에는 UserDetailsService 구현체의 loadUserByUsername()이 호출된다.
하지만 첫 로그인 이후엔 JWT 토큰이 발급되었다. 그 때부터는 UserDetailsService 구현체를 호출하지 않고 JWT 검증 필터를 거치게 되는 것을 확인할 수 있었다.
//시큐리티는 filter 를 가지고 있는데, 그 필터중에 BasicAuthenticationFilter 가 있다.
//권한이나 인증이 필요한 특정 주소를 요청했을 때 위 필터를 무조건 타게 되있다.
//만약에 권한이나 인증이 필요한 주소가 아니라면 이 필터를 안탐.
public class JwtAuthorizationFilter extends BasicAuthenticationFilter {
private final UserRepository userRepository;
public JwtAuthorizationFilter(AuthenticationManager authenticationManager, UserRepository userRepository) {
super(authenticationManager);
this.userRepository = userRepository;
}
//인증이나 권한이 필요한 주소요청이 있을 떄 이 필터를 타게 된다.
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
String jwtHeader = request.getHeader("Authorization");
//header가 있는지 확인. 없으면 바로 다음 필터로 이동하고 종료.
if (jwtHeader == null || !jwtHeader.startsWith("Bearer")) {
chain.doFilter(request, response);
return;
}
//JWT 토큰을 검증해서 정상적인 사용자인지 확인
String jwtToken = request.getHeader("Authorization").replace("Bearer ", "");
String username = JWT.require(Algorithm.HMAC512("cos"))//<-시크릿키는 원래 노출 안되게 해야 함.
.build()
.verify(jwtToken)//토큰에 서명하기
.getClaim("username").asString();
//서명이 정상적으로 됬다면
if (username != null) {
User userEntity = userRepository.findByUsername(username);
PrincipalDetails principalDetails = new PrincipalDetails(userEntity);
//Jwt 토큰 서명을 통해서 서명이 정상이면 Authentication 객체를 만들어준다.
Authentication authentication = new UsernamePasswordAuthenticationToken(principalDetails, null, principalDetails.getAuthorities());
//강제로 시큐리티 세션에 접근하여 Authentication 객체를 저장한 것.
SecurityContextHolder.getContext().setAuthentication(authentication);
}
chain.doFilter(request, response);
}
}
위 JWT 검증 필터를 설정용 클래스에 등록해야 한다.
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
...
.addFilter(new JwtAuthenticationFilter(authenticationManager()))
.addFilter(new JwtAuthorizationFilter(authenticationManager(), userRepository))
...
}
}