1.框架概述
Spring 是一个非常流行和成功的java应用开发框架。
Spring Security 基于Spring 框架,提供了一套web应用安全性的完整解决方案。
一般来说,Web 应用的安全性包括两部分:
-
用户认证(Authentication)
用户认证指的是验证某个用户是否为系统中的合法主体,也就是说用户能否访问该系统。用户认证一般要求用户提供用户名和密码。系统通过校验用户名和密码来完成认证过程。
-
用户授权(Authorization)
用户授权指的是验证某个用户是否有权限执行某个操作。在一个系统中,不同用户所具有的权限是不同的。比如对一个文件来说,有的用户只能进行读取,而有的用户可以进行修改。一般来说,系统会为不同的用户分配不同的角色,而每个角色则对应一系列的权限。
对于上面提到的两种应用情景,Spring Security 框架都有很好的支持。
在用户认证方面,Spring Security 框架支持主流的认证方式,包括 HTTP 基本认证、HTTP 表单验证、HTTP 摘要认证、OpenID 和 LDAP 等。
在用户授权方面,Spring Security 提供了基于角色的访问控制和访问控制列表(Access Control List,ACL),可以对应用中的领域对象进行细粒度的控制。
2.入门案例
-
引入相关的依赖,springboot的启动器,因为引入了启动器,所以好多东西springboot都已经给我们配置好了
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
-
编写一个controller尝试访问
@RestController @RequestMapping("/test") public class TestController { @GetMapping("hello") public String helloSecurity(){ return "hello security"; } }
浏览器访问之后出现的并不是页面上输出对应的内容,而是跳出来一个页面需要我们进行登录
我们不难知道这就是我们引入security的结果,我们通过产看控制台可以发现控制台上已经默认生成了一个加密之后的密码
默认的账号是:username。尝试登录
登录成功之后返回了我们想要的内容,这样我们就完成了一个security的快速入门
3.基本原理
3.1过滤链
Spring Security 的核心主要是一系列的过滤器链。
Spring Security的过滤链
本质上是一连串的Filter, 然后又以一个独立的Filter的形式插入到Filter Chain里,其名为FilterChainProxy。
实际上FilterChainProxy下面可以有多条Filter Chain,来针对不同的URL做验证,而Filter Chain中所拥有的Filter则会根据定义的服务自动增减。所以无需要显示再定义这些Filter,除非想要实现自己的逻辑。
- 绿色部分:
代表过滤器,每个方块都代表一个过滤器。- UsernamePasswordAuthenticationFilter用来处理表单登录的。检查当前的请求是不是一个登录请求,然后再这个请求里面带没带用户名和密码,如果带了用户名和密码,这个过滤器就会用用户名和密码尝试去登录,如果这个请求里面没有带用户名和密码,继续进行下面的过滤器。
- BasicAuthenticationFilter用来处理HTTPBasic登录的。检查请求的请求头中是不是有Basic开头的authentication的信息,如果有的话,会尝试拿出来做basic流的字节码然后从中取出用户名和密码尝试做登录。
springsecurity还提供了许多其他的认证方式,任何一个过滤器,成功的完成用户登录以后,都会再这个请求上做个标记,表明这个用户已经认证成功了。
- 蓝色部分:
在Exception Translation Filter中,捕获橙色部分FilterSecurity Interceptor抛出的异常,会根据抛出的异常,会做相应的处理。 - 橙色部分:
请求经历过这些过滤器后,就会到达这个写橘黄色的拦截器上比如FilterSecurity Interceptor,这个拦截器是整个Spring Security过滤器的最后一环,是最终的守门人,在它身后是我们自己写的controller的rest服务,在该拦截器中,它会去决定当前的请求能不能去访问后面真正的服务。如果验证不通过,则会往前抛出异常。
绿色的部分可以通过配置来设置是否生效,除了绿色之外的过滤器,是不能通过配置来控制的,而且位置也不能更改,不能移除到过滤器链外的。
3.2两个重要的接口
-
UserDetail接口
当用户什么都没有进行配置的时候我们可以看到,系统默认给我们生成了一个密码,但是在实际开发中密码和用户名都应该是我们自己进行配置的,所以就出现了这个接口
里面定义了一系列的变量,以后我们就继承这个接口对应的实现类(user)将对应的值设置进去就可以实现自定义密码和username了
-
PasswordEncoder接口
PasswordEncoder 接口是用来加密的,这个接口提供了三个方法:
String encode(CharSequence var1);
加密方法,返回加密后的密码。
boolean matches(CharSequence var1, String var2);
密码验证,返回密码是否一致。第一个参数是明文密码,第二个参数是加密后的密码(数据库取)default boolean upgradeEncoding(String encodedPassword) { return false; } }
表示如果解析的密码能够再次进行解析且达到更安全的结果则返回true,否则返回false,默认返回false。
PasswordEncoder 是一个接口,而Security中我们要使用这个接口的实现类BCryptPasswordEncoder来实现密码加密和验证操作
官方推荐我们使用的是
BCryptPasswordEncoder
进行密码加密和密码验证的流程:
1.注册用户时,使用encode方法,即SHA-256+随机盐+密钥把用户输入的密码进行hash处理,得到密码的hash值,然后将其存入数据库中。2.用户登录时,使用matches方法进行验证。注册的密码并不会进行密码解密(因为密码经过Hash处理,是不可逆的),而是使用相同的算法把用户输入的密码进行hash处理,得到密码的hash值,然后将其与从数据库中查询到的密码hash值进行比较。如果两者相同,说明用户输入的密码正确。
使用BCryptPasswordEncoder实现密码加密和验证:
1.自定义声明BCryptPasswordEncoder类的Bean,该类是PasswordEncoder接口的实现类。@Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); }
2.使用encode方法加密密码,做保存。
String encodePassword = passwordEncoder.encode(umsAdmin.getPassword()); umsAdmin.setPassword(encodePassword); adminMapper.insert(umsAdmin);
3.登录校验时使用matches方法校验密码是否正确。
UserDetails userDetails = loadUserByUsername(username);//数据库中存储的密码 if(!passwordEncoder.matches(password,userDetails.getPassword())){ throw new BadCredentialsException("密码不正确"); }
3.3springboot自动配置security
https://docs.spring.io/spring-security/site/docs/5.3.4.RELEASE/reference/html5/#servlet-hello
4.web权限方案
4.1设置用户密码
因为springboot已经默认给我们配置好了登录的密码和账号,所以自然也就会给我们提供修改账号和密码的方法,第一种修改密码和账号的方法,在配置类里面进行配置
spring:
security:
user:
name: rlfit
password: rlfit
这里使用的是yaml进行的配置。当然你还可以选择xml进行配置
配置之后控制台将不会再打印密码。这说明我们配置的密码和账号已经生效了
-
编写配置类
应为我们new的加密算法是password的实现类,但是现在在spring中没有这个实现类,所以我们得手动注入到spring中
@Bean PasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); }
评论区