从下图的6个方面去学习
一.Spring Security本质上是过滤器链。
1.导入security和springbootweb的依赖,就会开始生效,默认拦截全部请求,如果用户没有登录,跳转到内置登录页面。默认的用户名为user,密码在控制台打印。
2.自定义传入账号和密码1,他提供了 UserDetailsService 接口,而其返回值 UserDetails 也是一个接口,实现类有 User 类。使用时直接构造user类,传入账号密码和权限。
Spring Security 要求容器中必须有 PasswordEncoder 实例,所以当自定义登录逻辑时要求必须给容器注入PaswordEncoder 的bean对象。
3.自定义传入账号和密码2,PasswordEncoder 密码解析器是一个接口。
BCryptPasswordEncoder是官方推荐的解析器,实例化之后用encode方法加密,用matches方法判断密码是否正确。
//本来应该是把数据库里加密过的密码取出来,但是这里没连数据库,就先进行加密再放入user构造方法。
String password = b.encode("123");
User user = new User("admin", password,new ArrayList<>());
// boolean matches = b.matches("123", password);
// System.out.println(matches);
二.Oauth2第三方认证技术接口协议
1.以微信授权为例
2.Oauth2.0认证流程(官方)
3.Spring Security Oauth2授权码模式
1)导入spring-cloud-starter-oauth2等依赖
三.JSON Web Token(JWT)是一个开放的行业标准,用于在通信双方传递json对象
1.一个JWT实际上就是一个字符串,它由三部分组成,头部、载荷与签名
1)头部(Header)用于描述关于该JWT的最基本的信息,例如其类型(即JWT)以及签名所用的算法(如HMAC SHA256或RSA)等。
{
"alg": "HS256",
"typ": "JWT"
}
typ :是类型。
alg :签名的算法,这里使用的算法是HS256算法
一般我们会对头部的json字符串进行BASE64编码
2)负载(Payload)就是存放有效信息的地方
标准中注册的声明(建议但不强制使用)
iss: jwt签发者
sub: jwt所面向的用户
aud: 接收jwt的一方
exp: jwt的过期时间,这个过期时间必须要大于签发时间
nbf: 定义在什么时间之前,该jwt都是不可用的.
iat: jwt的签发时间
jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。
公共的声明
公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息.但不建议添加敏感信息,
因为该部分在客户端可解密
私有的声明
{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022
}
其中 sub 是标准的声明, name 是自定义的声明(公共的或私有的)
3)签证、签名(signature)签证信息由三部分组成
1. header (base64后的)
2. payload (base64后的)
3. secret(盐,一定要保密)
将这三部分用.连接成一个完整的字符串,构成了最终的jwt:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaW
F0IjoxNTE2MjM5MDIyfQ.8HI-Lod0ncfVDnbKIPJJqLH998duF9DSDGkx3gRPNVI
三.JJWT简介,JJWT是一个提供端到端的JWT创建和验证的Java库。
//创建一个JwtBuilder对象
JwtBuilder jwtBuilder = Jwts.builder()
//声明的标识{"jti":"888"}
.setId("888")
//主体,用户{"sub":"Rose"}
.setSubject("Rose")
//创建日期{"ita":"xxxxxx"}
.setIssuedAt(new Date())
//签名手段,参数1:算法,参数2:盐
.signWith(SignatureAlgorithm.HS256,"xxxx");
//设置过期时间一分钟
.setExpiration(new Date(now + 60 * 1000))
//获取jwt的token
String token = jwtBuilder.compact();
System.out.println(token);
//三部分的base64解密
System.out.println("--------------------");
String[] split = token.split("\.");
System.out.println(Base64Codec.BASE64.decodeToString(split[0]));
System.out.println(Base64Codec.BASE64.decodeToString(split[1]));
//无法解密
System.out.println(Base64Codec.BASE64.decodeToString(split[2]));
我们刚才已经创建了token ,在web应用中这个操作是由服务端进行然后发给客户端,客户端在下次向服务端发送
请求时需要携带这个token(这就好像是拿着一张门票一样),那服务端接到这个token 应该解析出token中的信息
(例如用户id),根据这些信息查询数据库返回相应的结果。
@Test
public void testParseToken(){
//token
String token =
"eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI4ODgiLCJzdWIiOiJSb3NlIiwiaWF0IjoxNTc4ODE0MjUyfQ" +
".-FYFMHyfTcGzq900f_Drfdsges0ge2UjaWvPW9gCDto";
//解析token获取负载中的声明对象
Claims claims = Jwts.parser()
.setSigningKey("xxxx")
.parseClaimsJws(token)
.getBody();
//打印声明的属性
System.out.println("id:"+claims.getId());
System.out.println("subject:"+claims.getSubject());
System.out.println("issuedAt:"+claims.getIssuedAt());
}