Spring Security 3.1中如何处理不同的身份验证异常?

拉斯帕公司

首先,我想评论一下,我已经检查了堆栈溢出中的其他问题,并根据以下答案实施了自己的方法:https : //stackoverflow.com/a/14425801/2487263https://stackoverflow.com/a/16101649 / 2487263

我试图在Spring 3.2 Spring MVC应用程序中使用Spring Security 3.1来保护REST API,但我正在使用具有简单配置的基本身份验证方法:

<http create-session="stateless" entry-point-ref="authenticationFailedEntryPoint">
    <intercept-url pattern="/**" access="ROLE_USER"/>
    <http-basic />
</http>

如您所见,我使用的是我的自定义入口点,我有我自己的ErrorResponse对象,该对象将以json格式添加到http响应中,请参见以下代码:

    @Component
public class AuthenticationFailedEntryPoint implements AuthenticationEntryPoint {
    static Logger log = Logger.getLogger(AuthenticationFailedEntryPoint.class);

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
        log.error(ExceptionUtils.getStackTrace(authException));
        ErrorResponse errorResponse = new ErrorResponse();  

            ... here I fill my errorResponse object ...

        ObjectMapper jsonMapper = new ObjectMapper();

        response.setContentType("application/json;charset=UTF-8");
        response.setStatus(status); 

        PrintWriter out = response.getWriter();
        out.print(jsonMapper.writeValueAsString(errorResponse));   
    }
}

我用两个测试案例尝试了该方法:

  1. 尝试在不提供基本身份验证标头的情况下使用一项服务:

这是请求/响应:

GET http://localhost:8081/accounts/accounts?accountNumber=1013


 -- response --
401 Unauthorized
Server:  Apache-Coyote/1.1

Content-Type:  application/json;charset=UTF-8

Content-Length:  320

Date:  Fri, 25 Oct 2013 17:11:15 GMT

Proxy-Connection:  Keep-alive

{"status":401,"messages":[{"code":"000011","message":"You are not authorized to reach this endpoint"}]}

2.-尝试使用相同的服务,但是现在使用错误的密码发送基本身份验证标头:

这是请求/响应:

GET http://localhost:8081/accounts/accounts?accountNumber=1013
Authorization: Basic bXl1c2VyOmdvb2RieWU=


 -- response --
401 Unauthorized
Server:  Apache-Coyote/1.1

WWW-Authenticate:  Basic realm="Spring Security Application"

Content-Type:  text/html;charset=utf-8

Content-Length:  1053

Date:  Fri, 25 Oct 2013 17:03:09 GMT

Proxy-Connection:  Keep-alive

<html> ... ugly html generated by tc server ... </html>

如您所见,在第一种情况下,已到达入口点,并且以适当的异常处理方式执行了begin方法,并返回了json响应。但是,如果密码错误,则不会发生这种情况。

在日志中,我发现两种情况都产生了不同的流量:

对于情况1(无身份验证标头):

...
2013-10-25 13:11:15,830 DEBUG tomcat-http--13 org.springframework.security.web.access.intercept.FilterSecurityInterceptor - Secure object: FilterInvocation: URL: /accounts?accountNumber=1013; Attributes: [ROLE_USER]
2013-10-25 13:11:15,830 DEBUG tomcat-http--13 org.springframework.security.web.access.intercept.FilterSecurityInterceptor - Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken@9055e4a6: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@957e: RemoteIpAddress: 127.0.0.1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS
2013-10-25 13:11:15,830 DEBUG tomcat-http--13 org.springframework.security.access.vote.AffirmativeBased - Voter: org.springframework.security.access.vote.RoleVoter@11da1f99, returned: -1
2013-10-25 13:11:15,831 DEBUG tomcat-http--13 org.springframework.security.access.vote.AffirmativeBased - Voter: org.springframework.security.access.vote.AuthenticatedVoter@7507ef7, returned: 0
2013-10-25 13:11:15,831 DEBUG tomcat-http--13 org.springframework.security.web.access.ExceptionTranslationFilter - Access is denied (user is anonymous); redirecting to authentication entry point
org.springframework.security.access.AccessDeniedException: Access is denied
...

