首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >在AuthenticationEntryPoint中捕获从OncePerRequestFilter的子类引发的自定义异常

在AuthenticationEntryPoint中捕获从OncePerRequestFilter的子类引发的自定义异常
EN

Stack Overflow用户
提问于 2019-06-05 02:00:29
回答 2查看 780关注 0票数 0

我有一个扩展OncePerRequestFilter的JWTAuthFilter,我在这里验证令牌。

validateToken方法抛出自定义异常(扩展org.springframework.security.core.AuthenticationException的CredentialsChangedException和TooManyDevicesException )

这些异常在过滤器中被正确捕获,但是当它们前进到AuthenticationEntryPoint时,AuthenticationException变成一个instanceof InsufficientAuthenticationException,并且我希望作为响应返回的自定义错误消息丢失。

代码语言:javascript
复制
@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);
    }
}
代码语言:javascript
复制
@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);
        }

    }
}

我想从我的过滤器发送一个适当的未经授权的响应,有没有办法做到这一点?

EN

回答 2

Stack Overflow用户

发布于 2019-06-05 02:11:33

我认为一旦你在JwtAuthFilter中捕获了AuthenticationException,你就不应该继续使用下一个过滤器,因为很可能会有一个AnonymousAuthenticationFilter位于过滤器链的后面,如果SecurityContextHolder为空,这个过滤器会将当前请求配置为匿名用户(即当身份验证失败时发生)。InsufficientAuthenticationException很可能是由于Spring认为当前请求是一个访问某些受保护的URL或方法的匿名用户造成的。

相反,一旦在JwtAuthFilter中捕获了AuthenticationException,就应该调用AuthenticationEntryPoint.commence()并结束过滤器链。这也是BasicAuthenticationFilter现在做的事情。

因此,我建议将JwtAuthFilter修改为:

代码语言:javascript
复制
@Component
public class JwtAuthFilter extends OncePerRequestFilter {

  @Autowired
  private AuthenticationEntryPoint authenticationEntryPoint;


  @Override
  protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
                    throws ServletException, IOException {
         try{

              //validate JWT

          } catch (AuthenticationException e) {
               logger.error(e.getLocalizedMessage());
                SecurityContextHolder.clearContext();
                this.authenticationEntryPoint.commence(request, response, e);
                return;
          }
    }
}
票数 0
EN

Stack Overflow用户

发布于 2019-06-05 21:27:53

作为目前的一种解决方法,我只需将来自JwtAuthFilter的自定义错误添加为request属性,并在AuthenticationEntryPoint中检索它

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56449140

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档