八.单点登录问题(JWT令牌的使用)
1.用户身份认证产生的问题
①单一服务器
- 流程
一个web服务器,web服务器接受前端数据与数据库数据进行校验。然后返回存储该session的用户信息的cookie,用户下次请求时携带cookie即可,服务器只需通过cookie校验信息。 - 判断是否登录
cookie中携带用户信息,第二次发过来如果cookie的用户信息和数据库中相同,则已经登录。
缺点:
单点压力,无法扩展(多个web服务器返回不同coolie无法互通登录),需要使用session共享方案
②单点登录SSO(Single Sign On)模式
- 解决上述问题:用redis缓存存储分布式的cookie。有统一的登录认证服务。
- 流程
无论那个web服务器接受到访问请求先去认证服务查看是否登录,登录校验后存储在redis中,然后下一次接收到访问请求先查看redis中是否有用户身份信息,有则不需要登录。 - 判断是否登录
第一次生成token返回为key,用户信息为value,校验时通过key查redis中是否有value,有则登陆过无需登录。 - 缺点
认证服务器压力较大
③token模式
- 解决上述问题:利用令牌存储用户信息保存在用户本地,第一次访问授权服务器生成令牌返回给客户端,之后访问其他微服务只需检验令牌是否正确即可不用登录实现访问。
- 判断用户是否登录
前端cookie保存了用户信息和服务器端为每个用户信息生成的密码(客户端不知道),在所有微服务共享该密码,如果解析JWT后密码相同,则登录过。 - 缺点:
占用带宽,jwt技术生成字符串较长
2.JWT令牌简介
①令牌种类
- 透明令牌
不存储其他信息,只存储引用字符串,引用字符串用于指向具体服务器端的用户信息 - 自包含令牌(JWT)
JSON Web Tokens,包含了用户信息和独一无二的服务器端生成的密码,通过编码和解码来对比信息是否登录过。
②JWT令牌的简介
- 头
算法 - 有效载荷
数据 - 签名哈希
根据服务器端独一无二的密码编码
3.JWT令牌的使用
①引入pom
<dependencies>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.7.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
③编码jwt
package com.atguigu.jwt;
public class JwtTests {
private static long tokenExpiration = 24*60*60*1000;
private static String tokenSignKey = "atguigu123";
@Test
public void testCreateToken(){
String token = Jwts.builder()
.setHeaderParam("typ", "JWT")
.setHeaderParam("alg", "HS256")
.setSubject("guli-user")
.setIssuer("atguigu")
.setAudience("atguigu")
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + tokenExpiration))
.setNotBefore(new Date(System.currentTimeMillis() + 20*1000))
.setId(UUID.randomUUID().toString())
.claim("nickname", "Helen")
.claim("avatar", "1.jpg")
.signWith(SignatureAlgorithm.HS256, tokenSignKey)
.compact();
System.out.println(token);
}
}
④解码jwt
@Test
public void testGetUserInfo(){
String token = "jwt字符串";
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token);
Claims claims = claimsJws.getBody();
String subject = claims.getSubject();
String issuer = claims.getIssuer();
String audience = claims.getAudience();
Date issuedAt = claims.getIssuedAt();
Date expiration = claims.getExpiration();
Date notBefore = claims.getNotBefore();
String id = claims.getId();
System.out.println(subject);
System.out.println(issuer);
System.out.println(audience);
System.out.println(issuedAt);
System.out.println(expiration);
System.out.println(notBefore);
System.out.println(id);;
String nickname = (String)claims.get("nickname");
String avatar = (String)claims.get("avatar");
System.out.println(nickname);
System.out.println(avatar);
}
未更新
未更新
未更新
未更新
未更新
未更新
未更新
未更新
未更新
未更新
未更新