session cookie
一般网站用户认证不外乎以下步骤:
1、用户向服务器发送用户名和密码。
2、服务器验证通过后,在当前对话(session)里面保存相关数据,比如用户角色、登录时间等等。
3、服务器向用户返回一个 session_id,写入用户的 Cookie。
4、用户随后的每一次请求,都会通过 Cookie,将 session_id 传回服务器。
5、服务器收到 session_id,找到前期保存的数据,由此得知用户的身份。
以上单机版基本没问题,但是分布式系统中涉及到 session 共享问题,比如 项目部署在serviceA 和 serviceB。用户登录后 sessionId 存在 serviceA 内存中,这个时候如果 a 挂掉了(lb 打到 b 服务器也有可能),你再请求服务器 b,发现sessionId不存在,直接让你重新登录了。
首先,问题的根源出在sessionId无法共享上,想要把sessionId共享,一个简单的思路就是把sessionId保存到数据库中(这里选择redis),这样验证的时候就不再从当前服务器获取sessionId了,而改为了从redis中获取。
Token+缓存
下面是使用 Token(相当于 session) 和 Redis 进行用户认证的基本流程:
-
用户登录:
- 用户提供用户名和密码进行登录。
- 服务器验证用户提供的凭据是否正确。
-
生成 Token:
- 如果用户提供的凭据正确,服务器会生成一个 Token。
- Token 包含用户身份信息和其他必要的元数据。
-
存储 Token 到 Redis:
- 服务器将生成的 Token 存储到 Redis 数据库中。
- Token 作为键值对的形式存储,键通常是用户标识符,值是 Token。
-
将 Token 发送给客户端:
- 服务器将生成的 Token 发送给客户端,通常是通过 HTTP 响应的方式发送给客户端。
-
客户端存储 Token:
- 客户端通常会将 Token 存储在本地,如 localStorage、sessionStorage 或者内存中。
-
用户请求受保护资源:
- 当用户访问受保护的资源时,客户端会在请求中包含 Token。通常,Token 被添加到 HTTP 请求的头部,如 Authorization 头部中。
-
验证 Token:
- 服务器接收到请求后,会从请求中提取 Token。
- 服务器验证 Token 的签名和有效性,以确保它是有效的且没有被篡改的。
-
从 Redis 中检索 Token:
- 如果 Token 有效,服务器会从 Redis 数据库中检索 Token,并验证其有效性和关联的用户身份信息。
-
授权访问:
- 如果 Token 有效,并且与用户的身份信息匹配,服务器将授权用户访问请求的资源。
-
定期更新 Token:
- 在 Token 的有效期内,客户端可以通过定期更新 Token 来保持用户的会话持续有效。
- 客户端可以使用 Refresh Token 或者其他方式来获取新的 Token。
-
用户登出:
- 用户可以通过退出登录来终止当前会话,服务器会将 Token 从 Redis 中删除,同时客户端也应该删除存储的 Token。
通过以上流程,使用 Token 和 Redis 进行用户认证能够有效地保护用户的身份信息,并且能够实现灵活的会话管理和访问控制。
JWT
以上都是维护有状态的情况,比如需要记录用户登录、在线、权限等。加入内网环境或者邮件取消等无状态场景可以选用 JWT模式。
JWT(JSON Web Token)是一种用于身份验证和信息传递的开放标准(RFC 7519),通常用于跨域认证。下面是使用 JWT 进行用户认证的基本流程:
-
用户登录:
- 用户提供用户名和密码进行登录。
- 服务器验证用户提供的凭据是否正确。
-
生成 JWT:
- 如果用户提供的凭据正确,服务器会生成一个 JWT。
- JWT 包含用户身份信息和其他必要的元数据,如过期时间等。
-
将 JWT 发送给客户端:
- 服务器将生成的 JWT 发送给客户端,通常是通过 HTTP 响应的方式发送给客户端。
-
客户端存储 JWT:
- 客户端通常会将 JWT 存储在本地,如 localStorage、sessionStorage 或者内存中。
-
用户请求受保护资源:
- 当用户访问受保护的资源时,客户端会在请求中包含 JWT。通常,JWT 被添加到 HTTP 请求的头部,如 Authorization 头部中。
-
验证 JWT:
- 服务器接收到请求后,会从请求中提取 JWT。
- 服务器验证 JWT 的签名和有效性,以确保它是有效的且没有被篡改的。
-
解析 JWT:
- 如果 JWT 有效,服务器会解析 JWT,提取其中的用户身份信息和其他元数据。
-
授权访问:
- 如果 JWT 有效,并且包含的用户身份信息是合法的,服务器将授权用户访问请求的资源。
-
定期更新 JWT:
- 在 JWT 的有效期内,客户端可以通过定期更新 JWT 来保持用户的会话持续有效。
- 客户端可以使用 Refresh Token 或者其他方式来获取新的 JWT。
-
用户登出:
- 用户可以通过退出登录来终止当前会话,此时客户端应该删除存储的 JWT。
总结
对比token+redis 和jwt:
1. 去中心化的JWT token
-
优点:
- 去中心化,便于分布式系统使用
- 基本信息可以直接放在token中。 username,nickname,role
- 功能权限较少的话,可以直接放在token中。用bit位表示用户所具有的功能权限
-
缺点:服务端不能主动让token失效
2. 中心化的 redis token / memory session等
-
优点:服务端可以主动让token失效
-
缺点:
- 依赖内存或redis存储。
- 分布式系统的话,需要redis查询/接口调用增加系统复杂性。