基于Cookie-Session和基于Token的认证模式

基于Cookie、Session和基于Token的认证模式介绍

HTTP是一个无状态的协议,一次请求结束后,下次在发送服务器就不知道这个请求是谁发来的了(同一个IP不代表同一个用户),在Web应用中,用户的认证和鉴权是非常重要的一环,实践中有多种可用方案,并且各有千秋。

在Web应用发展的初期,大部分采用基于Cookie-Session的会话管理方式,逻辑如下。

  • 客户端使用用户名、密码进行认证
  • 服务端验证用户名、密码正确后生成并存储Session,将SessionID通过Cookie返回给客户端
  • 客户端访问需要认证的接口时在Cookie 中携带SessionlD
  • 服务端通过SessionID查找Session并进行鉴权,返回给客户端需要的数据
image-20240615102235838

基于Session的方式存在多种问题:

  • 服务端需要存储Session,并且由于Session需要经常快速查找,通常存储在内存或内存数据库中,同时在线用户较多时需要占用大量的服务器资源。
  • 当需要扩展时,创建Session的服务器可能不是验证Session的服务器,所以还需要将所有Session单独存储并共享。
  • 由于客户端使用Cookie存储SessionlD,而cookie是没办法跨域的,在跨域场景下需要进行兼容性处理,同时这种方式也难以防范CSRF攻击。

info

CSRF攻击详见CSRF攻击.

Token认证模式

基于token的认证机制将认证信息返回给客户端并存储。下次访问其他页面,需要从客户端传递认证信息回服务端。简单的流程如下:

  • 客户端使用用户名跟密码请求登录;
  • 服务端收到请求,去验证用户名与密码;
  • 验证成功后,服务端会签发一个 Token,再把这个 Token 发送给客户端;
  • 客户端收到 Token 以后可以把它存储起来,比如放在 Cookie 里或者 Local Storage 里;
  • 客户端每次向服务端请求资源的时候需要带着服务端签发的 Token;
  • 服务端收到请求,然后去验证客户端请求里面带着的 Token,如果验证成功,就向客户端返回请求的数据;

基于token的验证机制,有以下的优点:

  • 支持跨域访问,将token置于请求头中,而cookie是不支持跨域访问的;
  • 无状态化,服务端无需存储token,只需要验证token信息是否正确即可,而session需要在服务端存储,一般是通过cookie中的sessionID在服务端查找对应的session;
  • 无需绑定到一个特殊的身份验证方案(传统的用户名密码登陆),只需要生成的token是符合我们预期设定的即可;
  • 更适用于移动端(Android,iOS,小程序等等),像这种原生平台不支持cookie,比如说微信小程序,每一次请求都是一次会话,当然我们可以每次去手动为他添加cookie,详情请查看博主另一篇博客;
  • 避免CSRF跨站伪造攻击,还是因为不依赖cookie;

缺点的话一个就是相比较于传统的session登陆机制实现起来略微复杂一点,另外一个比较大的缺点是由于服务器不保存 token,因此无法在使用过程中废止某个 token,或者更改 token 的权限。也就是说,一旦 token 签发了,在到期之前就会始终有效,除非服务器部署额外的逻辑。

如何解决这个问题?

可以给token的过期时间设置的短一点,然后引入一个refresh token,当token过期的时候,使用refresh token刷新token。具体做法是:

  1. 客户端使⽤用⽤用户名密码进⾏行行认证
  2. 服务端⽣生成有效时间较短的 Access Token(例例如 10 分钟),和有效时间较⻓长的 Refresh Token(例如 7 天)
  3. 客户端访问需要认证的接⼝口时,携带 Access Token
  4. 如果 Access Token 没有过期,服务端鉴权后返回给客户端需要的数据
  5. 如果携带 Access Token 访问需要认证的接⼝口时鉴权失败(例如返回 401 错误),则客户端使用Refresh Token 向刷新接⼝口申请新的 Access Token(也可以同时返回新的refresh token和access token)
  6. 如果 Refresh Token 没有过期,服务端向客户端下发新的 Access Token
  7. 客户端使⽤用新的 Access Token 访问需要认证的接口

note

使用这种方法后端需要对外提供⼀一个刷新Token的接口,前端需要实现⼀一个当Access Token过期时⾃自动请求刷新Token接口获取新Access Token的拦截器器。