对于情况2(密码错误):

...
2013-10-25 13:03:08,941 DEBUG tomcat-http--11 org.springframework.security.web.authentication.www.BasicAuthenticationFilter - Basic Authentication Authorization header found for user 'myuser'
2013-10-25 13:03:08,941 DEBUG tomcat-http--11 org.springframework.security.authentication.ProviderManager - Authentication attempt using org.springframework.security.authentication.dao.DaoAuthenticationProvider
2013-10-25 13:03:09,544 DEBUG tomcat-http--11 org.springframework.security.authentication.dao.DaoAuthenticationProvider - Authentication failed: password does not match stored value
2013-10-25 13:03:09,545 DEBUG tomcat-http--11 org.springframework.security.web.authentication.www.BasicAuthenticationFilter - Authentication request for failed: org.springframework.security.authentication.BadCredentialsException: Bad credentials
2013-10-25 13:00:30,136 DEBUG tomcat-http--9 org.springframework.security.web.context.SecurityContextPersistenceFilter - SecurityContextHolder now cleared, as request processing completed
...

第一种情况将抛出AccessDeniedException,该异常将被捕获并发送到我的入口点中的begin方法,但是第二种情况将抛出BadCredentialsException并没有到达入口点。

奇怪的是,Begin方法应该接收AuthenticationException,但是AccessDeniedException不是AuthenticationException,而是BadCredentialsException,请参阅Spring Security 3.1 API文档中的继承树:

java.lang.Object
  extended by java.lang.Throwable
      extended by java.lang.Exception
          extended by java.lang.RuntimeException
              extended by org.springframework.security.access.AccessDeniedException

java.lang.Object
  extended by java.lang.Throwable
      extended by java.lang.Exception
          extended by java.lang.RuntimeException
              extended by org.springframework.security.core.AuthenticationException
                  extended by org.springframework.security.authentication.BadCredentialsException

为什么使用非正确类型的异常调用begin方法,并且当BadCredentialsException具有正确类型时为何不调用异常?

编辑---实现了@Luke的答案

描述的两个解决方案使用问题中显示的定制AuthenticationEntryPoint,需要选择以下两个选项之一来修改配置:

  1. 添加自定义BASIC_AUTH_FILTER:

    <http create-session="stateless" entry-point-ref="authenticationFailedEntryPoint">
        <intercept-url pattern="/**" access="ROLE_USER"/>
        <custom-filter position="BASIC_AUTH_FILTER" ref="authenticationFilter" /> 
    </http>
    
    <beans:bean id="authenticationFilter" class="org.springframework.security.web.authentication.www.BasicAuthenticationFilter">
        <beans:constructor-arg name="authenticationManager" ref="authenticationManager" />
        <beans:constructor-arg name="authenticationEntryPoint" ref="authenticationFailedEntryPoint" />
    </beans:bean>
    
  2. 或将入口点添加到http-basic元素,IMO是最干净的解决方案:

    <http create-session="stateless" entry-point-ref="authenticationFailedEntryPoint">
        <intercept-url pattern="/**" access="ROLE_USER"/>
        <http-basic entry-point-ref="authenticationFailedEntryPoint" />
    </http>
    
小羊肖恩

我认为问题在于,在基本身份验证失败之后,直接从BasicAuthenticationFilter进行对入口点的调用,默认情况下,它将是内置实现。

您还需要entry-point-refhttp-basic元素设置属性以解决此问题。

另外,您可以将基本身份验证过滤器定义为Bean,并完全避免使用名称空间。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

在Spring Security中定制身份验证

来自分类Dev

Spring Security中的链式身份验证

来自分类Dev

如何在Spring Security中撤消身份验证令牌?

来自分类Dev

如何在Spring Security中关闭Websocket的身份验证?

来自分类Dev

Spring Security预身份验证成功处理程序

来自分类Dev

Spring Security:取决于实体的不同身份验证方法

