1. 概述

本文将展示如何在Spring Security项目中自定义访问被拒绝页面。这可以通过Spring Security配置或在web.xml文件中的Web应用程序配置来实现。接下来的章节将详细介绍这两种方法。

2. 自定义JSP

当用户尝试访问他们没有权限的页面时,应用会返回403状态码,表示访问被拒绝。为了用自定义页面替换默认的Spring 403状态响应页面,首先需要创建一个名为accessDenied.jsp的JSP文件:

<body>
<h2>Sorry, you do not have permission to view this page.</h2>

Click <a href="<c:url value="/homepage.html" /> ">here</a>
to go back to the Homepage.
</body>

3. Spring Security配置

默认情况下,Spring Security有一个ExceptionTranslationFilter,它处理AuthenticationExceptionAccessDeniedException类型的异常。后者通过accessDeniedHandler属性来完成,它使用AccessDeniedHandlerImpl类。

为了定制这种行为,使其使用我们之前创建的自定义页面,我们需要覆盖ExceptionTranslationFilter类的属性。这可以通过Java配置或XML配置来实现。

3.1. 访问被拒绝页面

使用Java,可以通过httpSecurity元素的accessDeniedPage()accessDeniedHandler()方法自定义403错误处理过程

让我们创建一个限制"/admin/*" URL对ADMIN角色的认证配置,并将访问被拒绝页面设置为我们刚才创建的accessDenied.jsp

@Override
protected void configure(final HttpSecurity http) throws Exception {
    http
      // ...
      .and()
      .exceptionHandling().accessDeniedPage("/accessDenied.jsp");
}

对应的XML配置如下:

<http use-expressions="true">
    <access-denied-handler error-page="/accessDenied"/>
 </http>

3.2. 访问被拒绝处理器

使用访问被拒绝处理器而不是页面的优点是可以定义在重定向到403页面之前执行的自定义逻辑。为此,我们需要创建一个实现AccessDeniedHandler接口的类,并重写handle()方法

让我们创建一个自定义的AccessDeniedHandler类,它会在每次访问被拒绝时记录一条警告消息,包含尝试访问的用户和他们试图访问的受保护URL:

public class CustomAccessDeniedHandler implements AccessDeniedHandler {

    public static final Logger LOG
      = Logger.getLogger(CustomAccessDeniedHandler.class);

    @Override
    public void handle(
      HttpServletRequest request,
      HttpServletResponse response, 
      AccessDeniedException exc) throws IOException, ServletException {
        
        Authentication auth 
          = SecurityContextHolder.getContext().getAuthentication();
        if (auth != null) {
            LOG.warn("User: " + auth.getName() 
              + " attempted to access the protected URL: "
              + request.getRequestURI());
        }

        response.sendRedirect(request.getContextPath() + "/accessDenied");
    }
}

在安全配置中,我们将定义bean并设置自定义的AccessDeniedHandler

@Bean
public AccessDeniedHandler accessDeniedHandler(){
    return new CustomAccessDeniedHandler();
}

//...
.exceptionHandling().accessDeniedHandler(accessDeniedHandler());

如果要使用XML配置上述CustomAccessDeniedHandler类,配置会有所不同:

<bean name="customAccessDeniedHandler" 
  class="com.baeldung.security.CustomAccessDeniedHandler" />

<http use-expressions="true">
    <access-denied-handler ref="customAccessDeniedHandler"/>
</http>

4. 应用程序配置

处理访问被拒绝错误可以通过Web应用程序的web.xml文件来完成,通过定义error-page标签。这个标签包含两个子标签:error-code指定要拦截的状态码,location指定了在遇到错误代码时用户将被重定向到的URL:

<error-page>
    <error-code>403</error-code>
    <location>/accessDenied</location>
</error-page>

如果应用程序没有web.xml文件,如Spring Boot的情况,Spring注解目前还没有提供与error-page标签精确对应的替代方案。根据Spring文档的建议,在这种情况下,应使用第3部分中介绍的accessDeniedPage()accessDeniedHandler()方法。

5. 总结

在这篇简短的文章中,我们详细介绍了如何使用自定义的403页面处理访问被拒绝错误的各种方式。文章的完整源代码可以在GitHub项目中找到。