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);
}
....
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话