来自分类Dev

Spring Security:取决于实体的不同身份验证方法

来自分类Dev

Tomcat身份验证和Spring Security

来自分类Dev

使用UserDetailsService的Spring Security身份验证

来自分类Dev

Spring Security Rest Basic身份验证

来自分类Dev

身份验证失败的Spring Security Wildfly

来自分类Dev

Spring Security SAML扩展如何在身份验证后处理后续请求?

来自分类Dev

为什么故障处理在Spring Security X.509身份验证中不起作用?

来自分类Dev

为什么在Spring Security中对“ anonymousUser”进行身份验证?

来自分类Dev

从服务中获取Spring Security身份验证

来自分类Dev

在Spring Security中接收令牌的基本身份验证

来自分类Dev

在Spring Security中接收令牌的基本身份验证

来自分类Dev

在 Spring Security 中捕获身份验证失败

来自分类Dev

从Spring Security 3升级到Spring Security 4后是否获得异常?

来自分类Dev

从Spring Security 3升级到Spring Security 4后是否获得异常?

来自分类Dev

如何在Spring WebFlux Security中实现多种身份验证方法?

来自分类Dev

如何在Spring Security中通过email_id或contact_number进行身份验证?

来自分类Dev

Spring MVC REST + Spring Security +基本身份验证

来自分类Dev

使用Spring Security + Spring数据+ MongoDB进行身份验证

来自分类Dev

Grails Spring Security Shiro,如何创建具有 2 个不同身份验证成功 url 的 2 个登录表单?

来自分类Dev

Spring Security验证逻辑

来自分类Dev

Spring Boot + Spring Security:如何取消基本身份验证表单

来自分类Dev

如何在Flyway中使用Spring Boot / Spring Security的JDBC身份验证

来自分类Dev

Spring Security身份验证提供程序Java配置

Related 相关文章

  1. 1

    在Spring Security中定制身份验证

  2. 2

    Spring Security中的链式身份验证

  3. 3

    如何在Spring Security中撤消身份验证令牌?

  4. 4

    如何在Spring Security中关闭Websocket的身份验证?

  5. 5

    Spring Security预身份验证成功处理程序

  6. 6

    Spring Security:取决于实体的不同身份验证方法

  7. 7

    Spring Security:取决于实体的不同身份验证方法

  8. 8

    Tomcat身份验证和Spring Security

  9. 9

    使用UserDetailsService的Spring Security身份验证

  10. 10

    Spring Security Rest Basic身份验证

  11. 11

    身份验证失败的Spring Security Wildfly

  12. 12

    Spring Security SAML扩展如何在身份验证后处理后续请求?

  13. 13

    为什么故障处理在Spring Security X.509身份验证中不起作用?

  14. 14

    为什么在Spring Security中对“ anonymousUser”进行身份验证?

  15. 15

    从服务中获取Spring Security身份验证

  16. 16

    在Spring Security中接收令牌的基本身份验证

  17. 17

    在Spring Security中接收令牌的基本身份验证

  18. 18

    在 Spring Security 中捕获身份验证失败

  19. 19

    从Spring Security 3升级到Spring Security 4后是否获得异常?

  20. 20

    从Spring Security 3升级到Spring Security 4后是否获得异常?

  21. 21

    如何在Spring WebFlux Security中实现多种身份验证方法?

  22. 22

    如何在Spring Security中通过email_id或contact_number进行身份验证?

  23. 23

    Spring MVC REST + Spring Security +基本身份验证

  24. 24

    使用Spring Security + Spring数据+ MongoDB进行身份验证

  25. 25

    Grails Spring Security Shiro,如何创建具有 2 个不同身份验证成功 url 的 2 个登录表单?

  26. 26

    Spring Security验证逻辑

  27. 27

    Spring Boot + Spring Security:如何取消基本身份验证表单

  28. 28

    如何在Flyway中使用Spring Boot / Spring Security的JDBC身份验证

  29. 29

    Spring Security身份验证提供程序Java配置

热门标签

归档