1.Jwt出现的原因及工作原理
1.1背景
在传统的会话管理方式中,服务器需要在每次请求时记录用户的会话状态,通常使用Session ID和Cookie来实现。然而,这种方式存在一些问题,如服务器需要维护会话状态,增加了服务器的负担;需要在多个服务器之间进行会话共享;不适用于跨域的场景等
而JWT(JSON Web Token)是一种用于身份验证和授权的开放标准,它出现的原因是为了解决传统的会话管理方式的一些问题。
1.2工作原理
1.2.1
JWT的工作原理相对简单,它由三部分组成:头部(Header)、负载(Payload)和签名(Signature)。
- 头部(Header):头部通常由两部分组成,一部分是声明该令牌使用的加密算法(如HMAC、RSA等),另一部分是声明令牌的类型(即JWT)。
- 负载(Payload):负载是JWT的主要内容,包含了一些称为声明(claims)的信息,如用户ID、角色、过期时间等。负载可以根据需求自定义添加一些额外的信息。
- 签名(Signature):签名是为了验证令牌的真实性和完整性,防止令牌被篡改。签名使用头部、负载和一个密钥(只有服务器知道)进行加密生成,服务器在接收到令牌后使用相同的密钥进行解密和验证签名。
1.2.2
1)当用户进行身份验证时,服务器会生成一个JWT,并将其作为响应的一部分返回给客户端。
2)客户端在后续的请求中会在请求头或其他方式中携带该JWT。
3)服务器在接收到请求后,会使用相同的密钥解密和验证JWT的签名,从而确认JWT的真实性和完整性,并根据负载中的信息进行相应的身份验证和授权操作。
2.Jwt工具类介绍,三种场景
创建JWT令牌,签发事件为当前时间
/**
* 创建JWT令牌,签发时间为当前时间
*
* @param claims
* 创建payload的私有声明(根据特定的业务需要添加,如果要拿这个做验证,一般是需要和jwt的接收方提前沟通好验证方式的)
* @param ttlMillis
* JWT的有效时间(单位毫秒),当前时间+有效时间=过期时间
* @return jwt令牌
*/
public static String createJwt(Map<String, Object> claims,
long ttlMillis) {
// 生成JWT的时间,即签发时间 2021-10-30 10:02:00 -> 30 10:32:00
long nowMillis = System.currentTimeMillis();
//链式语法:
// 下面就是在为payload添加各种标准声明和私有声明了
// 这里其实就是new一个JwtBuilder,设置jwt的body
JwtBuilder builder = Jwts.builder()
// 如果有私有声明,一定要先设置这个自己创建的私有的声明,这个是给builder的claim赋值,一旦写在标准的声明赋值之后,就是覆盖了那些标准的声明的
.setClaims(claims)
// 设置jti(JWT ID):是JWT的唯一标识,根据业务需要,这个可以设置为一个不重复的值,主要用来作为一次性token,从而回避重放攻击。
// 可以在未登陆前作为身份标识使用
.setId(UUID.randomUUID().toString().replace("-", ""))
// iss(Issuser)签发者,写死
.setIssuer("zking")
// iat: jwt的签发时间
.setIssuedAt(new Date(nowMillis))
// 代表这个JWT的主体,即它的所有人,这个是一个json格式的字符串,可放数据{"uid":"zs"}。此处没放
// .setSubject("{}")
// 设置签名使用的签名算法和签名使用的秘钥
.signWith(SIGNATURE_ALGORITHM, JWT_KEY)
// 设置JWT的过期时间
.setExpiration(new Date(nowMillis + ttlMillis));
return builder.compact();
}
测试
解密Jwt,获得所有声明(包括标准和私有声明)
/**
* 解密jwt,获得所有声明(包括标准和私有声明)
*
* @param jwt
* @return
* @throws Exception
*/
public static Claims parseJwt(String jwt) {
Claims claims = Jwts.parser()
.setSigningKey(JWT_KEY)
.parseClaimsJws(jwt)
.getBody();
return claims;
}
测试
复制Jwt,并重新设置签发时间
/**
* 复制jwt,并重新设置签发时间(为当前时间)和失效时间
*
* @param jwt
* 被复制的jwt令牌
* @param ttlMillis
* jwt的有效时间(单位毫秒),当前时间+有效时间=过期时间
* @return
*/
public static String copyJwt(String jwt, Long ttlMillis) {
//解密JWT,获取所有的声明(私有和标准)
//old
Claims claims = parseJwt(jwt);
// 生成JWT的时间,即签发时间
long nowMillis = System.currentTimeMillis();
// 下面就是在为payload添加各种标准声明和私有声明了
// 这里其实就是new一个JwtBuilder,设置jwt的body
JwtBuilder builder = Jwts.builder()
// 如果有私有声明,一定要先设置这个自己创建的私有的声明,这个是给builder的claim赋值,一旦写在标准的声明赋值之后,就是覆盖了那些标准的声明的
.setClaims(claims)
// 设置jti(JWT ID):是JWT的唯一标识,根据业务需要,这个可以设置为一个不重复的值,主要用来作为一次性token,从而回避重放攻击。
// 可以在未登陆前作为身份标识使用
//.setId(UUID.randomUUID().toString().replace("-", ""))
// iss(Issuser)签发者,写死
// .setIssuer("zking")
// iat: jwt的签发时间
.setIssuedAt(new Date(nowMillis))
// 代表这个JWT的主体,即它的所有人,这个是一个json格式的字符串,可放数据{"uid":"zs"}。此处没放
// .setSubject("{}")
// 设置签名使用的签名算法和签名使用的秘钥
.signWith(SIGNATURE_ALGORITHM, JWT_KEY)
// 设置JWT的过期时间
.setExpiration(new Date(nowMillis + ttlMillis));
return builder.compact();
}
测试
3.Jwt与Vuex配合在SPA项目中的应用
步骤
1)user登录方法,要放开用户信息生成jwt串保存到响应头中的代码
2)关闭jwtfilter中的off开关,代表开启jwt验证
private boolean OFF = false;// true关闭jwt令牌验证功能
3)crosfilter中要允许jwt使用请求头及响应头
<!--CrosFilter跨域过滤器-->
<filter>
<filter-name>corsFilter</filter-name>
<filter-class>com.zking.ssm.util.CorsFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>corsFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
state.js
export default{
jwt: ''
}
mutations.js
export default{
setJwt:function(state,payload){
// 载荷
staet.jwt = payload.jwt;
}
}
getters.js
export default{
getJwt:function(state){
return state:jwt;
}
}
main.js
window.vm = new Vue({})
http.js
// 请求拦截器
axios.interceptors.request.use(function(config) {
var jwt = window.vm.$store.getters.getJwt;
config.headers['jwt'] = jwt;
return config;
}, function(error) {
return Promise.reject(error);
});
// 响应拦截器
axios.interceptors.response.use(function(response){
var jwt = response.headers['jwt'];
if(jwt){
window.vm.$store.commit('setJwt',{jwt:jwt});
}
return response;
}, function(error) {
return Promise.reject(error);
})