如何使 UserDetailsManager 作为 bean 可用
How to make a UserDetailsManager available as a bean
我正在试验 spring-security 进行身份验证,并希望能够在运行时添加用户。我认为使用 UserDetailsManager 的干扰最小。 如何将它作为 bean 提供,以便我可以在控制器和其他对象中访问它?
我开始的代码如下:
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth, DataSource dataSource, PasswordEncoder enc) throws Exception {
auth.jdbcAuthentication().dataSource(dataSource).withDefaultSchema().passwordEncoder(enc)
.withUser("user").password(enc.encode("password")).roles("USER").and()
.withUser("admin").password(enc.encode("password")).roles("USER", "ADMIN");
}
jdbcAuthentication()
创建一个 JdbcUserDetailsManager
,一切正常。但我不知道如何在网络应用程序初始化后访问它。我尝试了两种无效的变体:
@Bean
public UserDetailsManager userDetailsManager(DataSource dataSource,PasswordEncoder enc) throws Exception {
return new JdbcUserDetailsManagerConfigurer<>().dataSource(dataSource).withDefaultSchema().passwordEncoder(enc)
.withUser("user").password(enc.encode("password")).roles("USER").and()
.withUser("admin").password(enc.encode("password")).roles("USER", "ADMIN").and()
.getUserDetailsService();
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth, UserDetailsManager userDetailsManager) throws Exception {
auth.userDetailsService(userDetailsManager);
}
填写登录表单时,我得到以下信息:
Table "USERS" not found; SQL statement:
select username,password,enabled from users where username = ? [42102-185]
所以这似乎没有正确初始化 bean。第二次尝试:
@Bean
public UserDetailsManager userDetailsManager(AuthenticationManagerBuilder auth, DataSource dataSource, PasswordEncoder enc) throws Exception {
return auth.jdbcAuthentication().dataSource(dataSource).withDefaultSchema().passwordEncoder(enc)
.withUser("user").password(enc.encode("password")).roles("USER").and()
.withUser("admin").password(enc.encode("password")).roles("USER", "ADMIN").and()
.getUserDetailsService();
}
在初始化期间,我得到:
java.lang.IllegalStateException: Cannot apply ...JdbcUserDetailsManagerConfigurer@3bd97b0d to already built object
因此在 @Bean
方法中使用生成器也不起作用。
如果我没看错,您想创建一个处理用户的 bean,我建议在 spring.xml 中声明它并使用不断添加到 bean 的函数。
尝试使用 applicationcontext,这将在主页上
ApplicationContext ac;
ac=new ClassPathXmlApplicationContext("Spring.xml");
prisontest par=(prisontest)ac.getBean("prison");
这里,applicationcontext就像一个容器,里面装着bean,prisontest是class,定义了datasource,看spring.xml,
就明白了
spring.xml 看起来像这样:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="prison" class="prisontest">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost/tgmc" />
<property name="username" value="root" />
<property name="password" value="root" />
</bean>
</beans>
引用数据源的 bean 将如下所示:
public class prisontest {
DataSource ds;
public void setDataSource(DataSource ds)
{
this.ds=ds;
}
在此处添加代码以在运行时管理用户
}
您也可以将您的其他代码放在同一个 class 中,希望这对您有所帮助。
jdbcAuthentication()
不仅仅是创建一个 JdbcUserDetailsManagerConfigurer
;最重要的是,它使用 apply()
注册配置器,以便以后可以按正确的顺序执行所有配置。
幸运的是,apply()
是public,所以我们可以自己调用它。知道了这一点,我们可以使用配置器的备用构造函数将主要配置负载移回 configureGlobal
。最终对我有用的是:
@Bean
public JdbcUserDetailsManager userDetailsManager(DataSource dataSource) {
JdbcUserDetailsManager mgr = new JdbcUserDetailsManager();
mgr.setDataSource(dataSource); // (1)
return mgr;
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth, JdbcUserDetailsManager userDetailsManager, DataSource dataSource, PasswordEncoder enc) throws Exception {
//set user detail service manually
auth.userDetailsService(userDetailsManager);
JdbcUserDetailsManagerConfigurer<AuthenticationManagerBuilder> conf =
new JdbcUserDetailsManagerConfigurer<>(userDetailsManager);
//apply the configurer
auth.apply(conf);
conf.dataSource(dataSource) // (2)
.withDefaultSchema().passwordEncoder(enc)
.withUser("user").password(enc.encode("password")).roles("USER").and()
.withUser("admin").password(enc.encode("password")).roles("USER", "ADMIN");
}
(1)和(2)中设置数据源似乎是多余的,但不设置任何一个都会导致初始化异常:
//without (1)
java.lang.IllegalArgumentException: 'dataSource' or 'jdbcTemplate' is required
//without (2)
java.lang.IllegalStateException: DataSource must be set
第一个错误是 userDetailsManager()
返回的 bean 的验证,第二个是 AuthenticationManagerBuilder 执行配置器之前的验证。
这样配置,我可以写,例如在控制器中:
@Autowired
private UserDetailsManager users;
@Autowired
private PasswordEncoder enc;
@RequestMapping(...)
public String handle(Model model) {
users.createUser(new User(username, enc.encode(password), authorities);
return "view";
}
我正在试验 spring-security 进行身份验证,并希望能够在运行时添加用户。我认为使用 UserDetailsManager 的干扰最小。 如何将它作为 bean 提供,以便我可以在控制器和其他对象中访问它?
我开始的代码如下:
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth, DataSource dataSource, PasswordEncoder enc) throws Exception {
auth.jdbcAuthentication().dataSource(dataSource).withDefaultSchema().passwordEncoder(enc)
.withUser("user").password(enc.encode("password")).roles("USER").and()
.withUser("admin").password(enc.encode("password")).roles("USER", "ADMIN");
}
jdbcAuthentication()
创建一个 JdbcUserDetailsManager
,一切正常。但我不知道如何在网络应用程序初始化后访问它。我尝试了两种无效的变体:
@Bean
public UserDetailsManager userDetailsManager(DataSource dataSource,PasswordEncoder enc) throws Exception {
return new JdbcUserDetailsManagerConfigurer<>().dataSource(dataSource).withDefaultSchema().passwordEncoder(enc)
.withUser("user").password(enc.encode("password")).roles("USER").and()
.withUser("admin").password(enc.encode("password")).roles("USER", "ADMIN").and()
.getUserDetailsService();
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth, UserDetailsManager userDetailsManager) throws Exception {
auth.userDetailsService(userDetailsManager);
}
填写登录表单时,我得到以下信息:
Table "USERS" not found; SQL statement:
select username,password,enabled from users where username = ? [42102-185]
所以这似乎没有正确初始化 bean。第二次尝试:
@Bean
public UserDetailsManager userDetailsManager(AuthenticationManagerBuilder auth, DataSource dataSource, PasswordEncoder enc) throws Exception {
return auth.jdbcAuthentication().dataSource(dataSource).withDefaultSchema().passwordEncoder(enc)
.withUser("user").password(enc.encode("password")).roles("USER").and()
.withUser("admin").password(enc.encode("password")).roles("USER", "ADMIN").and()
.getUserDetailsService();
}
在初始化期间,我得到:
java.lang.IllegalStateException: Cannot apply ...JdbcUserDetailsManagerConfigurer@3bd97b0d to already built object
因此在 @Bean
方法中使用生成器也不起作用。
如果我没看错,您想创建一个处理用户的 bean,我建议在 spring.xml 中声明它并使用不断添加到 bean 的函数。 尝试使用 applicationcontext,这将在主页上
ApplicationContext ac;
ac=new ClassPathXmlApplicationContext("Spring.xml");
prisontest par=(prisontest)ac.getBean("prison");
这里,applicationcontext就像一个容器,里面装着bean,prisontest是class,定义了datasource,看spring.xml,
就明白了spring.xml 看起来像这样:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="prison" class="prisontest">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost/tgmc" />
<property name="username" value="root" />
<property name="password" value="root" />
</bean>
</beans>
引用数据源的 bean 将如下所示:
public class prisontest {
DataSource ds;
public void setDataSource(DataSource ds)
{
this.ds=ds;
}
在此处添加代码以在运行时管理用户 }
您也可以将您的其他代码放在同一个 class 中,希望这对您有所帮助。
jdbcAuthentication()
不仅仅是创建一个 JdbcUserDetailsManagerConfigurer
;最重要的是,它使用 apply()
注册配置器,以便以后可以按正确的顺序执行所有配置。
幸运的是,apply()
是public,所以我们可以自己调用它。知道了这一点,我们可以使用配置器的备用构造函数将主要配置负载移回 configureGlobal
。最终对我有用的是:
@Bean
public JdbcUserDetailsManager userDetailsManager(DataSource dataSource) {
JdbcUserDetailsManager mgr = new JdbcUserDetailsManager();
mgr.setDataSource(dataSource); // (1)
return mgr;
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth, JdbcUserDetailsManager userDetailsManager, DataSource dataSource, PasswordEncoder enc) throws Exception {
//set user detail service manually
auth.userDetailsService(userDetailsManager);
JdbcUserDetailsManagerConfigurer<AuthenticationManagerBuilder> conf =
new JdbcUserDetailsManagerConfigurer<>(userDetailsManager);
//apply the configurer
auth.apply(conf);
conf.dataSource(dataSource) // (2)
.withDefaultSchema().passwordEncoder(enc)
.withUser("user").password(enc.encode("password")).roles("USER").and()
.withUser("admin").password(enc.encode("password")).roles("USER", "ADMIN");
}
(1)和(2)中设置数据源似乎是多余的,但不设置任何一个都会导致初始化异常:
//without (1)
java.lang.IllegalArgumentException: 'dataSource' or 'jdbcTemplate' is required
//without (2)
java.lang.IllegalStateException: DataSource must be set
第一个错误是 userDetailsManager()
返回的 bean 的验证,第二个是 AuthenticationManagerBuilder 执行配置器之前的验证。
这样配置,我可以写,例如在控制器中:
@Autowired
private UserDetailsManager users;
@Autowired
private PasswordEncoder enc;
@RequestMapping(...)
public String handle(Model model) {
users.createUser(new User(username, enc.encode(password), authorities);
return "view";
}