官网:

https://jwt.io/#debugger

JWT 安全认证

1. 介绍

JSON Web Token(JWT)是目前最流行的跨域身份验证解决方案,是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519)。JWT默认不加密,但可以加密。生成原始令牌(token)后,可以使用改令牌再次对其进行加密。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,其中token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的原则是在服务器身份验证之后,将生成一个JSON对象并将其发送回用户,一般是将它放入HTTP请求的Header Authorization字段中。

通俗来讲,JWT是一个含签名并携带用户相关信息的加密串,页面请求校验登录接口时,请求头中携带JWT串到后端服务,后端通过签名加密串匹配校验,保证信息未被篡改。校验通过则认为是可靠的请求,将正常返回数据。

2.JWT用处:

授权:这是最常见的使用场景,解决单点登录问题。因为JWT使用起来轻便,开销小,服务端不用记录用户状态信息(无状态),所以使用比较广泛;

信息交换:JWT是在各个服务之间安全传输信息的好方法。因为JWT可以签名,例如,使用公钥/私钥对儿 - 可以确定请求方是合法的。此外,由于使用标头和有效负载计算签名,还可以验证内容是否未被篡改。

3.JWT的数据结构

JWT对象为一个长字串,各字串之间也没有换行符,通过”.”分隔。总共有三个子串,每一个子串表示了一个功能块,JWT的三个部分为JWT头、有效载荷和签名,将它们写成一行格式如下。

xxx.yyy.zzz

1 JWT头

JWT头部分是一个描述JWT元数据的JSON对象,由两部分组成,令牌类型(即:JWT)、散列算法(HMAC、RSASSA、RSASSA-PSS等)。alg属性表示签名使用的算法,为HMAC SHA256(写为HS256);typ属性表示令牌的类型,JWT令牌统一写为JWT。

{
    "alg": "HS256",
    "typ": "JWT"
}

2 有效载荷

是 JWT 的主体,包含claims的 JSON 对象。

claims是关于实体(常用的是用户信息)和其他数据的声明,claims有三种类型:

  • registered claims(标准注册声明)
  • public claims(公共声明)
  • private claims(私有声明)

Registered claims:
这些是一组预定义的claims,非强制性的,常用属性如下:(全部属性)

JWT 规定了7个Registered claims

  1. iss (issuer):签发人
  2. exp (expiration time):过期时间
  3. sub (subject):主题
  4. aud (audience):受众 用户id
  5. nbf (Not Before):生效时间 在此之前不可用
  6. iat (Issued At):签发时间
  7. jti (JWT ID):编号 JWT ID用于标识该JWT

Public claims 和 Private claims:
这些是自定义的claims,用于传递不同系统间可以共享的数据。
但是,默认情况下JWT是未加密的,任何人都可以解读其内容,因此不要构建隐私信息字段,存放保密信息,以防止信息泄露。

{
"sub": "1234567890",
"name": "admin",
"admin": true
}

3 签名哈希

签名哈希部分是对上面两部分数据签名,通过指定的算法生成哈希,以确保数据不会被篡改。

若使用标头中指定的签名算法(默认情况下为HMAC SHA256),需要指定一个密码(secret)保存在服务器中,且不能向用户公开。根据以下公式生成签名。

HMACSHA256(
  base64UrlEncode(header) + "." +
    base64UrlEncode(payload),
    secret
)

若使用私钥签名令牌(RSA非对称加密),公钥保存在其他系统中,它还可以验证JWT的签发身份是否是它所声明的。

在计算出签名哈希后,JWT头,有效载荷和签名哈希的三个部分组合成一个字符串,每个部分用”.”分隔,构成整个JWT对象。

Base64URL算法和常见Base64算法类似,但由于 Base64中用的三个字符是”+”,”/“和”=”,由于在URL中有特殊含义,因此Base64URL中对他们做了替换:”=“去掉,”+“用”-“替换,”/“用”_”替换。

4. JWT的用法

