Spring Security JWT Filter
Есть микросервисная архитектура. Сервис подключен к серверу авторизации с использованием JWT токенов.
Настройка авторизации на сервисе:
@EnableWebSecurity
public class SecurityConfigSecured extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.oauth2ResourceServer()
.jwt();
}
}
После прохождения авторизации из контекста спринга можно вытащить
SecurityContextHolder.getContext().getAuthentication().getPrincipal();
UserDetails userDetails = (UserDetails) principal;
Но мне нужно из Jwt токена вытащить кастомные поля, например
String user_custom_field;
Для этого, я создал:
public class JwtUser extends UsernamePasswordAuthenticationToken {
private String user_custom_field;
// далее необходимые конструкторы, геттеры и сеттеры
}
И вот дальше, я хочу, чтоб в контексте спринга был именно JwtUser...
Я пытался запихнуть его в контекст при помощи
.addFilterAfter(new JwtTokenAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilterAfter(new JwtTokenAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.oauth2ResourceServer()
.jwt();
}
Для чего создал:
public class JwtTokenAuthenticationFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
String parsedToken = request.getHeader(TOKEN_HEADER).replace(TOKEN_PREFIX, "");
try {
Claims claims = getAllClaimsFromToken(parsedToken.substring(0, parsedToken.lastIndexOf('.') + 1));
if (claims.getSubject() != null) {
@SuppressWarnings("unchecked")
List<String> authorities = claims.get("groups", List.class);
// 1. Create auth object
JwtUser jwtUser = new JwtUser(
claims.getSubject()
, null
, authorities.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList())
, claims.get("user_custom_field", String.class)
);
// 2. Authenticate the user
SecurityContextHolder.getContext().setAuthentication(jwtUser);
}
} catch (Exception e) {
// In case of failure. Make sure it's clear; so guarantee user won't be authenticated
log.error("", e);
SecurityContextHolder.clearContext();
}
// go to the next filter in the filter chain
chain.doFilter(request, response);
}
Ну и дальше в коде, я пытаюсь получить авторизованного JwtUser из контекста спринга:
log.info("Authentication class is {}",SecurityContextHolder.getContext().getAuthentication());
получаю:
Authentication class is org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken@ef95dfc: Principal: org.springframework.security.oauth2.jwt.Jwt@f9381dc5; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@3bcc: RemoteIpAddress: 192.168.21.168; SessionId: null; Granted Authorities: SCOPE_openid, SCOPE_offline_access, SCOPE_microprofile-jwt, SCOPE_address, SCOPE_email, SCOPE_profile, SCOPE_phone
Что я делаю не так???