Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。
可以帮助进行认证和授权:
认证:就是用户登录的时候,检验用户的信息是否正确
授权:就是字面的意思,就像是每个用户又那些权限(vip1,vip2)
3.1引入依赖
org.springframework.boot
spring-boot-starter-security
3.2启动项目 ,控制台会出现登录密码。账号未user
可以通过配置文件来修改账号密码:
也可以通过配置类来修改账号密码:
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
BCryptPasswordEncoder pe = new BCryptPasswordEncoder();
String encode = pe.encode("123456");
auth.inMemoryAuthentication()
.passwordEncoder(pe)
.withUser("gjc") //设置用户名
.password(encode).roles("USER");//设置密码以及角色
}
}
如果不直接使用框架自带的html页面的话,就需要我们配置页面比如:使用jsp,或者使用thymeleaf模板引擎
登录
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// 这是配置自定义的信息
http
.formLogin().loginPage("/login.html") //配置为自定义的登录页面
.usernameParameter("myname") //设置页面form表单的用户名参数
.passwordParameter("mypwd") //设置页面form表单的密码参数
.loginProcessingUrl("/userlogin") //登录路径和前台form登录接口路径保持一致
// .defaultSuccessUrl("/")//登录成功跳转路径
.and().authorizeRequests().antMatchers("/","userlogin","/login.html").permitAll()//设置哪些路径不需要拦截
.anyRequest().authenticated()//除去不需要认证的路径的其它路径都需要认证
// .and().exceptionHandling().accessDeniedPage("")//自定义没有权限的页面
.and().csrf().disable(); //关闭csrf的保护
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
BCryptPasswordEncoder pe = new BCryptPasswordEncoder();
String encode = pe.encode("123456");
auth.inMemoryAuthentication()
.passwordEncoder(pe)
.withUser("gjc")
.password(encode).roles("USER");
}
}
如果需要根据数据库的账号密码进行登录,就需要替换掉原本的UserDetailsService,因为之前实在内存中查找账号密码,现在需要从数据库中查找。
依赖:
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-starter-security
org.projectlombok
lombok
com.baomidou
mybatis-plus-boot-starter
3.4.2
mysql
mysql-connector-java
8.0.31
com.alibaba
druid-spring-boot-starter
1.2.6
mysql连接配置:properties
spring.datasource.druid.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.druid.username=root
spring.datasource.druid.password=root
spring.datasource.druid.url=jdbc:mysql://localhost:3306/qy168?serverTimezone=Asia/Shanghai
#配置mybatis plus驼峰关闭
mybatis-plus.configuration.map-underscore-to-camel-case=false
#控制台打印sql语句日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
实体类:
@Data
@TableName("tbl_user")
public class TblUser {
@TableId(type = IdType.AUTO)
private long id;
private String username;
private String password;
private String headImg;
private String phone;
private String realname;
}
mybatis plus的mapper层和server层这里就不列举了,相信大家都会了
替换UserDetailsService,重写其中的方法,从数据库中查询用户信息
@Service
public class MyUserDetailsService implements UserDetailsService {
@Autowired
private UserService userService;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//查询用户信息
LambdaQueryWrapper query = new LambdaQueryWrapper<>();
query.eq(TblUser::getUsername,username);
TblUser tblUser = userService.getOne(query);
//如果没有查询到用户信息就抛出异常
if (Objects.isNull(tblUser)){
throw new RuntimeException("用户名或密码错误");
}
//TODO 查询对应的权限信息
//因为现在用户还没有权限模拟以下权限
// 查询用户的权限信息并将其转换为GrantedAuthority对象列表
List authorities = new ArrayList<>();
// 例如,假设用户有ROLE_USER角色
authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
//将数据封装为UserDetails对象
//因为这个User实现了UserDetails,所以我们可以使用这个User实体类
User user = new User(tblUser.getUsername(), tblUser.getPassword(), authorities);
return user;
}
}
测试:发现报错了
因为这里密码默认采用了一种PasswordEncoder密码校验的东西,如果要让密码是明文存储,需要在密码前加{noop}
真正开发肯定是不会用这种方式的,密码也不会明文存储。我们一般使用的SpringSecurity为我们提供的BCryptPasswordEncoder.
使用非常简单,只需要把BCryptPasswordEncoder注入到bean容器就行
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter{
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
}
测试:
@Test
void text(){
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
String encode = passwordEncoder.encode("123456");//对123456进行加密
String encode1 = passwordEncoder.encode("123456");//对123456进行加密
System.out.println(encode);
System.out.println(encode1);
//盐相同密文是不同的
//比较
boolean matches = passwordEncoder.matches("123456", "$2a$10$4IfzCQBjoxfmBGLg.SlnfOKwEBkuXDYBoEpU.8kUmBYF5WO.5zb42");
boolean matches1 = passwordEncoder.matches("123456", "$2a$10$FDltmVxzybG9HNx6e1jBu.NvBLHM4QD0lmZVV98igMQ4TgOCOet.e");
System.out.println(matches);
System.out.println(matches1);
}
运行结果:
那么我们只需要修改数据库的密码为加密之后的密码
再进行登录就可以了,这块在注册时就需要使用BcryptPasswordEncoder对密码加密存储到数据库中
登录:
1.需要自定义登录接口 -- 调用ProviderManager的方法进行认证 如果认证通过生成jwt -- 把用户信息存入redis中
2.自定义UserDetailsService -- 在这个实现类中查询数据库
校验:
1.定义jwt认证过滤器 -- 获取token -- 解析token获取其中的userid -- 从redis中获取用户信息 -- 存入SecurityContextHolder
依赖:在之前依赖中新增
org.springframework.boot
spring-boot-starter-data-redis
io.jsonwebtoken
jjwt
0.9.0
redis配置: