简体   繁体   English

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

[英]Spring security with multiple authentication providers - UsernameNotFoundException

We have a spring security configuration for 2 authentication providers: One for human users, second for other webapps (via REST). 我们为2个身份验证提供程序提供了一个春季安全性配置:一个用于人类用户,第二个用于其他web应用程序(通过REST)。 See my previous question: Spring security for both web services and users 请参阅我之前的问题: Web服务和用户的Spring安全性

Now, the problem is, when a webapp sends username + pass, spring security first tries the user authentication provider, fails, and then tries the rest authentication provider. 现在的问题是,当Webapp发送用户名+密码时,Spring Security会先尝试用户身份验证提供程序,然后失败,然后再尝试其余的身份验证提供程序。

This causes a org.springframework.security.core.userdetails.UsernameNotFoundException in the log, even if the rest authentication is eventually successful. 即使其余身份验证最终成功,这也会在日志中导致org.springframework.security.core.userdetails.UsernameNotFoundException Is there a way to prevent this from happening? 有办法防止这种情况发生吗?

The configuration is: 配置为:

security.xml: security.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: 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>

Log: 日志:

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]

This stacktrace comes from your own code : UserDetailsServiceImpl line 30 此stacktrace来自您自己的代码:UserDetailsS​​erviceImpl第30行

According the Spring documentation : 根据Spring文档:

AuthenticationProviders are usually tried in order until one provides a non-null response. 通常按顺序尝试AuthenticationProvider,直到提供非空响应为止。 A non-null response indicates the provider had authority to decide on the authentication request and no further providers are tried. 非空响应表示提供者有权决定认证请求,并且不再尝试其他提供者。

So what's going on ? 发生什么了 ?

The first authenticationManager (bean : authenticationProvider) is invoked and throw a UserNameNotFoundException. 调用第一个authenticationManager(bean:authenticationProvider)并引发UserNameNotFoundException。 That's OK and expected since authentication must fail with this one and must be successful with restAnthenticationProvider . 这是可以预期的,因为身份验证必须为此失败,并且必须通过restAnthenticationProvider成功。

The stacktrace is printed by your LoggingAspect and the problem is there . stacktrace由LoggingAspect打印,并且存在问题 LoggingAspect complains about "unexpected exception" BUT this one is not unexpected. LoggingAspect抱怨“意外的异常”,但是这不是意外的。 The bean authenticationProvider is perfectly respecting the contract and throw the expected exception. Bean authenticationProvider完全遵守合同并抛出预期的异常。 So fix LoggingAspect so that it don't complains about this exception. 因此,请修复LoggingAspect,以免它抱怨此异常。

Note that : simply inverting the declaration order of the authentication provider will workaround the problem (at least for all rest request). 请注意:只需反转身份验证提供程序的声明顺序即可解决该问题(至少对于所有其余请求而言)。 The drawback of this quick workaround is that there are good chance that you will get an equivalent exception for all human authentication request since all of them will first fail against restAuthenticationProvider. 这种快速解决方法的缺点是,您很有可能会为所有人工身份验证请求获得同等的异常,因为所有这些首先都会针对restAuthenticationProvider失败。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Spring Security-多个身份验证提供者 - Spring Security - multiple authentication-providers Spring安全 - 使用多个身份验证提供程序进行身份验证 - Spring security - remember-me authentication with multiple authentication providers Spring 与多个提供商的安全性 - Spring security with multiple providers 了解Spring Security中的身份验证提供程序 - Understanding authentication providers in Spring security 如何处理 UsernameNotFoundException spring security - How to handle UsernameNotFoundException spring security Spring Security-如何使用Java Config配置多个身份验证提供程序 - Spring security - How to configure multiple authentication providers using java config 多个身份验证提供程序:/ j_spring_security_check和社交登录 - Multiple authentication providers: /j_spring_security_check and social login Spring Boot / Spring Security根据路径在多个身份验证提供程序之间进行选择 - Spring Boot/Spring Security Choose Between Multiple Authentication Providers Based On Path UsernameNotFoundException:Spring Boot + Spring Security中的登录表单不起作用 - UsernameNotFoundException: Login form in Spring Boot + Spring Security doesn't work spring安全过滤器应该直接调用身份验证提 - Should spring security filters call authentication providers directly?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM