遇到的问题
1.在分布式集群中,我们该如何确保每一次用户访问集群的session都是原来的session
解决方案
1.基于服务器端
(1)基于session stcikly:他可以在用户登录的时候,将这个session与集群的一台机器绑定起来,以后这个session的请求都会落到这台机器上面。
(2)将session复制到集群中的每一台机器上面
(3)使用缓存,例如redis等等保存session信息,每次拦截器里面都去redis里面检验一次
2.基于客户端
(1)就是session信息只保存在客户端里面,服务器端不保存,只做session的校验。
基于客户端使用JWT解决的方案
1.在这个过程中涉及到的一些概念
(1)token:返回给客户端,用于登录的凭证。
token=base64(header).base64(payload).sinature。
(2)header:组成token的一部分,同时用于定义签名sinature的生成算法
{
"alg": "HS256",
"typ": "JWT"
}
(3)payload:同样是token的组成的一部分,里面可以声明定义用户信息,过期信息等等
{
"sub": "1234567890",
"name": "Michael",
"admin": true,
"exp": 1572687092123
}
(4)sinature:用来判断token里面的header和payload信息是否修改过,判断token是否过期等
(5)key:只是存在服务器端的密钥,用于拿来加密的,避免伪造token的,
2.生成token的过程:
我们是根据header,payload,key来生成token的
大致的过程如下:
最后代码实现如下:
package com.example.util;
import com.alibaba.fastjson.JSON;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.apache.commons.codec.binary.Base64;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* @author zhouyongquan
* @date 2019/11/2 下午4:28
* @description jwt的token的工具类
*/
public class JwtTokenUtils {
/**
* 过期时间
*/
public static final Integer TOKEN_EXPIRE_TIME = 3600 * 24 * 2;
/**
* 参与生成token的密钥key
*/
public static final String TOKEN_KEY = "MICHAEL1994";
/**
* 主函数
*
* @param args
*/
public static void main(String[] args) {
//测试生成token
String token = generateToken("michael");
System.out.println(token);
//解析生成的token
Claims claims = pharseToken("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyTmFtZSI6Im1pY2hhZWwiLCJleHAiOjE1NzI2ODY0NTE3ODN9.hLpsCqO3Vq967SV_6cc9LXgZI8Pg7eZMrNFOvL25GWc");
System.out.println(claims);
}
/**
* 由token和密钥获取header,payload里面的信息
*
* @param token
* @param secretkey
* @return
*/
public static Claims pharseToken(String token, String secretkey) {
Jws<Claims> claimsJwt = Jwts.parser()
.setSigningKey(secretkey)
.parseClaimsJws(token);
return claimsJwt.getBody();
}
/**
* 由token获取header,payload里面的信息
*
* @param token
* @return
*/
public static Claims pharseToken(String token) {
Jws<Claims> claimsJwt = Jwts.parser()
.setSigningKey(generatorSecretkey(TOKEN_KEY))
.parseClaimsJws(token);
return claimsJwt.getBody();
}
/**
* 传入header,payload,secretkey生成token
*
* @param header
* @param payload
* @param secretkey
* @return
*/
public static String generateToken(Map<String, Object> header, Map<String, Object> payload, String secretkey) {
String token = Jwts.builder()
.setHeader(header)
.setPayload(JSON.toJSONString(payload))
.signWith(SignatureAlgorithm.HS256, secretkey).compact();
return token;
}
/**
* 添加一些默认信息生成token
*
* @param userName
* @param exp
* @param secretkey
* @return
*/
public static String generateToken(String userName, long exp, String secretkey) {
Map<String, Object> defaultHeader = new HashMap<>();
defaultHeader.put("alg", "HS256");
defaultHeader.put("typ", "JWT");
Map<String, Object> payload = new HashMap<>();
payload.put("userName", userName);
payload.put("exp", exp);
return generateToken(defaultHeader, payload, secretkey);
}
/**
* userName,secretkey生成token
*
* @param userName
* @param secretkey
* @return
*/
public static String generateToken(String userName, String secretkey) {
return generateToken(userName, getDefaultTokenExpireTime(), secretkey);
}
/**
* 使用默认密钥生成token
*
* @param userName
* @return
*/
public static String generateToken(String userName) {
return generateToken(userName, generatorSecretkey(TOKEN_KEY));
}
/**
* 计算过期时间
*
* @return
*/
public static Long getDefaultTokenExpireTime() {
Date curDate = new Date();
return curDate.getTime() + TOKEN_EXPIRE_TIME;
}
/**
* 加密
*
* @param key
* @return
*/
private static String generatorSecretkey(String key) {
return Base64.encodeBase64String(key.getBytes());
}
}