分布式系统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的
大致的过程如下:
在这里插入图片描述
最后代码实现如下:

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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
分布式前端session共享是一种实现分布式系统实现前端用户会话的机制。在传统的单体应用中,前端会话通常可以直接存储在后端服务器的内存或数据库中,但在分布式系统中,由于涉及多个前端实例和后端服务实例,需要实现前端会话的共享,以保证用户在不同的前端实例间的状态一致性和无缝切换。 实现分布式前端session共享的常用方案包括: 1. 使用缓存中间件:可以通过使用像Redis或Memcached等缓存中间件,将前端会话数据存储在缓存中,实现多个前端实例之间的共享。前端实例可以通过访问同一个缓存中间件,来读取和写入会话数据。 2. 使用数据库存储:将前端会话数据存储在数据库中,通过数据库实现数据的共享。前端实例可以访问同一个数据库,来读取和写入会话数据。 3. 使用分布式协议:通过一致性哈希算法或其他分布式算法,将前端会话数据进行分片,然后分散存储在多个前端实例中。每个前端实例只需存储自己负责的会话数据,实现数据的共享与分布。 4. 使用共享存储:可使用像NFS(Network File System)这样的共享文件系统,将前端会话数据存储在共享文件中,实现多个前端实例之间的数据访问共享。 无论选择哪种方案,需要注意的是要解决会话数据的一致性和并发访问的问题。可以采用同步策略、加锁机制或乐观锁等方法来保证会话数据的一致性。同时,还需要考虑到共享会话数据的性能要求,确保能够支持高并发和低延迟的访问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值