JWT
https://jwt.io/
- 인증 헤더 내에서 사용되는 토큰 포맷
- 두 개의 시스템끼리 안전한 방법으로 통신 가능
- 장점
- 클라이언트 독립적인 서비스(stateless)
- CDN
- No Cookie-Session (No CSRF, 사이트간 요청 위조)
- 지속적인 토큰 저장
로그인 처리 과정

AuthenticationFilter 수정
- Dependencies (Gradle)
implementation 'io.jsonwebtoken:jjwt:0.9.1'
추가
successfulAuthentication()
함수 추가
// AuthenticationFilter.java
@Slf4j
public class AuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private AuthenticationManager authenticationManager;
private UserService userService;
private Environment env;
public AuthenticationFilter(AuthenticationManager authenticationManager,
UserService userService,
Environment env) {
this.userService = userService;
this.env = env;
super.setAuthenticationManager(authenticationManager);
}
...
@Override
protected void successfulAuthentication(HttpServletRequest request,
HttpServletResponse response,
FilterChain chain,
Authentication authResult) throws IOException, ServletException {
String userName = ((User)authResult.getPrincipal()).getUsername();
UserDto userDetails = userService.getUserDetailsByEmail(userName);
String token = Jwts.builder()
.setSubject(userDetails.getUserId())
.setExpiration(new Date(System.currentTimeMillis()
+ Long.parseLong(env.getProperty("token.expiration_time"))))
.signWith(SignatureAlgorithm.ES512, env.getProperty("token.secret"))
.compact();
response.addHeader("token", token);
response.addHeader("userId", userDetails.getUserId());
}
}
Service 수정
// UserService.java
public interface UserService extends UserDetailsService {
UserDto createUser(UserDto userDto);
UserDto getUserByUserId(String userId);
Iterable<UserEntity> getUserByAll();
UserDto getUserDetailsByEmail(String email);
}
// UserServiceImpl.java
@Service
public class UserServiceImpl implements UserService {
private UserRepository userRepository;
private BCryptPasswordEncoder bCryptPasswordEncoder;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserEntity userEntity = userRepository.findByEmail(username);
if (userEntity == null) {
throw new UsernameNotFoundException(username);
}
return new User(userEntity.getEmail(),
userEntity.getEncryptedPwd(),
true,
true,
true,
true,
new ArrayList<>());
}
@Autowired
public UserServiceImpl(UserRepository userRepository, BCryptPasswordEncoder bCryptPasswordEncoder) {
this.userRepository = userRepository;
this.bCryptPasswordEncoder = bCryptPasswordEncoder;
}
...
@Override
public UserDto getUserDetailsByEmail(String email) {
UserEntity userEntity = userRepository.findByEmail(email);
UserDto userDto = new ModelMapper().map(userEntity,UserDto.class);
return userDto;
}
API Gateway에 Spring Security와 JWT 사용 추가
AuthorizationHeaderFilter
추가
- Dependencies (Gradle)
implementation 'io.jsonwebtoken:jjwt:0.9.1'
추가
// AuthorizationHeaderFilter.java
@Component
@Slf4j
public class AuthorizationHeaderFilter extends AbstractGatewayFilterFactory<AuthorizationHeaderFilter.Config> {
Environment env;
public AuthorizationHeaderFilter(Environment env) {
this.env = env;
}
public static class Config {
}
// CustomFilter
// login -> token -> users (with token) -> header (include token)
@Override
public GatewayFilter apply(Config config) {
return ((exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest();
if (!request.getHeaders().containsKey(HttpHeaders.AUTHORIZATION)) {
return onError(exchange, "No authorization header", HttpStatus.UNAUTHORIZED);
}
String authorizationHeader = request.getHeaders()
.get(HttpHeaders.AUTHORIZATION)
.get(0);
String jwt = authorizationHeader.replace("Bearer", "");
if (!isJwtValid(jwt)) {
return onError(exchange, "JWT token is not valid", HttpStatus.UNAUTHORIZED);
}
return chain.filter(exchange);
});
}
// JWT 유효성 체크
private boolean isJwtValid(String jwt) {
boolean returnValue = true;
String subject = null;
try {
subject = Jwts.parser().setSigningKey(env.getProperty("token.secret"))
.parseClaimsJws(jwt).getBody()
.getSubject();
} catch (Exception e) {
returnValue = false;
}
if(subject == null || subject.isEmpty()) {
returnValue = false;
}
return returnValue;
}
// Error메시지
// Mono, Flux -> Spring WebFlux
private Mono<Void> onError(ServerWebExchange exchange, String err, HttpStatus httpStatus) {
ServerHttpResponse response = exchange.getResponse();
response.setStatusCode(httpStatus);
log.error(err);
return response.setComplete();
}
}
javax/xml/bind/DatatypeConverter 에러 발생 시
- build.gradle의 dependencies에
implementation 'io.jsonwebtoken:jjwt:0.9.1'
Postman 테스트

Get
요청 시 token이 없으면 401에러 (인증 자격이 없음) 발생

- token 추가 시 200 OK와 정보를 반환하는 것을 볼 수 있다.