简介
上一步已经完成登录,使用security默认提供的用户名和密码登录,这一章我们实现自定义用户名和密码登录。
处理用户信息获取逻辑
security默认处理用户信息获取逻辑,要想实现自己的逻辑那就要新建自己的逻辑类然后去实现security默认逻辑
org.springframework.security.core.userdetails.UserDetailsService
在browser项目新建MyUserDetailsService类去实现UserDetailsService重写loadUserByUsername方法
package com.spring.security;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
public class MyUserDetailsService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
return null;
}
}
我们先打开返回值UserDatails源码看看里面有什么方法
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.springframework.security.core.userdetails;
import java.io.Serializable;
import java.util.Collection;
import org.springframework.security.core.GrantedAuthority;
public interface UserDetails extends Serializable {
Collection<? extends GrantedAuthority> getAuthorities();
String getPassword();
String getUsername();
boolean isAccountNonExpired();
boolean isAccountNonLocked();
boolean isCredentialsNonExpired();
boolean isEnabled();
}
- getAuthorities() #权限信息
- getPassword() #密码
- getUsername() #用户名
- isAccountNonExpired() #你的账户是否过期 返回true没有过期 返回false已过期
- isAccountNonLocked() #你的账号是否锁定 返回true没有被锁定 返回false已经被锁定 用户可以申请恢复
- isCredentialsNonExpired() #你的密码是否过期 返回true没有过期 返回false已过期
- isEnabled() #你的账号是否被删除 返回true未删除 返回false已删除 一般数据库伪删除不能用户不能申请恢复
修改loadUserByUsername方法去定义自己的用户名和密码:
security提供的两种User构造方法:
返回:用户名,密码,用户权限资料。账号是否被删除,账户是否过期,密码是否过期,账号是否锁定默认都是true
public User(String username, String password, Collection<? extends GrantedAuthority> authorities)
返回:用户名,密码,账号是否被删除,账户是否过期,密码是否过期,账号是否锁定,用户权限资料
public User(String username, String password, boolean enabled, boolean accountNonExpired, boolean credentialsNonExpired, boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities)
直接测试下面这个返回值的方法:
package com.spring.security;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
@Component
public class MyUserDetailsService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
System.out.println("登录用户名:" + username);
//这里可以通过用户名去数据库查用户的密码和账号状态,权限。
//先写死
return new User(username,"123456",true,true,true,false, AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));
}
}
启动项目测试,不管密码是否正确都会提示账号已被锁定。

修改accountNonLocked为true再重启项目:
启动以后输入用户名和密码点登陆发现报异常,这个异常是spring security5+后密码策略变更了。必须使用 PasswordEncoder 方式也就是你存储密码的时候
需要使用{noop}123456这样的方式,这个在官网文档中有讲到。由于我们没有使用加密策略等等我们解决这个问题。
java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null"
修改passaword值为{noop}123456,再启动项目:
错误密码:

正确密码:

处理密码加密解密
创建BrowserSecurityConfig类去继承WebSecurityConfigurerAdapter类
package com.spring.security;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
在UserDetailsService中我们模拟存入数据库中的密码就是加密后的字符串
package com.spring.security;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
@Component
public class MyUserDetailsService implements UserDetailsService {
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
System.out.println("登录用户名:" + username);
//这里可以通过用户名去数据库查用户的密码和账号状态,权限。
//这一步应该是放在注册那一步然后从数据库取密码,这里我们是模拟加密
String password = passwordEncoder.encode("123456");
return new User(username, password, true, true, true, true, AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));
}
}
框架会把提交的密码使用我们定义的passwordEncode加密后调用
org.springframework.security.crypto.password.PasswordEncoder#matches方法,与返回的User中的密码进行比对。配对正常就验证通过;
启动项目测试:


来源:oschina
链接:https://my.oschina.net/u/1046143/blog/3182927