SpringSecurity(二):认证
快速入门
1.引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
2.编写controller
@RestController
public class HelloController{
@GetMapping("/hello")
public String hello(){
return "hello world";
}
}
启动项目后。我们发现访问'/hello'接口,会自动跳转到'/login'界面
下面我们来看一下这个流程

用户的生成
我们先来看一下spring security默认的用户生成
Spring Security使用UserDetailsService接口向认证器传入一个User实例(org.springframework.security.core.userdetails.User,有三个参数name,password,roles),如果我们还需要用户的其它信息比如验证码之类的,我们需要自己实现一个UserDetails实现类,否则使用默认的(org.springframework.security.core.userdetails.User)即可
public class User implements UserDetails {
private String username;
private String password;
private Boolean rememberMe;
private String verifyCode;
private String power;
private Long expirationTime;
private List<String> roles;
/**
* 省略其它的 get set 方法
*/
//注意这个方法的返回类型是List<SimpleGrantedAuthority>,所以需要进行转换!
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
List<SimpleGrantedAuthority> authorities=new ArrayList<>();
for(String s:roles){
authorities.add(new SimpleGrantedAuthority(s));
}
return authorities;
}
@Override
public String getPassword() {
return password;
}
@Override
public String getUsername() {
return username;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
接下来我们看下UserDetailsService的源码
public interface UserDetailsService{
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}
loadUserByUsername有一个参数username接收用户认证时传入的用户名,开发中一般我们需要自定义实现UserDetailsService
Spring Security也为UserDetailsService提供了默认实现,InMemoryUserDetailsManager就是一种基于内存的实现。
默认情况下,Spring Security会提供一个InMemoryUserDetailsManager实例,可以通过SecurityPropertes类的getUser()方法获取到一个User实例(org.springframework.security.core.userdetails.User)
@configurationProperties(profix="spring.security") //加载配置文件,因此可以在配置文件中指定账号密码
public class SecurityProperties{
private User user=new User();
public User getUser(){
return this.user;
}
public static class User{
private String name="user";
private String password=UUID.randomUUID().toString();
private List<String> roles=new ArrayList<>();
}
}
可以看到默认账号为user,密码为一串随机的UUID。同时,默认的密码会由getOrDeducePassword方法进行加密,如果没有指定加密方法,则只是会加一个前缀{noop}表明是明文存储。
自定义从数据库获取用户
1.可以自定义一个UserDetails的实现类,也可以使用security的User类,区别在上边已经讲过了
2.自定义UserDetailsService实现类
//注意注册为bean交给容器管理
@Component
public class UserDateService implements UserDetailsService {
@Autowired
UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String phone) throws UsernameNotFoundException {
//这是通过username查询获取一组数据将获得的数据传给security的User
com.wang.pojo.User user = userMapper.getUserByPhone(phone);
//如果用户没找到,则抛出UsernameNotFoundException异常
if (user == null) {
throw new UsernameNotFoundException("该用户不存在!");
}
//把获得的账号密码传给security的User
return new User(user.getPhone(), user.getPassword(), new ArrayList<>());
}
}
3.把UserDateService注入到配置类中
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter{
//注入我们自定义的UserDateService 实例
@Autowired
UserDateService userDateService;
//注意是参数为AuthenticationManagerBuilder的configure方法
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception{
auth.userDetailsService(userDateService);
}
....
}

浙公网安备 33010602011771号