如何解决如何使用WebSecurityConfigurerAdapter定义自定义UserDetailsService?
对于如何正确扩展WebSecurityConfigurerAdapter
以正确使用自定义UserDetailsService
并将其公开为bean,我有些困惑。
我的意思是:
-
userDetailsService()
:Javadoc说:允许从以下位置修改和访问
UserDetailsService
userDetailsServiceBean()
,而无需与ApplicationContext
。开发人员应在以下情况下重写此方法 更改userDetailsServiceBean()
的实例。 -
userDetailsServiceBean()
:Javadoc说:重写此方法以显示从
UserDetailsService
创建的configure(AuthenticationManagerBuilder)
作为bean。 [...] 改变 实例返回后,开发人员应进行更改 改为userDetailsService()
-
configure(AuthenticationManagerBuilder)
:Javadoc说:[...]
authenticationManagerBean()
方法可用于公开 得到的AuthenticationManager
作为Bean。的userDetailsServiceBean()
可用于显示最后填充的UserDetailsService
是使用AuthenticationManagerBuilder
作为Bean。UserDetailsService
也会自动填充到HttpSecurity#getSharedObject(Class)
与其他人一起使用SecurityContextConfigurer
(即RememberMeConfigurer)”
如果我刚刚读过这篇文章,我就会明白:
-
configure(AuthenticationManagerBuilder)
配置一个AuthenticationManager
,可以通过覆盖authenticationManagerBean()
并将其标记为@Bean
来暴露它;建立AuthenticationManager
,configure(AuthenticationManagerBuilder)
建立并连线UserDetailsService
- 覆盖
userDetailsServiceBean()
(以@Bean
标记)可以暴露通过先前方法构建和连接的UserDetailsService
- 如果我希望
configure(AuthenticationManagerBuilder)
使用自己的UserDetailsService
实现,则必须重写userDetailsService()
才能返回它;然后将通过覆盖userDetailsServiceBean()
来公开它
所以我最终得到了这个
@Override
protected void configure(final AuthenticationManagerBuilder auth)
throws Exception {
final MyUserDetailsService userDetailsService = userDetailsService();
auth.userDetailsService(userDetailsService);
// all the other configuration has been omitted
}
@Override
protected MyUserDetailsService userDetailsService() {
return new MyUserDetailsService();
}
@Bean
@Override
public UserDetailsService userDetailsServiceBean() throws Exception {
return super.userDetailsServiceBean();
}
但是,这是令我困惑和看到的东西:
-
configure(final AuthenticationManagerBuilder auth)
的默认实现基本上不执行任何操作(只需将disableLocalConfigureAuthenticationBldr
设置为true
),尤其是它不会调用userDetailsService()
;这是我的首要任务,所以是通过使用UserDetailsService
注入自定义userDetailsService()
实现的原因;换句话说,如果我不重写userDetailsService()
并直接在UserDetailsService
中创建自定义configure(final AuthenticationManagerBuilder auth)
实例,我将得到相同的结果 - 可能与上述情况有关:
userDetailsService()
的默认实现与userDetailsServiceBean()
的默认实现完全相同...我希望后者迟早会委派给前者,但是如果以前的默认实现实际上是相同的...我真的迷路了,我想知道为什么提供了两种不同的方法 - 我希望通过上述操作,我的自定义
MyUserDetailsService
实现会在应用程序上下文中公开,但是如果我尝试在其他位置注入MyUserDetailsService
实例,Springs会抱怨说没有这样的实例在我的应用程序上下文中;实际上,userDetailsServiceBean()
返回的bean总是某种委派的包装器。如果我注入一个通用的UserDetailsService
实例并尝试使用它,则会得到一个IllegalStateException
,说“ UserDetailsService是必需的”(org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter.UserDetailsServiceDelegator.loadUserByUsername(String)
中的委托机制无法检索正确的默认{{ 1}} ...) - 通过调试,我看到两次调用
UserDetailsService
(因此创建了两个userDetailsService()
的DISTINCT实例),一次是通过上述MyUserDetailsService
的实现,一次是由configure(final AuthenticationManagerBuilder auth)
的调用...
因此,以上内容显然是不正确的(身份验证有效,因为将正确的org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter.createSharedObjects()
注入到UserDetailsService
中,但是无法在应用程序上下文中公开AuthenticationManager
),我可能通过简单地用UserDetailsService
标记一个MyUserDetailsService
bean或在我的@Service
扩展中编写另一个@Bean
方法来返回我的自定义{{1 }},因此绕过WebSecurityConfigurerAdapter
和UserDetailsService
...但是我不确定这是否是实现所需结果的最佳方法(出于某种原因,应该把这两种方法放在那儿。 )
我真的认为userDetailsService()
的处理方式过于复杂...
解决方法
配置自定义UserDetailsService
的方式取决于UserDetailsService
的数量和UserDetailsService
的种类。
还记得在Spring中公开bean的方法有多种:使用工厂方法(@Configuration
)的@Bean
,使用@ComponentScan
的{{1}},XML等。 >
一个全局@Component
如果您要使用一个全局自定义UserDetailsService
,则只需公开它,请参见Spring Security Reference:
10.10.7。 UserDetailsService
UserDetailsService
由UserDetailsService
用于检索用户名,密码和其他用于使用用户名和密码进行身份验证的属性。 Spring Security提供DaoAuthenticationProvider
的内存和JDBC实现。您可以通过将自定义
UserDetailsService
公开为bean来定义自定义身份验证。例如,以下示例将假设UserDetailsService
实现CustomUserDetailsService
来自定义身份验证:仅在未填充
UserDetailsService
并且未定义AuthenticationManagerBuilder
时使用。示例66.自定义UserDetailsService Bean
AuthenticationProviderBean
@Bean
CustomUserDetailsService customUserDetailsService() {
return new CustomUserDetailsService();
}
和userDetailsService()
的默认实现返回全局userDetailsServiceBean()
。无需覆盖这些方法。
不同的UserDetailsService
如果您想对不同的UserDetailsService
使用不同的UserDetailsService
,则可以覆盖WebSecurityConfigurerAdapter#configure
:
由
WebSecurityConfigurerAdapter
的默认实现用于尝试获取authenticationManager()
。如果被覆盖,则应使用AuthenticationManager
来指定AuthenticationManagerBuilder
。
并用AuthenticationManagerBuilder#userDetailsService
添加它:
根据传入的自定义
AuthenticationManager
添加身份验证。然后返回一个UserDetailsService
以允许自定义身份验证。
DaoAuthenticationConfigurer
和userDetailsService()
的默认实现返回userDetailsServiceBean()
中的UserDetailsService
。
如果要将AuthenticationManagerBuilder
注入另一个组件,则可以覆盖UserDetailsService
。如果公开多个userDetailsServiceBean()
,则必须使用不同的bean名称。
内置UserDetailsService
由UserDetailsService
创建的一些内置UserDetailsService
不会公开。
如果在其他组件中需要这样的AuthenticationManagerBuilder
,则必须覆盖
UserDetailsService
,请参见WebSecurityConfigurerAdapter#configure
:
例如,以下配置可用于在内存身份验证中注册,以公开内存中的UserDetailsService:
userDetailsServiceBean()
如果公开多个@Override
protected void configure(AuthenticationManagerBuilder auth) {
auth
// enable in memory based authentication with a user named
// "user" and "admin"
.inMemoryAuthentication().withUser("user").password("password").roles("USER").and()
.withUser("admin").password("password").roles("USER","ADMIN");
}
// Expose the UserDetailsService as a Bean
@Bean
@Override
public UserDetailsService userDetailsServiceBean() throws Exception {
return super.userDetailsServiceBean();
}
,则必须使用不同的bean名称。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。