1. 常用的认证机制
A. Cookie-Sesion
cookie-session认证机制是为一次请求认证在服务端创建一个session对象,同时在客户端的浏览器创建一个cookie对象,通过客户端带上来的cookie对象与服务端的session对象匹配来实现状态管理的。
基于session认证缺点:每个用户经过我们的应用认证之后,都会在服务端做一次记录,以方便用户下次请求的鉴别,一般session都是保存在内存中,而随着认证用户的增多,服务端开销会明显增大;
如果认证信息(session)是被保存在内存中,这意味着用户下次请求还必须要发到这台服务器上,这样才能拿到授权的资源,对于分布式应用,则限制了负载均衡器的能力,不易扩展;
通过cookie来进行用户识别,如果cookie被捕获,服务器就会很容易受到跨站请求伪造的攻击(CSRF)。
B. JWT token
JWT(Json Web Token)是为了在网络应用环境间传递声明而执行的一种基于JSON标准,JWT的声明一般被用在身份提供者和服务提供者间传递被认证的用户身份信息,以便与从资源服务器获取资源,也可以增加一些额外的其他业务逻辑所必须的声明信息。服务器不会保存任何会话状态,即服务器无状态。
特点:体积小,因而传输速度快
传输方式多样,如URL/POST参数/HTTP头部等方式传输
严格的结构化,在payload中包含了所有与用户相关的验证消息,如用户可访问路由、访问有效期等信息,服务器无需再去连接数据库验证信息的有效性,并且payload支持为应用定制化
支持跨域验证,特别适用于分布式站点单点登录
由于服务器不保存会话状态,所以使用期间不可能取消令牌或更改令牌权限,也就是一旦JWT签发,在有效期内将会一直有效
2. maven依赖
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.2.0</version>
</dependency>
3. JWT 结构
A. Header 头部
{
"alg": "HS256", ——加密的算法,通常直接使用HMAC SHA256
"typ": "JWT" ——声明类型,这里是JWT
}
B. Payload 载荷
载荷就是存放有效信息的地方,包含标准中注册的声明、公共的声明和私有的声明三部分
标准中注册的声明:
{
"iss": JWT签发者
"sub": JWT所面向的用户
"aud": 接收JWT的一方
"exp": JWT的过期时间
"nbf": 定义在什么时间之前,该JWT都是不可用
"iat": JWT签发时间
"jti": JWT唯一身份标识,主要用作一次性token,避免重放攻击
}
公共的声明:一般添加用户的相关信息或其他业务需要的必要信息,不要添加敏感信息,因为base64是对称加密,可解密的
私有的声明:是提供者与消费者所共同定义的声明,也不要添加敏感信息
C .Signature 签名
签名是由base64后的header、base64后的payload加上秘钥secret进行算法加密构成的
签名的作用:签名实际上是对头部和载荷内容进行签名,如果有人对头部以及载荷的内容解码之后进行修改,再编码的话,加上未知的私钥,那么新的签名和之前的就不一样,这样能保证token不被篡改。
token就是将这三部分用符号点连接形成的,如:eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1NzgwMjc4ODksInVzZXJuYW1lIjoiYWRtaW4ifQ.uE-Nhr1C_gXVxYUdWik9T6_rIY9KLDYePddXbfvXNFs
4. JWT用法
A. 前端:Authorization: Bearer token 客户端接收服务器返回的token,可存储在localStorage中,每次客户端与服务器交互都需要携带;
B. 后端:用户请求登录服务器 ->服务器接收到请求生成jwt token并返回 ->用户请求携带token认证 ->认证通过接着后面的请求,认证不通过,前端重置登录页面
package com.ruhuanxingyun.utils;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.ruhaunxingyun.commons.CommonConstant;
import java.io.UnsupportedEncodingException;
import java.util.Date;
/**
* @description: JWT工具类
* @author: ruphie
* @date: Create in 2019/12/20 17:29
* @company: ruhuanxingyun
*/
public class JwtUtils {
private final static String USERNAME = "username";
/**
* 生成token
*
* @param secret 密钥
* @param username 用户名
* @return token
*/
public static String sign(String secret, String username) throws UnsupportedEncodingException {
Date date = new Date(System.currentTimeMillis() + CommonConstant.EXPIRE_TIME);
Algorithm algorithm = Algorithm.HMAC256(secret);
String token = JWT.create()
.withClaim(USERNAME, username)
.withExpiresAt(date)
.sign(algorithm);
return token;
}
/**
* 根据token获取用户名
*
* @param token 令牌
* @return username
*/
public static String getUsername(String token) {
DecodedJWT decodedJWT = JWT.decode(token);
String username = decodedJWT.getClaim(USERNAME).asString();
return username;
}
/**
* 校验token
*
* @param secret 密钥
* @param username 用户名
* @param token token
* @return 是否合法
*/
public static boolean verify(String secret, String username, String token) {
try {
Algorithm algorithm = Algorithm.HMAC256(secret);
JWT.require(algorithm)
.withClaim(USERNAME, username)
.build()
.verify(token);
return true;
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
return false;
}
}
可参考:几种常用的认证机制
Cookie/Session/Token/Session的详解