java - 具有多个身份验证提供程序的 Spring 安全性 - UsernameNotFoundException

标签 java spring rest spring-mvc spring-security

我们有一个用于 2 个身份验证提供程序的 spring 安全配置:一个用于人类用户,第二个用于其他网络应用程序(通过 REST)。请参阅我之前的问题:Spring security for both web services and users

现在,问题是,当 webapp 发送用户名 + pass 时,spring security 首先尝试用户身份验证提供程序,失败,然后尝试其余身份验证提供程序。

这会导致日志中出现 org.springframework.security.core.userdetails.UsernameNotFoundException,即使其余身份验证最终成功。有什么办法可以防止这种情况发生吗?

配置是:

安全.xml:

<security:http use-expressions="true">
    <security:intercept-url pattern="/user/login"
        access="permitAll" />
             ...
    <security:intercept-url pattern="/**"
        access="isAuthenticated()" />

    <security:form-login
        authentication-success-handler-ref="userAuthenticationSuccessHandler" />

    <security:logout logout-url="/user/logout"
        logout-success-url="/demo/user/logoutSuccess" />
</security:http>

<bean id="bCryptPasswordEncoder"
    class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" />

<security:authentication-manager alias="authenticationManager">
    <security:authentication-provider
        ref="authenticationProvider">
    </security:authentication-provider>
    <security:authentication-provider
        ref="restAuthenticationProvider">
    </security:authentication-provider>
</security:authentication-manager>

rest-security.xml:

<security:http create-session="stateless"
    entry-point-ref="digestEntryPoint" pattern="/provider/**"
    use-expressions="true">
    <security:intercept-url pattern="/provider/**"
        access="isAuthenticated()" />

    <security:http-basic />
    <security:custom-filter ref="digestFilter"
        after="BASIC_AUTH_FILTER" />
</security:http>

<bean id="digestFilter"
    class="org.springframework.security.web.authentication.www.DigestAuthenticationFilter">
    <property name="userDetailsService" ref="webappDetailsServiceImpl" />
    <property name="authenticationEntryPoint" ref="digestEntryPoint" />
</bean>

<bean id="digestEntryPoint"
    class="org.springframework.security.web.authentication.www.DigestAuthenticationEntryPoint">
    <property name="realmName" value="Contacts Realm via Digest Authentication" />
    <property name="key" value="acegi" />
</bean>

日志:

22 Jun 2014 10:43:46 ERROR LoggingAspect - Unhandled exception caught: ...UserDetailsServiceImpl    loadUserByUsername
org.springframework.security.core.userdetails.UsernameNotFoundException: User with loginName: *** doesnt exist
at ...UserDetailsServiceImpl.loadUserByUsername(UserDetailsServiceImpl.java:30)
at org.springframework.security.authentication.dao.DaoAuthenticationProvider.retrieveUser(DaoAuthenticationProvider.java:102)
at org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.authenticate(AbstractUserDetailsAuthenticationProvider.java:132)
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:156)
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:177)
at org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilter(BasicAuthenticationFilter.java:168)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:344)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:261)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:409)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1044)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:607)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:313)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
22 Jun 2014 10:43:47  INFO LoggingAspect - Entering: ...WebappDetailsServiceImpl    Method name: loadUserByUsername Method arguments : [1]

最佳答案

此堆栈跟踪来自您自己的代码:UserDetailsS​​erviceImpl 第 30 行

根据 Spring 文档:

AuthenticationProviders are usually tried in order until one provides a non-null response. A non-null response indicates the provider had authority to decide on the authentication request and no further providers are tried.

这是怎么回事?

第一个 authenticationManager(bean:authenticationProvider)被调用并抛出 UserNameNotFoundException。这没关系并且在意料之中,因为身份验证必须通过此验证失败,并且必须通过 restAnthenticationProvider 成功。

堆栈跟踪由您的 LoggingAspect 打印,问题就在那里。 LoggingAspect 提示“意外异常”,但这并不意外。 bean authenticationProvider 完全遵守契约(Contract)并抛出预期的异常。因此,请修复 LoggingAspect,使其不会提示此异常。

请注意:只需反转身份验证提供程序的声明顺序即可解决该问题(至少对于所有其余请求而言)。这种快速解决方法的缺点是,对于所有人工身份验证请求,您很有可能会得到等效的异常,因为所有这些请求都会首先因 restAuthenticationProvider 而失败。

关于java - 具有多个身份验证提供程序的 Spring 安全性 - UsernameNotFoundException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24349219/

相关文章:

rest - HTTP 2.0 与 HTTP 1.1 在服务器到服务器通信上的连接池

java - 无法安装Weblogic服务器12C,jar文件甚至无法打开

java - 在 Pi 3 B+ 上使用 Processing Pi 的 GLSL 着色器

java - 可以访问 findAll 规范方法的自定义存储库

java - Spring boot + hikari - dataSource 或 dataSourceClassName 或 jdbcUrl 是必需的问题

Spring Boot Rest WebService,如何改进干净的代码?

java - Jaxb:在同一个包中使用多个命名空间解码 xml

java - 如何在黑莓中导入 Java 插件中的项目

hibernate - 如何在集成测试中使用 Propagation.REQUIRES_NEW 回滚嵌套事务

json - 更正有关 json 正文中缺少或无效字段的 http 错误