У меня есть JWTAuthFilter, который расширяет OncePerRequestFilter
, где я проверяю токен.
Метод validateToken генерирует пользовательские исключения (CredentialsChangedException и TooManyDevicesException, которые расширяют org.springframework.security.core.AuthenticationException
)
Эти исключения правильно фиксируются в фильтре, но когда они перемещаются к AuthenticationEntryPoint
, AuthenticationException превращается в instanceof
InsufficientAuthenticationException
, и пользовательское сообщение об ошибке, которое я хочу вернуть в ответ, теряется.
@Component
public class JwtAuthFilter extends OncePerRequestFilter {
private static final String BEARER = "Bearer ";
private static final Logger logger = LoggerFactory.getLogger(JwtAuthFilter.class);
@Autowired
private UserDetailsService jwtUserDetailsService;
@Autowired
private JwtTokenUtil jwtTokenUtil;
@Value ("${jwt.http.request.header}")
private String tokenHeader;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
final String requestTokenHeader = request.getHeader(this.tokenHeader);
String username = null;
String jwtToken = null;
if((requestTokenHeader != null) && requestTokenHeader.startsWith(BEARER)) {
jwtToken = requestTokenHeader.substring(7);
try {
username = jwtTokenUtil.getUsernameFromToken(jwtToken);
if((username != null) && (SecurityContextHolder.getContext()
.getAuthentication() == null)) {
UserDetails userDetails = this.jwtUserDetailsService.loadUserByUsername(username);
if(jwtTokenUtil.validateToken(jwtToken, userDetails)) {
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
new UsernamePasswordAuthenticationToken(userDetails, null,
userDetails.getAuthorities());
usernamePasswordAuthenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext()
.setAuthentication(usernamePasswordAuthenticationToken);
}
}
}
catch (IllegalArgumentException e) {
logger.error("Unable to get username from JWT. ", e.getLocalizedMessage());
}
catch (ExpiredJwtException e) {
logger.warn("Expired JWT. ", e.getLocalizedMessage());
}
catch (Exception e) {
logger.error(e.getLocalizedMessage());
}
}
chain.doFilter(request, response);
}
}
@Component
public class JwtUnAuthorizedResponseAuthenticationEntryPoint implements AuthenticationEntryPoint , Serializable {
private static final long serialVersionUID = - 8970718410437077606L;
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e)
throws IOException {
if(e instanceof TooManyDevicesException) {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, Constants.TOO_MANY_DEVICES);
}
else if(e instanceof CredentialsChangedException) {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, Constants.CREDENTIALS_CHANGED);
}
else {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, Constants.JWT_EXPIRED);
}
}
}
Я хочу отправить соответствующий несанкционированный ответ от моего фильтра, есть ли способ сделать это?