<aside> 1️⃣ JSON Web Token (JWT)란?
</aside>
<aside> 2️⃣ Spring Boot와 JWT를 함께 사용하는 방법
</aside>
build.gradle
파일에 다음과 같이 추가하면 된다.dependencies {
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'io.jsonwebtoken:jjwt:0.9.1'
}
AuthenticationFilter
**와 **AuthenticationProvider
**를 구현해야 한다.AuthenticationFilter
예시:
public class JwtAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
public JwtAuthenticationFilter() {
// super("/api/**");: "/api/**"와 일치하는 모든 요청에 이 필터를 적용하겠다는 것을 나타냅니다.
super("/api/**");
}
@Override
// attemptAuthentication(): 이 메소드는 인증 시도를 처리합니다. 이 경우, 클라이언트로부터 "Authorization" 헤더를 받아 JWT 토큰으로 사용합니다.
public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse res)
throws AuthenticationException, IOException, ServletException {
String token = req.getHeader("Authorization");
if (token == null) {
throw new RuntimeException("Invalid auth token");
}
JwtAuthenticationToken authRequest = new JwtAuthenticationToken(token);
return getAuthenticationManager().authenticate(authRequest);
}
@Override
// successfulAuthentication(): 인증이 성공적으로 이루어진 후 추가적으로 필요한 동작을 정의합니다. 여기서는 필터 체인에 있는 다음 필터를 호출하도록 설정되어 있습니다.
protected void successfulAuthentication(HttpServletRequest req, HttpServletResponse res, FilterChain chain,
Authentication auth) throws IOException, ServletException {
super.successfulAuthentication(req, res, chain, auth);
chain.doFilter(req, res);
}
}
AuthenticationProvider
예시public class JwtAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
@Override
// supports(): 이 메소드는 이 인증 제공자가 특정 인증 타입을 지원하는지 여부를 결정합니다. 여기서는 JwtAuthenticationToken만 지원합니다.
public boolean supports(Class<?> authentication) {
return (JwtAuthenticationToken.class.isAssignableFrom(authentication));
}
@Override
// additionalAuthenticationChecks(): 추가적인 인증 검사를 수행하는 곳입니다. 여기서는 아무런 동작도 수행하지 않습니다.
protected void additionalAuthenticationChecks(UserDetails userDetails,
UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
}
@Override
// retrieveUser(): 인증된 사용자를 검색하는 메소드입니다. 이 메소드에서는 토큰에서 사용자 정보를 파싱하고, 해당 정보를 바탕으로 UserDetails 객체를 생성합니다.
protected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication)
throws AuthenticationException {
JwtAuthenticationToken jwtAuthenticationToken = (JwtAuthenticationToken) authentication;
String token = jwtAuthenticationToken.getToken();
// JwtUserDto와 jwtService는 별도로 구현해야 하는 부분들입니다. JwtUserDto는 토큰에서 추출된 사용자 정보를 담는 클래스이고, jwtService는 토큰을 생성하고 검증하는 로직을 갖고 있어야 합니다.
JwtUserDto parsedUser = jwtService.parseToken(token);
if (parsedUser == null) {
throw new JwtTokenMalformedException("JWT token is not valid");
}
List<SimpleGrantedAuthority> authorityList = Collections
.singletonList(new SimpleGrantedAuthority(parsedUser.getRole()));
return new User(parsedUser.getUsername(), token, authorityList);
}
}
JwtService
예시에서)에서 구현하게 될 것이다.
이처럼 JWT를 사용하면 서버는 상태를 유지할 필요가 없으며, 클라이언트는 요청에 JWT를 포함시켜 서버에 전달하면 된다. 이 방법은 Stateless 서비스를 구축하는 데 매우 유용하다.