如何使用 Spring Security 3.0.x 处理 HTTP 403

Posted

技术标签:

【中文标题】如何使用 Spring Security 3.0.x 处理 HTTP 403【英文标题】:How to handle HTTP 403 with Spring Security 3.0.x 【发布时间】:2011-05-10 08:36:03 【问题描述】:

我在使用 Spring Security 3.0.x(目前尤其是 3.0.2)时遇到了一点问题。我正在处理的整个应用程序运行良好,除非有人没有权限尝试登录。

当它发生时,用户被重定向到“欢迎”页面,因为他的用户名/密码是有效的,他会收到一个可爱的白色页面:“错误 403:访问被拒绝”

所以,我一直在网上寻找如何处理这种行为。到目前为止,我已经得出结论,如果我错了,请纠正我,它是由ExceptionTranslationFilter 管理的。但我不太明白如何充分利用这些信息。

我已尝试编辑我的 SecurityContext.xml 以将 access-denied-handler 标记添加到我的 http 标记,但它不起作用。我是否需要添加更多的标签才能使其工作?是否还有其他可能使我的应用程序更加用户友好?

编辑:我想重定向到一个页面,比如 403.html

此致, 谢谢

【问题讨论】:

期望的行为是什么? 你是如何使用标签的?你使用这样的东西吗?: 在你的控制器中你有一个 controllerUrl 返回到 403.html 的视图 我是这样用的: 【参考方案1】:

我仍然不明白为什么你必须实现自己的访问处理程序...我目前面临同样的任务:

 <security:access-denied-handler error-page="/accessDenied"/> - works like charm.

不要忘记在控制器中指定处理程序:

 @RequestMapping(value = "/accessDenied")
      public String accessDenied() 

            return "accessDenied"; // logical view name
       

Spring Boot 更新(2014 年 10 月):

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter 

    @Override
    protected void configure(HttpSecurity http) throws Exception 
        http.exceptionHandling().accessDeniedHandler(customHandler) OR .accessDeniedPage("/somePage.html").and
            .formLogin()
                .failureHandler(ajaxAuthenticationFailureHandler) 

现在我们并没有真正返回此类任务的视图,因为 Angular js 开始发挥作用,因此您可以使用失败/成功处理程序并返回定制的 JSON 响应。对我们来说,使用故障处理程序就足够了,但您可以选择您希望控制启动的位置。我们通常不使用视图解析器,因为有 UI 瓦片框架(例如角度部分)能够将片段构建到单个页面中为你。 Html 片段存储在服务器上,仅作为静态资源提供。

让我们使用 Embedded Tomcat 来实现与 web.xml 类似的行为!

@Configuration
@EnableAutoConfiguration
public class ApplicationWebXml extends SpringBootServletInitializer 

private static final Logger LOGGER = LoggerFactory.getLogger(Application.class);

@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) 
    return application.profiles(addDefaultProfile())
            .showBanner(false)
            .sources(Application.class);


//required for container customizer to work, the numerous tutorials didn't work for me, so I simply tried overriding the default one
@Bean
public EmbeddedServletContainerFactory servletContainer() 
    TomcatEmbeddedServletContainerFactory tomcat = new TomcatEmbeddedServletContainerFactory();
    return tomcat;


@Bean
public EmbeddedServletContainerCustomizer containerCustomizer(

) 
    return new EmbeddedServletContainerCustomizer() 
        @Override
        public void customize(ConfigurableEmbeddedServletContainer container) 
            TomcatEmbeddedServletContainerFactory containerFactory = (TomcatEmbeddedServletContainerFactory) container;
             containerFactory.setSessionTimeout(1); // just for your interest, remove as necessary

            containerFactory.addErrorPages(new ErrorPage(HttpStatus.FORBIDDEN,"/views/accessDenied.html"),
                    new ErrorPage(HttpStatus.NOT_FOUND,"/views/notFound.html"));
            containerFactory.addConnectorCustomizers(new TomcatConnectorCustomizer() 
                @Override
                public void customize(Connector connector) 
                    connector.setPort(8082);// just for your interest, remove as necessary
                
            );
        
    ;

【讨论】:

这是最好的解决方案,因为在web.xml 中定义错误页面不会让用户访问 JSP 视图中的 spring 安全标签,例如导致看似缺少内容(即菜单、用户名等)的模板页面...)。【参考方案2】:

我已经找到了如何做到这一点。通过实现AccessDeniedHandler 接口和相应的handle 方法,我可以轻松控制Http 403 错误的处理方式。

这样,你可以在会话中添加各种项目,然后在你的jsp上拦截它们。

xml 文件如下所示:

