Cookie && Session && JWT 使用总结

认证-授权-凭证

什么是认证

认证就是验证当前用户的身份
互联网中的认证:

  • 用户名密码登陆
  • 邮箱发送登陆连接验证
  • 手机号接收验证码

什么是授权

用户授权第三方应用访问该用户某些资源的权限

  • 你在安装手机应用的时候,APP 会询问是否允许授予权限(地址获取,存储权限获取)
  • 微信访问小程序时,登陆时,小程序会询问是否允许授予权限
  • 实现授权的方式:cookie、session、token、OAuth

什么是凭证(Credentials)

实现认证和授权的前提是需要一种媒介(证书)来标记访问者身份

在互联网应用中一般网站(如掘金)会有两种模式,游客模式和登陆模式。游客模式中,可以正常浏览网站上面的文章,但是一旦想要点赞/收藏/分享文章,就需要登陆或者注册账号。
当用户登陆成功后,服务器会给该用户使用的浏览器颁发一个令牌(token),这个林牌用来表明你的身份,每次浏览器发送请求时就会带上这个令牌,就可以使用游客模式下无法使用的功能。

Cookie

  • HTTP 是无状态的协议(对于网络请求没有记忆能力,每次客户端和服务端会话完成时,服务端不会保存任何会话信息):每个请求都是独立的,服务端无法确认当前访问者的身份信息。
    所以服务器与浏览器为了进行会话跟踪(知道是谁在访问我),就必须主动的去维护一个状态,这个状态用于告知服务端前后端前后两个请求是否来自同一浏览器。而这个状态通过 cookie 或者 session 去实现。

  • cookie 存储在客户端:cookie 是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上。

  • cookie 是不可跨域的:每个 cookie 都会绑定单一的域名,无法在别的域名下获取使用,一级域名和二级域名之间是允许共享使用的(靠的是 domain)。

cookie 常用的属性:

属性 说明
name=value key-value,设置 Cookie 的名称及相对应的值,都必须是字符串类型
- 如果值为 Unicode 字符,需要为字符编码
- 如果值为二进制数据,则需要使用 BASE64 编码
domain 指定 cookie 所属域名,默认是当前域名
path 指定 cookie 在哪个路径(路由)下生效,默认是 ‘/‘
如果设置为 /abc,则只有 /abc下的路由可以访问到该 cookie,如:abc/read
maxAge cookie 失效时间,单位秒。如果为整数,则该 cookie 在 maxAge 秒后失效。如果为负数,该 cookie 为临时 cookie ,关闭浏览器即失效,浏览器也不会以任何形式保存该 cookie。如果为 0 ,表示删除该 cookie。默认为 -1。
expires 过期时间,在设置的某个时间点后该 cookie 就会失效。
一般浏览器的 cookie 都是默认存储的,当关闭浏览器结束这个会话的时候,这个 cookie 也就会被删除。
secure 该 cookie 是否仅被使用安全协议传输。安全协议有 HTTPS,SSL 等,在网络上传输数据之前先将数据加密。默认为 False
httpOnly 如果给某个 cookie 设置了 httpOnly 属性,则无法通过 JS 脚本读取到该 cookie 的信息,但还是能通过 Application 中手动修改 cookie,所以只是在一定程度上可以防止 XSS 攻击,不是绝对的安全

session

  • session 是另一种记录服务器和客户端会话状态的机制
  • session 是基于 cookie 实现的,session 存储在服务器端,sessionId 会被存储在客户端的 cookie 中

direct

session 认证流程

  • 用户第一次请求服务器的时候,服务器根据用户提交的相关信息,创建对应的 Session
  • 请求返回时将此 Session 的唯一标识信息 SessionID 返回给浏览器
  • 浏览器接收到服务器返回的 SessionID 信息后,会将此信息存入到 Cookie 中,同时 Cookie 记录此 SessionID 属于哪个域名
  • 当用户第二次访问服务器的时候,请求会自动判断此域名下是否存在 Cookie 信息,如果存在自动将 Cookie 信息发送给客户端,服务端会从 Cookie 中获取 SessionID, 再根据 SessionID 查找对应的 Session 信息,如果没有找到说民用户没有登陆或者登陆失败,如果找到 Session 证明用户已经登陆可执行后面操作。

SessionID 是连接 Cookie 和 Session 的一道桥梁,大部分系统也是根据此原理来验证用户登陆状态

Cookie 和 Session 区别

  • 安全性:Session 比 Cookie 安全,Session 是存储在服务器端的,Cookie 是存储在客户端的。
  • 存取值的类型不同:Cookie 只支持存字符串数据,想要设置其他类型的数据,需要将其转换成字符串,Session 可以存任意数据类型
  • 有效性不同:Cookie 可设置长时间保持,比如我们经常使用默认登陆功能,Session 一般失效时间较短,客户端关闭(默认情况下)或者 Session 超时都会失效
  • 存储大小不同:单个 Cookie 保存的数据不能超过 4K,Session 可存储数据远高于 Cookie,但是当访问量过多,会占用过多的服务器资源。