image-20240615102555596

基于JWT的token方式验证

JWT是JSON Web Token 的缩写,是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC7519)。JWT本身没有定义任何技术实现,它只是定义了一种基于Token的会话管理的规则,涵盖Token需要包含的标准内容和Token 的生成过程,特别适用于分布式站点的单点登录(SSO)场景。

一个JWT Token 就像这样:

1
2
3
eyJhbGcioiJIUzI1NiIsInR5cCI6IkpxVCJ9
.eyJ1c2VyX2lkIjoyODAxODcyNzQ4ODMyMZU4NSwiZXhwIjoxNTkONTQwMjkxLCJpc3MiOiJibHVlYmVsbCJ9
.lk_ZrAtYGCeZhK3iupHxP1kgjBTzQTVTtX0izYFx9wU

它是由.分隔的三部分组成,这三部分依次是:

  • 头部(Header):存储了所使用的加密算法和Token类型
  • 负载(Payload):自定义信息内容
  • 签名(Signature):头部Base64通过加密算法和密钥生成的,防止令牌信息被篡改 头部和负载以JSON形式存在,这就是JWT中的JSON,三部分的内容都分别单独经过了Base64编码,以.拼接成一个JWT Token。
image-20240615114512952

Header:

JWT的Header中存储了所使用的加密算法和Token类型。

1
2
3
4
{
"alg": "HS256", // HS256:带有SHA-256的HMAC
"TYP": "jwt"
}

Payload:

Payload表示负载(将Token当做是一个载体,表示Token里面装的是什么),也是一个JSON对象,JWT规定了7个官方字段供选用

1
2
3
4
5
6
7
iss (issuer)︰签发人
exp ( expiration time):过期时间
sub ( subject)︰主题
aud (audience)︰受众
nbf (Not Before):生效时间
iat ( Issued At)︰签发时间
jti(JwT ID)∶编号

除了官方字段,开发者也可以自己指定字段和内容,例如下面的内容。

1
2
3
4
5
{
"sub" : "1234567890",
"name " : "John Doe" ,
"admin " : true
}

注意,JWT默认是不加密的,任何人都可以读到,所以不要把秘密信息放在这个部分。这个JSON对象也要使用Base64URL算法转成字符串。

Signature:

Signature部分是对前两部分的签名,防止数据篡改。 首先,需要指定一个密钥(secret)。这个密钥只有服务器才知道,不能泄露给用户。然后,使用Header里面指定的签名算法(默认是 HMAC SHA256),按照下面的公式产生签名。

JWT优缺点

JWT拥有基于Token的会话管理方式所拥有的一切优势,不依赖Cookie,使得其可以防止CSRF攻击,也能在禁用Cookie的浏览器环境中正常运行。

  1. jwt基于json,非常方便解析
  2. 可以在令牌中自定义丰富的内容,易扩展;
  3. 通过对称加密算法及数字签名技术。

区别与联系

cookie和token的区别

Token 和 Cookie 是两种在 Web 开发中用于存储和管理用户会话、身份验证信息的机制。尽管它们在功能上有一定的重叠,但它们在设计、实现和使用方式上存在显著差异。以下是 Token 和 Cookie 的详细比较:

方面 Token Cookie
存储位置 客户端存储(localStorage、sessionStorage)或移动设备 浏览器的 Cookie 存储
安全性 通过加密和签名增强安全;易受 XSS 攻击 通过 HttpOnlySecureSameSite 增强安全;易受 CSRF 攻击
管理 客户端和服务器共同管理;需要手动添加到请求头 由浏览器自动管理和发送
生命周期 通常较短;支持刷新 可以设置长时间过期或会话结束时失效
使用场景 单页应用、API 调用、移动应用 传统 Web 应用、会话管理、用户偏好保存
便捷性 需要手动操作,灵活但复杂 浏览器自动管理,便捷但限制多

token与JWT的区别

Token需要查库验证token 是否有效,而JWT不用查库,直接在服务端进行校验,因为用户的信息及加密信息,和过期时间,都在JWT里,只要在服务端进行校验就行,并且校验也是JWT自己实现的。


基于Cookie-Session和基于Token的认证模式
https://gstarmin.github.io/2024/06/15/基于Cookie-Session和基于Token的认证模式/
作者
Starmin
发布于
2024年6月15日
许可协议