分布式系统session一致性的解决方案

遇到的问题

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的
大致的过程如下:
分布式系统session一致性的解决方案_第1张图片
最后代码实现如下:

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 claimsJwt = Jwts.parser()
                .setSigningKey(secretkey)
                .parseClaimsJws(token);
        return claimsJwt.getBody();
    }

    /**
     * 由token获取header,payload里面的信息
     *
     * @param token
     * @return
     */
    public static Claims pharseToken(String token) {
        Jws 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 header, Map 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 defaultHeader = new HashMap<>();
        defaultHeader.put("alg", "HS256");
        defaultHeader.put("typ", "JWT");

        Map 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());
    }
}

你可能感兴趣的:(分布式系统)