Spring Security 是spring家族中的一个安全管理框架。相比于另一个安全框架Shiro,它提供更丰富的功能和社区资源,但也较难上手。所以一般大项目用spring Security,小项目用Shiro。
一般web应用需要认证和授权,这也是spring Security的核心功能。
认证:验证当前访问系统的是不是本系统用户,并且要确认具体是哪个用户。
授权:经过认证后判断当前用户是否有权限进行某操作。
需要引入以下依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
然后我们写一个简单的访问controller,来简单看看springSecurity的功能
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping
public class HelloController {
@GetMapping("/hello")
public String hello(){
return "hello";
}
}
启动后,在浏览器访问 http://localhost:8080/hello 访问该接口时会自动跳转到一个springSecurity默认的登陆界面,默认用户名为user,密码会输出在控制台。
登陆后才可访问。
下面说说通用的登陆校验流程:
在登陆时,前端会把用户输入的用户名和密码传给后端,后端根据用户名去数据库查询,若有该用户并且密码正确则认证通过,然后根据userId生成jwt,把jwt传给前端。这样用户登陆后,在发送其他请求时携带token发送给后端,后端就可以根据token解析出userId获取用户信息然后做出响应。
下面我们在看看springSecurity是怎么实现该流程的:
先简单说说springSecurity
springSecurity原理其实是一个过滤器链,内部包含提供各种功能的过滤器。
UsernamePasswordAuthenticationFilter:负责处理我们在登陆页面填写了用户名密码后的登陆请求。
ExceptionTranslationFilter:处理过滤器链中跑出的任何AccessDeniedException和AuthenticationException。
FilterSecurityInterceptor:负责权限校验的过滤器。
具体过滤器及顺序:
下面是springSecurity实现认证流程的一个案例(springSecurity有很多不同的实现方法,但几乎都差不多,看懂一个其他的就也能看懂了)
下面的图为重点
Authentication接口:它的实现类,表示当前访问系统的用户,封装了用户相关信息。
AuthenticationManager接口:定义了认证Authentication的方法
UserDetailsService接口:加载用户特定数据的核心接口,里面定义了一个根据用户名查询用户信息的方法。
UserDetails接口:提供可信用户信息。通过UserDetailsService根据用户名获取处理的用户信息要封装成UserDetails对象返回。然后将这些信息封装到Authentication对象中。
其中UserDetailsService是从内存中查询用户信息,但我们想要的是从数据库中查,所以我们可以替换掉UserDetailsService的实现类。
而且这个新的实现类还需要实现图中5.2功能,把查询到的数据封装为UserDetails对象返回;同时,认证通过时,还需要返回一个token,但UsernamePasswordAuthenticationFilter中无法响应token,所以我们还自定义一个登陆接口Filter。
修改后的流程图:
上图仅仅是登陆的大概流程,但我们还要考虑校验(就是登陆之后,在发请求时怎么判断该用户是否已经登陆):
查看请求中是否携带token,然后从token中获取用户id。
然后获取userId后怎么获取该用户的完整信息呢?我们很容易想到到数据库去查,但如果每发一次请求都去查询数据库,数据库压力会很大。所以我们可以添加一个redis:如果认证通过了,用userId作key,用户完整信息作value存入redis。