客户端接收服务器返回的JWT,将其存储在Cookie或localStorage中。

此后,客户端将在与服务器交互中都会带JWT。如果将它存储在Cookie中,就可以自动发送,但是不会跨域,因此一般是将它放入HTTP请求的Header Authorization字段中。(默认“Beear ”开头)

Authorization: Bearer

5. JWT 注意事项

1、JWT默认不加密,但可以加密。生成原始令牌后,可以使用改令牌再次对其进行加密。所以在JWT没有再次加密的情况下,JWT的信息不是私密的。
2、为了减少盗用和窃取的可能,JWT不建议使用HTTP协议来传输代码,而是使用加密的HTTPS协议进行传输。
3、JWT的最大缺点是服务器不保存会话状态,所以在使用期间不可能取消令牌或更改令牌的权限。也就是说,一旦JWT签发,在有效期内将会一直有效。
4、JWT本身包含认证信息,因此一旦信息泄露,任何人都可以获得令牌的所有权限。为了减少盗用,JWT的有效期(expiretime)不宜设置太长。对于某些重要操作,用户在使用时应该每次都进行进行身份验证。
5.token添加expiretime,决定token是否过期。当业务方访问的一个token的租约快要过期时,系统会自动给token续租。仅在token生成后,一个租约的时间内没有任何业务方访问时,该token才会失效,这样不会导致用户在使用中会突然掉线的情况。

6. 认证与授权

认证: 是用户信息的验证(通常是登录信息/密码对).
授权: 是指给个人或群体执行特定操作的权限, 是检查用户是否有权访问特定资源的程序.
正常的认证与授权过程:

用户向服务器发送认证数据(登录信息/密码对), 即 认证处理.
如果数据正确, 服务器使用必要的信息(身份id, 权限, token 生命周期等)生成 jwt token.
用户每次向服务器发送请求都要携带接收到的 token.
服务器基于 token 中包含的信息(权限, 生命周期等)决定是否给用户相应的访问权限.

7. Refresh Token

为了实现不保存用户数据也能够更新 jwt, 需要引入新的概念, 例如 Refresh Token.
认证 token 被称为 Access Token, 用来更新 Access Token 的第二 token 被称为Refresh Token. 将其保存在客户端, 代替登录信息/密码对.
Refresh 通常比 Access Token “存活”的时间长, 例如一个月或两个月.
我们将 Refresh Token 存放在数据库, 每次客户端需要更新 Access Token 我们就验证它. 它是一个随机生成的字符串(例如: Lxd6bj7w33GEX1GOSgzCNZWNSMskaUmPwgG6uM)

8. Refresh Token 更新

客户端通过登录信息/密码对进行验证.
如果成功, 服务器创建新的 Access TokenRefresh Token, Refresh Token 和 他的生命周期一起存放到数据库.
服务器以这个形式响应给客户端:

{
     "expired_at": ...,
     "access_token": ...,
     "refresh_token": ...
 }  

客户端保存这些信息.
每次请求前, 客户端检测 Access Token 是否过期. 如果未过期, 请求携带 token 一起发送.
为了刷新token, 客户端发送 Refresh Token 到指定的 api 路径(例如: /v1/account/refresh-token).
服务器通过查询数据库, 对比发送的 refresh token 是否正确, 并且检测是否过期.
如果 refresh token 过期, 或者数据库不存在此 token, 则取消认证并向客户端返回 401 错误.
如果 refresh token 存在并且未过期, 则创建新的 access token 并更新 refresh token, 以 步骤3 的格式返回给客户端.
客户端现在可以通过新的 access token 继续进行请求操作.

参考文档:
在gin框架中使用JWT:
https://www.liwenzhou.com/posts/Go/json-web-token/
一步一步教你实现JWT安全认证:
https://blog.csdn.net/xmcy001122/article/details/126501371
https://blog.csdn.net/qq_40382179/article/details/105979488

作者:admin  创建时间:2022-12-01 21:43
最后编辑:admin  更新时间:2024-05-10 15:32