两种登陆状态

有状态登陆

为了保证客户端cookie的安全性,服务端需要记录每次会话的客户端信息,从而识别客户端身份,根据用户身份进行请求的处理,典型的设计如tomcat中的session。

例如登录:用户登录后,我们把登录者的信息保存在服务端session中,并且给用户一个cookie值,记录对应的session。然后下次请求,用户携带cookie值来,我们就能识别到对应session,从而找到用户的信息。

缺点是什么:

  1. 服务端保存大量数据,增加服务端压力
  2. 服务端保存用户状态,无法进行水平扩展
  3. 客户端请求依赖服务端,多次请求必须访问同一台服务器

无状态登陆

微服务及集群的每个服务队外都是提供REST风格的接口,而这些接口有一个重要的规范就是服务的无状态。

  • 也就是服务端不保存任何客户端的信息
  • 客户端的每次请求都必须自备描述信息,通过这些信息识别客户端身份

我们不禁想问,带来的收益是什么

  • 任何多次请求不需要访问同一台服务器
  • 服务器的集群和状态对客户端透明
  • 服务端可以任意的前一和伸缩
  • 减小服务端的存储压力

无状态登陆流程

  1. 当客户端第一次请求服务时候,服务端对于用户进行信息认证
    1
    2
    3
    4
    5
    boolean isValidToken = validateToken(token);
    if (!isValidToken) {
    handleInvalidToken(request);
    return null;
    }
  2. 认证通过后,将用户信息进行加密形成token,返回给客户端,作为登陆凭证
    1
    2
    3
    4
    5
    6
    7
    8
    @Override
    public String login(String username, String password) {
    if (!userDao.existsByUserNameAndPassword(username, password)) {
    logger.info("登录失败:用户名或密码错误");
    return null;
    }
    return generateNewJwt(username);
    }
  3. 以后每次请求,客户端都携带认证的token
    1
    2
    3
    4
    5
    6
    fetch('https://example.com/api/endpoint', {
    method: 'GET',
    headers: {
    'Authorization': `Bearer ${storedToken}`, // 将 Token 添加到 Authorization Header
    },
    });
  4. 服务对于token进行解密,判断是否有效

什么是JWT

JWT,全称是Json Web Token, 是JSON风格轻量级的授权和身份认证规范,可实现无状态、分布式的Web应用授权;

整个过程的关键点是token是识别客户端身份的唯一标识,如果加密不够严密,那么将会出现问题
我们将使用JWT + RSA非对称加密

在简单的复习一下RSA的加密过程
我们需要知道(N,e)公钥和(N,d)私钥,将私钥进行保存
将想要加密的消息进行{\displaystyle c=n^{e}{\bmod {N}}}
我们需要进行传递c
然后我们就可以使用快速幂等的方法去获得想要的信息n
{\displaystyle n=c^{d}{\bmod {N}}}

JWT包含三部分数据
header: 包含token类型:jwt,加密方式:base64
payload: 用户身份信息以及token的签发时间,过期时间和签发人等
signature:整个数据的认证信息,再加上secret
login

同时jwt也有一些缺陷,例如
无法动态更新用户信息,也就是无法主动失效的问题
痛点:JWT一旦签发,其中的信息(如角色、权限)在有效期内是固定的。如果用户权限在令牌有效期内发生变化(如被管理员修改),旧令牌仍然有效,直到过期。
影响:可能导致权限不一致的问题。
解决思路:
缩短令牌有效期,强制用户定期刷新。
结合服务端检查,每次请求时验证用户当前权限(但这会增加服务器负担,部分违背无状态初衷)。
使用黑名单机制,权限变更时将旧令牌加入黑名单(你已经实现了类似的方案)。