Token (令牌)

Acess Token

  • 访问资源接口(API)时所需要的资源凭证
  • 简单 token 的组成:uid(用户唯一的身份标识)time(当前时间的时间戳)sign(签名,token 的前几位以哈希算法压缩成一定长度的十六进制字符串)
  • 特点:
    • 服务端无状态化、可扩展性好
    • 支持移动端设备
    • 安全
    • 支持跨程序调用

tocken 的身份验证流程:

direct

    1. 客户端使用用户名跟密码请求登陆
    1. 服务端收到请求,去验证用户端与密码
    1. 验证成功后,服务端会签发一个 token 并把这个 token 发送给客户端
    1. 客户端收到 token 后,会把它存储起来,比如放在 cookie 或者 localStorage
    1. 客户端每次向服务端请求资源的时候需要带着服务端签发的 token
    1. 服务端收到请求,然后去验证客户端请求里面带着的 token,如果验证成功,就向客户端返回请求的数据

特点:

  • 每一次请求都需要携带 token,需要把 token 放在 HTTP 的 Header 里
  • 基于 token 的用户认证是一种服务端无状态的认证方式,服务端不同存放 token 数据。用解析 token 的计算方式换取 session 的存储空间,从而减轻服务器的压力,减少频繁的查询数据库
  • token 完全由应用管理,所以它可以避开同源策略

Refresh Token

direct

  • refresh token 是专门用于刷新 access token 的 token。如果没有 refresh token,也可以刷新 access token,但每次刷新都要用户输入登陆用户名和密码,比较麻烦。有了 refresh token,就可以减少这个麻烦,
    客户端直接用 refresh token 去更新 access token,无需用户进行额外的操作。

Token 和 Session 的区别

  • Session 是一种记录服务器和客户端会话状态的机制,使服务端有状态化,可以记录会话信息。
  • Token 是令牌,**访问资源接口(API)时所需要的资源凭证。Token 使服务端无状态化,不会存储会话信息
  • 作为身份验证 Token 安全性比 Session 好,因为每一个请求都有签名还能防止监听以及重放攻击,而 Session 就必须依赖链路层来保障通讯安全了。
  • 所谓的 Session 认证只是简单的把 User 信息存储到 Session 里,因为 SessionID 的不可预测性,暂时认为是安全的。而 Token,如果指的是 OAuth Token 或类似机制的话,提供的是认证和授权,认证是针对用户,授权是指的 App。其目的是让某 App 有权利访问某用户的信息。
    这里的 Token 是唯一的(每个项目的 secret 还是相关信息不同)。不可以转移到其他 App 上,也不可以转到其他用户上。
  • Session 只是提供一种简单的认证,即只要有此 SessionID,即认为有此 User 的全部权限。是需要严格保密的,这个数据只是保存在服务器上,不应该共享给其他往后在哪或者第三方 App。
    所以简单来说:
    • 如果你的用户数据可能需要和第三方共享,或者允许第三方调用 API 接口,用 Token。若永远只是自己的 website 则可以用 Seesion

JWT

  • Json Web Token 是目前前后端分离的跨域认证解决方案
  • 是一种认证授权机制
  • 基于 JSON 的开放标准(RFC 7519)
  • 使用 HMAC 算法或者是 RSA 的公/私密钥对 JWT 进行签名。
    direct

这里参考:http://www.ruanyifeng.com/blog/2018/07/json_web_token-tutorial.html

用户认证流程:

  • 客户端使用用户名和密码来请求服务器进行登陆
  • 服务器进行用户名和密码的验证
  • 通过验证,服务器生成一个 token 并返回给浏览器
  • 客户端存储 token,存储位置为 header/localstorge/url?token=xxxxx 的方式
  • 服务端验证 token 值,并返回相应的响应

JWT token 数据组成格式

JWT token 是一个字符串,由三部分组成,用 . 隔开

  • 头部(header)
  • 载荷(payload)
  • 签名(signature)
1
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

// Generate JWT token
func GenerateJwtToken(username, password string) (string, error) {
nowTime := time.Now()
expireTime := nowTime.Add(2 * time.Hour)

claims := Claims{
// header
username,
password,

// payload
jwt.StandardClaims{
ExpiresAt: expireTime.Unix(),
Issuer: PROJECTISSUE,
},
}

// signature
tokenClaims := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)

token, err := tokenClaims.SignedString(projectSecret)
return token, err
}

基于 Gin 的 JWT 实现

代码地址:https://github.com/tyronemaxi/Jwt-practice

-------------THANKS FOR READING-------------