实战:Go语言项目之使用JWT实现用户认证
基于cookie-Session 和基于token的认证模式
需求:请求分类
用户认证
HTTP 是一个无状态的协议,一次请求结束后,下次再发送,服务器就不知道这个请求是谁发过来的(同一个 IP 不代表同一个用户),在Web 应用中,用户的认证和鉴权是非常重要的一环,实践中有多种实现方案,各有千秋。
Cookie - Session 认证模式
在 Web 应用发展的初期,大部分采用基于 Cookie - Session 的会话管理方式。逻辑如下:
- 客户端使用用户名、密码进行认证
- 服务端验证用户名、密码正确后生成并存储 Session,将SessionID 通过 Cookie 返回给客户端
- 客户端访问需认证的接口时在 Cookie 中携带 SessionID
- 服务端通过 SessionID 查找 Session 并进行鉴权,返回给客户端需要的数据
基于 Session 的方式存在多种问题
- 服务端需要存储 Session,并且由于 Session 需要经常快速查找,通常存储在内存或内存数据库中,同时在线用户较多时需要占用大量的服务器资源。
- 当需要扩展时,创建 Session 的服务器可能不是验证 Session 的服务器,所以还需要将所有Session 单独存储并共享。
- 由于客户端使用 Cookie 存储 SessionID,在跨域场景下需要进行兼容性处理,同时这种方式也难以防范CSRF 攻击。
Token 认证模式
鉴于基于 Session 的会话管理方式存在上述多个缺点,基于 Token 的无状态会话管理方式诞生了,所谓无状态,就是服务端可以不再存储信息,甚至是不再存储Session。逻辑如下:
- 客户端使用用户名、密码进行认证
- 服务端验证用户名、密码正确后生成 Token 返回给客户端
- 客户端保存 Token,访问需要认证的接口时在 URL 参数或 HTTP Header 中加入 Token
- 服务端通过解码 Token 进行鉴权,返回给客户端需要的数据
基于 Token 的会话管理方式有效解决了基于 Session 的会话管理方式带来的问题。
- 服务端不需要存储和用户鉴权有关的信息,鉴权信息会被加密到 Token 中,服务端只需要读取 Token 中包含的鉴权信息即可
- 避免了共享 Session 导致的不易扩展问题
- 不需要依赖 Cookie,有效避免 Cookie 带来的 CSRF 攻击问题
- 使用 CORS 可以快速解决跨域问题
JWT 介绍
JWT 文档:https://jwt.io/introduction
JWT 是 JSON Web Token 的缩写,是为了在网络应用环境间传递声明而执行的一种基于 JSON 的开放标准((RFC 7519)。JWT 本身没有定义任何技术实现,它只是定义了一种基于 Token 的会话管理的规则,涵盖 Token 需要包含的标准内容和 Token 的生成过程,特别适用于分布式站点的单点登录(SSO)场景。
JSON Web Token (JWT)是一个开放标准(RFC 7519) ,它定义了一种紧凑和自包含的方式,用于作为 JSON 对象在各方之间安全地传输信息。此信息可以进行验证和信任,因为它是经过数字签名的。JWT 可以使用机密(使用 HMAC 算法)或使用 RSA 或 ECDSA 的公钥/私钥对进行签名。
虽然可以对 JWT 进行加密,以便在各方之间提供保密性,但是我们将重点关注已签名的令牌。签名令牌可以验证其中包含的声明的完整性,而加密令牌可以向其他方隐藏这些声明。当使用公钥/私钥对对令牌进行签名时,该签名还证明只有持有私钥的一方才是对其进行签名的一方。
下面是 JSON Web 令牌非常有用的一些场景:
- Authorization 授权: 这是使用 JWT 最常见的场景。一旦用户登录,每个后续请求都将包含 JWT,允许用户访问该令牌所允许的路由、服务和资源。单点登录是目前广泛使用 JWT 的一个特性,因为它的开销很小,而且能够很容易地跨不同域使用。
- Information Exchange 信息交换: JSON Web 令牌是在各方之间安全传输信息的好方法。因为可以对 JWT 进行签名(例如,使用公钥/私钥对) ,所以可以确保发件人就是他们所说的那个人。此外,由于签名是使用头和有效负载计算的,因此还可以验证内容是否被篡改。
一个 JWT Token 就像这样:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
JSON Web Token由以点(.)分隔的三个部分组成,它们是:
- Header 头部
- Payload 负载
- Signature 签名
因此,JWT 通常如下所示。
xxxxx.yyyyy.zzzzz
Header
Header通常由两部分组成: 令牌的类型(即 JWT)和所使用的签名算法(如 HMAC SHA256或 RSA)。
For example:
{
"alg": "HS256",
"typ": "JWT"
}
然后,对这个 JSON 进行 Base64Url 编码,形成 JWT 的第一部分。
Payload
Payload 表示负载,也是一个 JSON 对象,JWT 规定了 7 个官方字段供选用:
iss (issuer):签发人
exp (expiration time):过期时间
sub (subject):主题
aud (audience):受众
"nbf" (Not Before):生效时间
"iat" (Issued At) :签发时间
"jti" (JWT ID):编号
https://datatracker.ietf.org/doc/html/rfc7519#section-4.1
除了官方字段,开发者也可以自己指定字段和内容,例如下面的内容。
{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}
然后对有效 payload 进行 Base64Url 编码,形成 JSON Web Token的第二部分。
请注意,对于已签名的令牌,这些信息虽然受到保护,不会被篡改,但任何人都可以阅读。除非加密,否则不要将机密信息放在 JWT 的有效负载或头元素中。
Signature
signature 部分是对前两部分的签名,防止数据篡改。
首先需要指定一个密钥(secret)。这个密钥只有服务器才知道,不能泄漏给用户。然后使用Header 里面指定的签名算法(默认是 HMAC SHA256)。
To create the signature part you have to take the encoded header, the encoded payload, a secret, the algorithm specified in the header, and sign that.
要创建签名部分,您必须获取编码的标头、编码的有效载荷、秘密、标头中指定的算法,并对其进行签名。
例如,如果您想使用 HMAC SHA256算法,签名将按以下方式创建:
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
该签名用于验证消息在执行过程中没有被更改,并且,对于使用私钥签名的令牌,它还可以验证 JWT 的发送方是否就是它所说的那个人。
Putting all together
输出是三个由点分隔的 Base64-URL 字符串,这些字符串可以在 HTML 和 HTTP 环境中轻松传递,同时与基于 XML 的标准(如 SAML)相比更加紧凑。
The following diagram shows how a JWT is obtained and used to access APIs or resources:
- The application or client requests authorization to the authorization server. This is performed through one of the different authorization flows. For example, a typical OpenID Connect compliant web application will go through the
/oauth/authorize
endpoint using the authorization code flow. - When the authorization is granted, the authorization server returns an access token to the application.
- The application uses the access token to access a protected resource (like an API).
JWT 优缺点
JWT 拥有基于 Token 的会话管理方式所拥有的一切优势,不依赖 Cookie,使得其可以防止 CSRF 攻击,也能在禁用 Cookie 的浏览器环境中正常运行。
而 JWT 的最大优势是服务端不再需要存储 Session,使得服务端认证鉴权业务可以方便扩展,避免存储 Session 所需要引入的 Redis 等组件,降低了系统架构复杂度。但这也是 JWT 最大的劣势,由于有效期存储在 Token 中,JWT Token 一旦签发,就会在有效期内一直可用,无法在服务端废止,当用户进行登出操作,只能依赖客户端删除掉本地存储的 JWT Token,如果需要禁用用户,单纯使用 JWT 就无法做到了。
基于 JWT 实现认证实践
前面说的 Token,都是 Access Token,也就是访问资源接口时所需要的 Token,还有另外一种 Token,Refresh Token,通常情况下,Refresh Token 的有效期会比较长,而 Access Token 的有效期比较短,当 Access Token 由于过期而失效时,使用 Refresh Token 就可以获取到新的 Access Token,如果 Refresh Token 也失效了,用户就只能重新登陆了。
使用JWT实现用户认证
golang-jwt:https://github.com/golang-jwt/jwt
安装指南
- 要安装 jwt 包,首先需要安装 Go,然后可以使用下面的命令在 Go 程序中添加 jwt-Go 作为依赖项。
go get -u github.com/golang-jwt/jwt/v5
- Import it in your code:
import "github.com/golang-jwt/jwt/v5"
golang-jwt docs:https://golang-jwt.github.io/jwt/usage/create/
https://github.com/appleboy/gin-jwt
项目实操
项目目录
goblog on main [!?] via
标签:err,jwt,JWT,认证,go,Token,Go,gin
From: https://www.cnblogs.com/QiaoPengjun/p/18630890