我们正在使用Spring MVC + spring security + hibernate创建一个RESTful API。 该API可以生成JSON和HTML。 为弹簧安全性做好错误处理让我头疼:在Spring Security中处理自定义异常
身份验证可能以各种方式发生:BasicAuth,通过POST请求中的不同参数以及Web登录。 对于每种认证机制,在spring security xml config的<http>
命名空间元素中声明了一个过滤器。
我们在自定义HandlerExceptionResolver
中处理所有弹簧异常。这适用于我们的控制器中引发的所有异常,但我不知道如何处理自定义弹簧安全筛选器中引发的自定义异常。 由于在我们的控制器被调用之前,Spring安全过滤器就会出现,所以我们没有看到我们在自定义弹簧安全过滤器中抛出的异常。
我在这里找到这个问题stackoverflow.com问题: Use custom exceptions in Spring Security。不过,我不明白他们在哪里处理那里引发的异常。 我们尝试了这种方法,但我们的自定义HandlerExceptionResolver
未被调用。相反,用户会看到由tomcat呈现的丑陋堆栈跟踪。
为什么我们需要这个? 用户可以被激活和停用。如果它们被停用并尝试执行某些操作,我们希望返回带有自定义错误消息的JSON。这应该与弹簧安全性抛出AccessDeniedException
时显示的不同。 AccessDeniedException
以某种方式使它成为我们的HandlerExceptionResolver
,但我无法追踪到底。
可能的解决方法 我们想过用一个ExceptionTranslationFilter
,然而,当我们把我们的自定义异常(设置在doFilter()方法的catch语句断点)这不叫。根据我的理解,应该调用这个catch块并使用一个认证入口点。
另一种可能性:我们可以做类似的东西ExceptionTranslationFilter
在春季安全过滤器链,做类似于其AccessDeniedHandler
做一些事情:
RequestDispatcher dispatcher = request.getRequestDispatcher(errorPage);
dispatcher.forward(request, response);
我们可以添加一些参数(错误代码,原因等。 )发送到请求,并让它指向一个控制器,该控制器将负责JSON或HTML中的呈现。
下面是我们配置的简短摘录:
春季安全:
<http create-session="stateless" use-expressions="true" >
<!-- Try getting the authorization object from the request parameters. -->
<security:custom-filter ref="filter1" after="SECURITY_CONTEXT_FILTER"/>
<security:custom-filter ref="filter2" before="LOGOUT_FILTER"/>
<!-- Intercept certain URLS differently -->
<intercept-url pattern="/admin/**" access="hasRole('ROLE_ADMIN')" />
<!-- Some more stuff here -->
<intercept-url pattern="/**" access="denyAll" />
<http-basic />
</http>
的HandlerExceptionResolver
@Bean
public HandlerExceptionResolver handlerExceptionResolver(){
logger.info("creating handler exception resolver");
return new AllExceptionHandler();
}
我们的定制HandlerExceptionResolver的AppConfig的
public class AllExceptionHandler implements HandlerExceptionResolver {
private static final Logger logger = LoggerFactory
.getLogger(AppConfig.class);
@Override
public ModelAndView resolveException(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex) {
// This is just a snipped of the real method code
return new ModelAndView("errorPage");
}
我们的过滤器之一的相关部分:
try {
Authentication authResult = authenticationManger.authenticate(authRequest);
SecurityContextHolder.getContext().setAuthentication(authResult);
}
catch(AuthenticationException failed) {
SecurityContextHolder.clearContext();
throw failed;
}
的web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<context-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>xxx.xxx.xxx.config</param-value>
</context-param>
<context-param>
<param-name>spring.profiles.default</param-name>
<param-value>LIVE</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value></param-value>
</init-param>
<load-on-startup>1</load-on-startup>
<!-- Add multipart support for files up to 10 MB -->
<multipart-config>
<max-file-size>10000000</max-file-size>
</multipart-config>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<filter>
<filter-name>openEntityManagerInViewFilter</filter-name>
<filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>openEntityManagerInViewFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<!-- Map filters -->
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<error-page>
<error-code>404</error-code>
<location>/handle/404</location>
</error-page>
</web-app>
有没有人对我们如何解决这个任何指针? 我浏览了google上的很多文章,其中大多数描述了如何处理Spring安全性抛出的AccessDeniedException,因为当没有筛选器能够验证请求时。
我们使用Spring Security 3.1.0和spring web mvc 3.1.0。
感谢您的回答:只是为了确保我是否正确理解了你。你建议为我的过滤器使用类似after =“EXCEPTION_TRANSLATION_FILTER”的东西。 – David
是的。 'EXCEPTION_TRANSLATION_FILTER'之后的任何位置都很好。 –
这与自定义处理程序结合起来就可以了。谢谢! – David