用户身份认证-JWT

用户身份认证体系

JWT(JSON Web Tokens)

是为了在网络应用环境间传递声明而执行的一种基于 JSON 的开放标准(RFC 7519);
来自 JWT RFC 7519 标准化的摘要说明。

JSON Web Token 是一种紧凑的, URL 安全的方式, 表示要在双方之间传输的声明;

JWT 一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,
以便于从资源服务器获取资源, 也可以增加一些额外的其它业务逻辑所必须的声明信息,
此 Token 也可直接被用于认证, 也可被加密;

简述

即使用一个 json 存放基础的用户身份信息, 客户每次访问都在 http 头内带着;
服务器只颁发和验证此 json, 不存储;

数据以 json 格式组织, 适用于 web 场景, 是一个 token(令牌)

场景

  1. Authorization (授权): 确认用户具有此次操作的权限
  2. Information Exchange (信息交换): 确定传来的数据, 是可信用户发出的

JWT 的优点

  1. 跨语言, JSON 的格式保证了跨语言的支撑
  2. 基于 Token, 无状态
  3. 服务器端不需要存储, 只做颁发和校验
  4. 占用字节小, 便于传输

跨域问题

一般来说服务器需要设置为接受来自所有域的请求, 用 Access-Control-Allow-Origin: *

优点

  1. 服务器不需要存储 session 信息, 只需要验证是否合法即可;
  2. 适合分布式场景, 在多个域之间请求时, 由客户端选择性传递
  3. 因为服务器侧无状态, 所以可以很方便的扩容;

缺点

  1. token 在有效期内, 需要服务器侧注销, 会比较麻烦;
  2. 数据一致性问题
    JWT 中的个性信息如果发生改变是否需要重新颁发 token

比对-基于服务器存储认证信息的缺点

  1. 需要存储大量的 session, 还需要考虑高可用
  2. 需要考虑 同一用户 多设备使用时 的 session 同步或冲突问题
  3. 容易受到 CSRF 攻击
  1. 默认并不会存储在客户端;
  2. 与 cookie 的 header 字段不同, 可以自定义。

===

JWT 结构

JWT 是由三段信息构成的

  1. 第一段为头部(Header)
  2. 第二段为载荷(Payload)
  3. 第三段为签名(Signature)

每一段内容都是一个 JSON 对象, 将每一段 JSON 对象采用 BASE64 编码,
将编码后的内容用 . 链接一起就构成了 JWT 字符串;

例如:
header.payload.signature
xxxx.yyyy.zzzz

1. Header

由两部分组成: token 的类型(“JWT”)和算法名称(比如: HMAC SHA256 或者 RSA 等等);
然后, 用 Base64 对这个 JSON 编码就得到 JWT 的第一部分

头部用于描述关于该 JWT 的最基本的信息, 例如其类型以及签名所用的算法等;
这也可以被表示成一个 JSON 对象

1
2
3
4
{
"typ": "JWT",
"alg": "HS256"
}

HS256
指的是使用 HMAC SHA256 签名算法

2. Payload

也是一个 JSON 对象, 用来存放实际需要传递的数据;

可以根据需要自定义需要放置的内容

载荷就是存放有效信息的地方; 有效信息包含三个部分:
标准中注册的声明
公共的声明
私有的声明

分为三种类型

  1. registered claims 标准声明(建议但不强制使用)
    一般常用于校验的有 iat, exp, nbf 校验 token 是否过期
    iss: jwt 签发者
    sub: jwt 所面向的用户
    aud: 接收 jwt 的一方
    exp: jwt 的过期时间, 这个过期时间必须要大于签发时间
    nbf: 定义在什么时间之前, 该 jwt 都是不可用的.
    iat: jwt 的签发时间
    jti: jwt 的唯一身份标识, 主要用来作为一次性 token,从而回避重放攻击

  2. public claims 公开声明
    可以添加任意信息, 一般添加用户的相关信息或其他业务需要的必要信息, 比如 userid 等,
    但注意不要添加敏感信息, 因为该部分在客户端可解密, 不是信息安全的

  3. private claims 私密声明
    双方约定的信息

    私有声明是提供者和消费者所共同定义的声明,
    一般不建议存放敏感信息, 因为 base64 是对称解密的, 意味着该部分信息可以归类为明文信息;
    一般放置个性化数据, 减少查库次数

示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
{
    "iss": "Online JWT Builder",
    "iat": 1416797419,
    "exp": 1448333419,
    "aud": "www.primeton.com",
    "sub": "devops@primeton.com",
    "GivenName": "dragon",
    "Surname": "wang",
    "admin": true
}
1
2
3
4
5
{
    "sub": "xxxxx",
    "uid": "10001",
    "admin": true
}

3. Signature 签名

Base64(header).Base64(payload) + head 中定义的算法 + 密钥 生成一个字符串

即将 Base64(header) 和 Base64(payload) 使用 ‘.’ 连接组成的字符串;

然后使用 head 中定义的加密算法和盐进行加密,就构成了 jwt 的第三部分;

比如:
HMACSHA256(base64UrlEncode(header) + “.” + base64UrlEncode(payload), secret)


JWT 认证流程

  1. 客户端调用登录接口(或者获取 token 接口), 传入用户名密码

  2. 服务端请求身份认证中心, 确认用户名密码正确

  3. 服务端创建 JWT, 返回给客户端

  4. 客户端拿到 JWT, 进行存储
    (可以存储在缓存中, 也可以存储在数据库中, 如果是浏览器, 可以存储在 Cookie 中或 localStorage)
    在后续请求中, 在 HTTP 请求头中加上 JWT;
    可以把它放在 Cookie 里面自动发送, 但是这样不能跨域, 所以更好的做法是放在 HTTP 请求的头信息 Authorization 字段里面
    // Authorization: Bearer <token>

    另一种做法是, 跨域的时候, JWT 就放在 POST 请求的数据体里面

  5. 服务端校验 JWT, 校验通过后, 返回相关资源和数据;


http header 头位置

通常放在 Authorization header 中,如: \

1
Authorization: Bearer <token>

微信搜索IT运维小秋

Licensed under CC BY-NC-SA 4.0
转载或引用本文时请遵守许可协议,知会作者并注明出处
不得用于商业用途!
最后更新于 2023-02-10 00:00 UTC