目录
会话跟踪
Cookis
优点
Http协议支持的技术
缺点
移动端app无法使用
不安全
不能跨域
Session
优点
存储在服务端,安全
缺点
服务器集群环境下无法直接使用Session
还有Cookie的缺点
令牌技术
优点
支持PC端,移动端
解决集群环境下的认证问题
减轻服务器存储的压力
缺点
需要自己实现
JWT令牌技术
简洁
指jwt就是一个简单的字符串。可以在请求参数或者是请求头当中直接传递。
自包含
指的是jwt令牌,看似是一个随机的字符串,但是我们是可以根据自身的需求在jwt令牌中存储自定义的数据内容。如:可以直接在jwt令牌中存储用户的相关信息。
用途
在通信双方以json数据格式安全的传输信息,所以安全
组成
由三个部分之间使用点来分割
Header(头):记录令牌类型、签名算法等
Payload(有效载荷):携带一些自定义信息、默认信息
Signature(签名):防止Token被篡改、确保安全性。将header、payload,并加入指定秘钥,通过指定签名算法计算而来
解析数据
JWT是如何将原始的JSON格式数据,转变为字符串的呢?
在生成JWT令牌时,会对JSON格式的数据进行一次编码:进行base64编码
一种基于64个可打印的字符来表示二进制数据的编码方式
64个字符分别是A到Z、a到z、 0- 9,一个加号,一个斜杠,加起来就是64个字符还有一个符号,等号它是一个补位的符号
是编码方式,而不是加密方式
令牌实现操作案例
1. 在登录成功之后,要生成令牌。
先引入JWT的依赖
<!-- JWT依赖-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
生成JWT代码
@Test
public void genJwt(){
Map<String,Object> claims = new HashMap<>();
claims.put("id",1);
claims.put("username","Tom");
String jwt = Jwts.builder()
.setClaims(claims) //自定义内容(载荷)
.signWith(SignatureAlgorithm.HS256, "itheima") //签名算法
.setExpiration(new Date(System.currentTimeMillis() + 24*3600*1000)) //有效期
.compact();
System.out.println(jwt);
}
2. 每一次请求当中,要接收令牌并对令牌进行校验。
可以校验JWT令牌(解析生成的令牌):
@Test
public void parseJwt(){
Claims claims = Jwts.parser()
.setSigningKey("itheima")//指定签名密钥(必须保证和生成令牌时使用相同的签名密钥)
.parseClaimsJws("eyJhbGciOiJIUzI1NiJ9.eyJpZCI6MSwiZXhwIjoxNjcyNzI5NzMwfQ.fHi0Ub8npbyt71UqLXDdLyipptLgxBUg_mSuGJtXtBk")
.getBody();System.out.println(claims);
}
使用JWT令牌时需要注意
JWT校验时使用的签名秘钥,必须和生成JWT令牌时使用的秘钥是配套的。
如果JWT令牌解析校验时报错,则说明 JWT令牌被篡改 或 失效了,令牌非法。
登录下发令牌
实现步骤
1.引入JWT工具类
public class JwtUtils {
private static String signKey = "itheima";//签名密钥
private static Long expire = 43200000L; //有效时间/**
* 生成JWT令牌
* @param claims JWT第二部分负载 payload 中存储的内容
* @return
*/
public static String generateJwt(Map<String, Object> claims){
String jwt = Jwts.builder()
.addClaims(claims)//自定义信息(有效载荷)
.signWith(SignatureAlgorithm.HS256, signKey)//签名算法(头部)
.setExpiration(new Date(System.currentTimeMillis() + expire))//过期时间
.compact();
return jwt;
}/**
* 解析JWT令牌
* @param jwt JWT令牌
* @return JWT第二部分负载 payload 中存储的内容
*/
public static Claims parseJWT(String jwt){
Claims claims = Jwts.parser()
.setSigningKey(signKey)//指定签名密钥
.parseClaimsJws(jwt)//指定令牌Token
.getBody();
return claims;
}
}
2.登录完成后,调用工具类生成JWT令牌并返回
@RestController
@Slf4j
public class LoginController {
//依赖业务层对象
@Autowired
private EmpService empService;@PostMapping("/login")
public Result login(@RequestBody Emp emp) {
//调用业务层:登录功能
Emp loginEmp = empService.login(emp);//判断:登录用户是否存在
if(loginEmp !=null ){
//自定义信息
Map<String , Object> claims = new HashMap<>();
claims.put("id", loginEmp.getId());
claims.put("username",loginEmp.getUsername());
claims.put("name",loginEmp.getName());//使用JWT工具类,生成身份令牌
String token = JwtUtils.generateJwt(claims);
return Result.success(token);
}
return Result.error("用户名或密码错误");
}
}