spring-security(十四)UserDetailsService

本文详述了Spring Security中的UserDetailsService接口及其在认证过程中的作用。它仅负责查找用户信息,不涉及认证逻辑。文章介绍了如何实现自定义的UserDetailsService,包括基于内存、属性文件和关系数据库的用户信息存储。特别是对于数据库认证,讨论了JdbcDaoImpl的使用,包括用户分组和权限管理,并展示了如何根据业务需求调整查询语句。
摘要由CSDN通过智能技术生成
前言:
作为spring security的核心类,大多数的认证方式都会用到UserDetailsService和UserDetails这两个接口,本文会详细探讨下UserDetailsService及其实现类。

1. UserDetailsService接口
在spring security中,为了方便扩展,UserDetailsService接口被设计的极其简单,只包含一个方法

UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;

根据提供的用户名,查找对应的用户信息,只是查找信息,没有和认证相关的任何逻辑,是DaoAuthenticationProvider默认使用的用户信息加在类,返回的UserDetails也是一个接口。根据具体实现的不同,做用户信息查找时即有可能是大小写敏感,也有可能不敏感,所以UserDetails中的用户名并不一定和传入的用户名一致。在一些认证方式中,即便他们并不真的使用用户名和密码,也会用到UserDetailsService类,可能仅仅是想利用UserDetails对象中的GrantedAuthority信息来做权限判断(如LDAP、X.509、CAS等,这些认证系统自身承担着验证证书是否有效的任务)。
因为UserDetailsService接口是如此简单,我们很容易实现他,来自定义我们获取用户信息的逻辑,同时spring security也为我们提供了一些基本常见的实现。
2.基于内存的认证
自定义UserDetailsService从我们喜欢的一种数据持久化引擎中(文件、数据库等)获取数据并不麻烦,但有时候我们并不需要这么复杂的实现,例如我们仅仅是做一个spring security的原型、或者是在学习spring security,你并不想花时间来搭建一个数据库,此时就可以以使用基于内存的用户信息存储,使用java config配置用户信息如下:

@Bean
public UserDetailsService userDetailsService() {
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
manager.createUser(User.withUsername("user").password("password").roles("USER").build());
manager.createUser(User.withUsername("admin").password("password").roles("ADMIN").build());
return manager;
}

这种方式还支持properties文件来配置

@Bean
public UserDetailsService userDetailsService() throws FileNotFoundException, IOException {

Properties properties = new Properties();
properties.load(getClass().getClassLoader().getResourceAsStream("users.properties"));

return new InMemoryUserDetailsManager(properties);
}

properties的文件格式如下:

username=password,grantedAuthority[,grantedAuthority][,enabled|disabled]

例如
 
jimi=jimispassword,ROLE_USER,ROLE_ADMIN,enabled
bob=bobspassword,ROLE_USER,enabled

还可以使用如下代码段来创建

@Autowired
public void auth(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("admin").password("password").authorities("ROLE_ADMIN").and()
.withUser("user").password("password").authorities("ROLE_USER");
}

3.基于关系数据库的认证
3.1 spring security也为我们提供了一个从关系型数据库获取认证信息的实现-JdbcDaoImpl,在这个类内部使用了Spring JDBC,下面是一个具体使用的配置例子

@Bean
public DruidDataSource dataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUsername("root");
dataSource.setPassword("sso");
dataSource.setName("chengf");
dataSource.setUrl("jdbc:mysql://localhost:3306/chengf?useUnicode=true&characterEncoding=UTF-8");
dataSource.setMaxActive(20);
dataSource.setInitialSize(1);
dataSource.setMaxWait(60000);
dataSource.setMinIdle(1);
dataSource.setTimeBetweenEvictionRunsMillis(60000);
dataSource.setMinEvictableIdleTimeMillis(300000);
dataSource.setValidationQuery("select 'x'");
dataSource.setPoolPreparedStatements(true);
dataSource.setMaxPoolPreparedStatementPerConnectionSize(20);
return dataSource;
}

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth, DataSource dataSource) throws Exception {
auth.jdbcAuthentication().dataSource(dataSource);
}

完整的例子请参考[url=http://fengyilin.iteye.com/blog/2410931]spring-security(四)java config-sample之jdbc [/url]
3.2 默认情况下,JdbcDaoImpl直接从数据库中获取某个特定用户对应的权限列表信息,在实际应用中我们可能会先将用户分组,再把具体的权限赋予某个分组,从而使这个组里面的用户都具有这些权限,JdbcDaoImpl也为我们提供了 分组的支持,默认情况下没有启用,如果想使用这个功能,可以通过如下设置

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth, DataSource dataSource) throws Exception {
auth.jdbcAuthentication().dataSource(dataSource).getUserDetailsService().setEnableGroups(true);;
}

如果spring 默认的schema不能满足我们的业务需求(表结构的定义、信息的完整性),我们也可以利用JdbcDaoImpl,重写其中的查询语句,如我们想重写查询用户信息的语句可以如下配置

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth, DataSource dataSource) throws Exception {
auth.jdbcAuthentication().dataSource(dataSource).getUserDetailsService().setEnableGroups(true);;
auth.jdbcAuthentication().dataSource(dataSource).usersByUsernameQuery("select username,password,email,phone,address,enabled from my_user_table where username = ? ");
}

如果默认实现和我们需求相差太大,简单修改配置已不能满足我们需求,我们可以自己实现加载用户信息的类,就是实现UserDetailsService,并把他作为bean注册到spring 中即可。


@Bean
public DruidDataSource dataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUsername("root");
dataSource.setPassword("sso");
dataSource.setName("chengf");
dataSource.setUrl("jdbc:mysql://localhost:3306/chengf?useUnicode=true&characterEncoding=UTF-8");
dataSource.setMaxActive(20);
return dataSource;
}
@Bean
public UserDetailsService userDetailsService () {
MyUserDetailsService userDetailsService = new MyUserDetailsService();
userDetailsService.setDataSource(dataSource());
return userDetailsService;
}

这样在程序启动时,配置类InitializeUserDetailsManagerConfigurer加载时,会为我们创建一个DaoAuthenticationProvider,并且使用我们定义的UserDetailsService。具体过程可参考
[url=http://fengyilin.iteye.com/blog/2410779]spring-security(二)java config加载机制-@EnableGlobalAuthentication [/url]
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值