<sec:http>
    <!-- lots of urls here -->
    <sec:access-denied-handler ref="accessDeniedHandler" />
    <sec:anonymous/>
</sec:http>

<bean id="accessDeniedHandler" class="foo.bar.CustomAccessDeniedHandler">
    <property name="accessDeniedUrl" value="403.html" />
</bean>

java类:

package foo.bar;
public class CustomAccessDeniedHandler implements org.springframework.security.web.access.AccessDeniedHandler 
private String accessDeniedUrl;

    public CustomAccessDeniedHandler() 
    

    public CustomAccessDeniedHandler(String accessDeniedUrl) 
        this.accessDeniedUrl = accessDeniedUrl;
    

    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException 
        response.sendRedirect(accessDeniedUrl);
        request.getSession().setAttribute("CustomSessionAttribute", "value here");
    

    public String getAccessDeniedUrl() 
        return accessDeniedUrl;
    

    public void setAccessDeniedUrl(String accessDeniedUrl) 
        this.accessDeniedUrl = accessDeniedUrl;
    

还有一个jsp例子:

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
 <c:if test="$!empty CustomSessionAttribute">
    <br/>
    ACCESS IS DENIED
    <br/>
 </c:if>
<!-- other stuff down here -->

【讨论】:

您不需要实现自定义处理程序 为什么投反对票?我并不是说这是唯一的方法,而是说这是一种行之有效的方法。另请记住,这与 Spring Security 3.0.2 有关,并且这个问题已有 2 年历史。事情现在可能已经改变了。 当我找到这个页面(正在寻找 403 拦截)时,您的答案和其他答案的评分相同,但您的答案被标记为正确答案。正如您所说,这个问题已有 2 年历史,但寻找解决方案的人会更喜欢其他答案。这并不意味着你的不好。【参考方案3】:

您已经检查了应用程序中的标签,对我来说它似乎可以工作。

<sec:access-denied-handler error-page="/handle403Url" />

我想调用handle403Url来处理这个错误(例如显示一个错误)。

不要忘记您必须在过滤器中允许此 url,以便此用户权限可以访问它,因此在过滤器开始时您必须添加如下内容:

<sec:intercept-url pattern="/handle403Url" filters="none" />

【讨论】:

【参考方案4】:

处理错误重定向的一种更简洁的方法是在 web.xml 中使用 &lt;error-page&gt;&lt;error-code&gt; 标记。请参阅下面的示例:

<!-- Custom 403 Error Page -->
<!--
            NOTE: Security will throw this error when a user has been authenticated successfully
            but lacks the permissions to perform the requested action.
    -->
    <error-page>
        <error-code>403</error-code>
        <location>/403.jsp</location>
    </error-page>

此代码块在遇到指定错误代码时会重定向到指定位置。

这消除了应用程序逻辑中对授权代码的需求。

【讨论】:

这会起作用,尽管您将无法访问 Authentication 对象,因此将无法访问正在使用的任何 http://www.springframework.org/security/tags 标签,从而导致这些标签中的所有内容都不会出现。 这完全正确,您为未来的读者指出这一点是件好事。最佳策略完全取决于人们希望他们的应用程序如何处理身份验证错误。如果您想在有人无法进行身份验证时对信息进行某种处理,那么由于您所说的这一点,该解决方案确实无法工作。如果您只想将用户发送到一个千篇一律的拒绝访问页面,那么我喜欢使用此解决方案,因为它不会与我的其余应用程序代码混在一起。 @KristenD。能否请您说明,错误页面 facelet 的 location 应该如何设置?我的页面没有被重定向。这是webapp 文件夹中的相对路径吗?在您的情况下,错误页面是否直接放在该文件夹中?非常感谢!【参考方案5】:

完成这项工作的方法是在您的入口点中定义一个处理程序:

public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint 
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, org.springframework.security.core.AuthenticationException authException) throws IOException, ServletException 

        if (authException != null) 
            // you can check for the spefic exception here and redirect like this
            response.sendRedirect("403.html");
        
    

您可以通过将其设置为 xml 配置文件中的入口点来将其定义为入口点:

<http entry-point-ref="customAuthenticationEntryPoint">

  ...

</http>

【讨论】:

以上是关于如何使用 Spring Security 3.0.x 处理 HTTP 403的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Spring Security 获取当前用户的角色

使用 Spring Security 3.0.5 覆盖 ChannelProcessingFilter 不起作用

如何在 JSF 中使用 Spring Security Facelets 标签库

使用 Spring Security 3.0.2 进行 OpenId 身份验证和自动注册

Spring security 3.0.3 配置错误

Spring Security 3.0.5 自定义过滤器问题