覆盖 spring-security BadCredentialsException 的容器响应

Posted

技术标签:

【中文标题】覆盖 spring-security BadCredentialsException 的容器响应【英文标题】:Overriding container response for spring-security BadCredentialsException 【发布时间】:2013-10-06 18:44:52 【问题描述】:

我有一个简单的 REST 应用程序,它需要一些使用 HTTP 基本身份验证保护的资源。我不想看到容器生成的 html 以响应此应用程序的客户端可能执行的任何操作。所以我已经像这样设置了我的 SpringSecurity:

<http pattern="/api/**" auto-config="true" create-session="stateless" entry-point-ref="entryPoint">
    <intercept-url pattern="/**" method="PUT" access="ROLE_ADMIN" />
    <intercept-url pattern="/**" method="POST" access="ROLE_ADMIN" />
    <intercept-url pattern="/**" method="DELETE" access="ROLE_ADMIN" />
    <http-basic />
</http>

<http security="none" />

<authentication-manager>
    <authentication-provider>
        <user-service id="userDetailsService" 
            properties="classpath:META-INF/spring/users.properties"/>
    </authentication-provider>
</authentication-manager>

我的 EntryPoint 类如下所示:

public class BasicJsonEntryPoint extends BasicAuthenticationEntryPoint 

    @Override
    public void commence(
        HttpServletRequest request, 
        HttpServletResponse response, 
        AuthenticationException authException
    ) throws IOException, ServletException 

        response.addHeader("WWW-Authenticate", "Basic realm=\"" + getRealmName() + "\"");
        response.setStatus(SC_UNAUTHORIZED);
        PrintWriter writer = response.getWriter();
        writer.println("\"status\":" + SC_UNAUTHORIZED + ", \"message\":\"" + authException.getMessage() + "\"");

    

当我遇到受保护的资源/方法组合并得到类似以下内容时,此方法有效;

HTTP/1.1 401 Unauthorized
Server: Apache-Coyote/1.1
WWW-Authenticate: Basic realm="Admin"
Content-Length: 84
Date: Sun, 29 Sep 2013 11:50:48 GMT

"status":401, "message":"Full authentication is required to access this resource"

.. 这正是我想要的。但是,如果我在 Authorize: HTTP 标头中提供无效凭据,我会得到 Tomcat 的 HTML 响应...

HTTP/1.1 401 Unauthorized
Server: Apache-Coyote/1.1
WWW-Authenticate: Basic realm="Admin"
Content-Type: text/html;charset=utf-8
Content-Length: 1019
Date: Sun, 29 Sep 2013 11:51:14 GMT

<html><head><title>Apache Tomcat/7.0.33 - Error report</title><style><!--H1 font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22px; H2 font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:16px; H3 font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:14px; BODY font-family:Tahoma,Arial,sans-serif;color:black;background-color:white; B font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76; P font-family:Tahoma,Arial,sans-serif;background:white;color:black;font-size:12px;A color : black;A.name color : black;HR color : #525D76;--></style> </head><body><h1>HTTP Status 401 - Invalid basic authentication token</h1><HR size="1" noshade="noshade"><p><b>type</b> Status report</p><p><b>message</b> <u>Invalid basic authentication token</u></p><p><b>description</b> <u>This request requires HTTP authentication.</u></p><HR size="1" noshade="noshade"><h3>Apache Tomcat/7.0.33</h3></body></html>

为了在此处获得相同的 JSON 响应(理想情况下使用我已经创建的相同类),我还必须覆盖/实现什么?

非常感谢,

【问题讨论】:

【参考方案1】:

问题出在BasicAuthenticationFilter,它使用的是自己的BasicAuthenticationEntryPoint 实例,而不是您的实现。所以你可以稍微调整一下:

<http auto-config="true" create-session="stateless">
    <intercept-url .../>
    <http-basic />
    <custom-filter ref="basicAuthenticationFilter" before="BASIC_AUTH_FILTER" />
</http>

<beans:bean id="basicAuthenticationFilter"
      class="org.springframework.security.web.authentication.www.BasicAuthenticationFilter">
    <beans:property name="authenticationManager" ref="authenticationManager" />
    <beans:property name="authenticationEntryPoint" ref="entryPoint" />
</beans:bean>

<beans:bean id="entryPoint" class="mypackage.BasicJsonEntryPoint">
    <beans:property name="realmName" value="realm"/>
</beans:bean>

<authentication-manager alias="authenticationManager">
    <authentication-provider>
        ...
    </authentication-provider>
</authentication-manager>

【讨论】:

谢谢!我发现我也需要在 元素上保留 [ entry-point-ref="en​​tryPoint" ],以便没有凭据的原始请求仍然有效。

以上是关于覆盖 spring-security BadCredentialsException 的容器响应的主要内容,如果未能解决你的问题,请参考以下文章

在同一场战争中防止春季会话覆盖

如何覆盖 Google API 请求权限页面中的 grant_heading

Spring-Security

Spring-Security:升级到 Spring-Security 4.1 后,用户名发送为空以进行登录

在使用 Oauth、SAML 和 spring-security 的多租户的情况下从 spring-security.xml 中获取错误

Spring-security - 无法访问 ServletException