如何使UserDetailsManager可用作bean

时间:2015-04-04 14:24:40

标签: java spring authentication spring-security spring-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,一切正常。但我不知道如何在Web应用程序初始化后访问它。我尝试了两种不起作用的变体:

@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方法中使用构建器也不起作用。

2 个答案:

答案 0 :(得分:1)

jdbcAuthentication()不只是创建JdbcUserDetailsManagerConfigurer;最重要的是,它使用apply()注册配置器,以便以后可以按正确的顺序执行所有配置。

幸运的是,apply()是公开的,所以我们可以自己称呼它。知道了,我们可以使用configurer的备用构造函数将主配置负载移回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";
}

答案 1 :(得分:0)

如果我说得对,你想创建一个处理用户的bean,我建议在spring.xml中声明它并使用不断添加到bean的函数。  尝试使用applicationcontext,这将在主页上

ApplicationContext ac;
        ac=new ClassPathXmlApplicationContext("Spring.xml");
        prisontest par=(prisontest)ac.getBean("prison");

这里,applicationcontext就像一个容纳bean的容器,prisontest是定义数据源的类,你可以理解看到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;
        }

在此处添加代码,以便在运行时管理用户     }

您也可以将其他代码放在同一个类中,希望这会有所帮助。