用户登录时,系统会根据用户名,从存储设备查找该用户的密码及权限等,将其组装成一个UserDetails对象。并用UserDetails中的数据对用户进行认证,决定其输入的用户名/密码是否正确。
从内存认证
- 之前两篇我使用的是预置的user用户,以下则自定义一个user用户,密码123,权限是auth。user用户登录时会根据这些信息自动构建一个UserDetails,保存在内存中。
- passwordEncoder:这里设置密码不加密,5.0以后必须配置这一项,否则报错,具体以后再讲。
@SpringBootConfiguration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()//用户详细存储在内存
.withUser("user").password("123").authorities("auth")//创建一个用户
.and()
.passwordEncoder(NoOpPasswordEncoder.getInstance());//不加密
从数据库认证
@Autowired
DataSource dataSource;
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication().dataSource(dataSource)//使用jdbc默认sql
.passwordEncoder(NoOpPasswordEncoder.getInstance());
此时用户登录,会从数据库读取相关用户/密码/权限等信息,默认会执行系统内置的两条sql,如下
自定义sql
内置的sql不一定能和我们的数据库匹配,以下方式可自定义sql,这两条sql就是上面系统默认的,
@Autowired
DataSource dataSource;
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication().dataSource(dataSource)
.usersByUsernameQuery("select username,password,enabled from users where username = ?")
.authoritiesByUsernameQuery("select username,authority from authorities where username = ?")
.passwordEncoder(NoOpPasswordEncoder.getInstance());
- usersByUsernameQuery:根据登录时输入的用户名查询用户名/密码,enabled是用户激活状态true/false。
- authoritiesByUsernameQuery:查询用户名/权限,可以查出多条结果,表示用户有多个权限。具体sql怎么写要看你的数据库结构,只要关键字段名能够对应上就行了。之后系统就会根据查询结果集自动构建UserDetails。
UserDetails源码
包含用户名、密码、权限以及四个状态,状态默认为true,其中任何一个为false,都将导致登录失败。
public interface UserDetails extends Serializable {
Collection<? extends GrantedAuthority> getAuthorities();//权限
String getPassword(); //密码
String getUsername(); //用户名
boolean isAccountNonExpired(); //账号是否未过期
boolean isAccountNonLocked(); //账号是否未锁定
boolean isCredentialsNonExpired();//密码是否未过期
boolean isEnabled(); //是否激活
自定义UserDetails
可以从任意数据库,甚至缓存等,自由构建UserDetails,需要编写自己的UserDetailsService。
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService())//自定义构建
.passwordEncoder(NoOpPasswordEncoder.getInstance());
}
@Bean
public UserDetailsService userDetailsService(){
return new UserDetailsService() {
//username是用户登录时填的用户名
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//根据username查询密码,现假设是user登录,从任意数据库查到密码是123
String password = "123";
//如果查不到用户名,这里可以抛出UsernameNotFoundException异常
//根据username查询权限,这里假设从任意位置查到权限是auth
List<GrantedAuthority> authorities= new ArrayList<GrantedAuthority>();
authorities.add(new SimpleGrantedAuthority("auth"));
//User是系统自带的UserDetails实现类,4个状态其中一个为false就会抛异常
return new User(username, password, true, true, true, true, authorities);
}
};
}