我有自定义安全过滤器,作为额外的授权步骤。
过滤器检查用户是否可以被授权,如果用户不应该访问该资源,则会抛出异常。
问题是如果我从过滤器中抛出异常 - 它没有映射到正确的状态代码(在我的情况下我需要HTTP 403)。
我无法使用@ControllerAdvice
和@ExceptionHandler
因为security filters work before controller handling。
我想可能是我做错了,我不应该抛出异常,或者我应该抛出一个非常具体的。
问:有没有办法自动将过滤器中的异常映射到正确的状态代码?或者有没有办法在没有例外的情况下实现过滤器?
注意:我还阅读this post,但是从调试中我发现我的过滤器链不包含ExceptionTranslationFilter
。
答案 0 :(得分:0)
或者有没有办法在没有例外的情况下实现过滤器?
显然,您可以直接写入响应并从捕获身份验证或授权失败的那一点返回。因为我只有一个JWT身份验证过滤器实现 - AbstractAuthenticationProcessingFilter
,因此抛出异常然后全局处理它似乎对我来说太多不必要的过度工作了每当不符合身份验证条件时,例如JWT令牌解析问题,丢失令牌,格式错误的令牌等,我只需记录错误,设置HttpStatus
并从null
方法返回attemptAuthentication
。
这样我的整个逻辑被封装在单个类中。我还必须为所有情况发送401
,但错误消息不同,并且由一个简单的实用方法处理。
如果您必须从应用程序中的许多地方执行此操作,我发现抛出然后处理异常没有任何错误,在这种情况下,处理程序可以在Nicholas Smith的答案中指定。
答案 1 :(得分:-1)
Spring
推荐的方法是使用@Component
来实现AccessDeniedHandler
,然后在您的类中WebSecurityConfigurerAdapter
将其注册到.accessDeniedHandler()
configure(HttpSecurity ...)
方法。这适用于403
,如果您希望包含401
错误,则需要扩展Http401AuthenticationEntryPoint
。我将重点关注以下403
个案例。
您的WebSecurityConfigurerAdapter
@Override
protected void configure(final HttpSecurity http) throws Exception {
...
http
.csrf().disable()
.exceptionHandling().authenticationEntryPoint(<YOUR Http401AuthenticationEntryPoint>)
.and()
.exceptionHandling().accessDeniedHandler(<YOUR ACCESS DENIED HANDLER>);
...
}
您的AccessDeniedHandler
@Override
public void handle(HttpServletRequest request,
HttpServletResponse response,
AccessDeniedException accessDeniedException) throws IOException, ServletException {
response.setHeader("Content-Type", "application/hal+json;charset=UTF-8");
response.getOutputStream()
.print(objectMapper
.writeValueAsString("Access Denied");
response.setStatus(403);
}