用u盘做网站,手机移动端网站怎么做,画册设计理念和设计思路,网站报价内容AI图像生成网站
目录
一、项目介绍
二、雪花算法
三、JWT认证与令牌桶算法
四、项目架构
五、图床上传与图像生成API搭建
六、项目测试与调试(等待更新) 三、JWT认证与令牌桶算法
在现代后端开发中#xff0c;用户认证和接口限流是确保系统安全性和性能的两大关键要素…AI图像生成网站
目录
一、项目介绍
二、雪花算法
三、JWT认证与令牌桶算法
四、项目架构
五、图床上传与图像生成API搭建
六、项目测试与调试(等待更新) 三、JWT认证与令牌桶算法
在现代后端开发中用户认证和接口限流是确保系统安全性和性能的两大关键要素。本文将基于实际代码介绍 JWT 认证 和 令牌桶限流算法 的原理和实现。 1. JWT认证
JWTJSON Web Token是一种开放标准RFC 7519定义了一种紧凑的、自包含的方式用于在各方之间安全地传输信息。这些信息经过签名验证后可以信任其真实性。它通常用于用户认证场景流程如下
用户登录成功后服务器生成一个JWT并返回给客户端。客户端每次访问受保护的接口时将JWT放入请求头中。服务器解析JWT验证用户身份。
一个典型的JWT由三部分组成
Header描述加密算法类型如 HS256。Payload有效载荷实际数据例如用户信息和 Token 过期时间。Signature通过密钥和 Header、Payload 签名生成用于验证数据的完整性。 JWT 的标准声明只包含一些通用字段如 exp、iat1但在实际应用中我们需要存储更多的业务数据比如用户 ID 和用户名。 在 JWT 中Payload 就是 Token 的核心数据部分用来存储那些需要在两方之间传递的信息。它包含了自定义的声明Claims例如用户的标识user_id或过期时间exp。Payload 不会被加密但会被签名以保证数据的完整性。我们可以自定义结构体 MyClaims来实现自定义声明
type MyClaims struct {UserID uint64 json:user_idUsername string json:usernamejwt.StandardClaims
}之后我们需要生成Access Token和Refresh Token来减少用户的重复登录行为从而在保证安全性的同时提高交互体验具体交互过程为 用户登录阶段
用户在登录页面输入用户名和密码。服务器验证用户的身份后生成并返回 一个短期有效的 Access Token。一个长期有效的 Refresh Token。 客户端存储 Token通常 Access Token 存在内存中Refresh Token 存在安全存储区。
生成 Access Token 和 Refresh Token 的函数如下
// 定义Secret 用于加密的字符串
var mySecret []byte(aidraw)func GenToken(userID uint64, username string) (aToken, rToken string, err error) {c : MyClaims{UserID: userID,Username: username,StandardClaims: jwt.StandardClaims{ExpiresAt: time.Now().Add(AccessTokenExpireDuration).Unix(),Issuer: aidraw,},}aToken, err jwt.NewWithClaims(jwt.SigningMethodHS256, c).SignedString(mySecret)rToken, err jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.StandardClaims{ExpiresAt: time.Now().Add(RefreshTokenExpireDuration).Unix(),Issuer: aidraw,}).SignedString(mySecret)return
}
与网站交互阶段
初始请求客户端将 Access Token 添加到每个请求的 HTTP 头部Authorization: Bearer Access Token。服务器解析 Token 并验证用户身份。
解析Token的代码为
func keyFunc(_ *jwt.Token) (i interface{}, err error) {return mySecret, nil
}// ParseToken 解析Token.
func ParseToken(tokenString string) (claims *MyClaims, err error) {claims new(MyClaims)token, err : jwt.ParseWithClaims(tokenString, claims, keyFunc)if err ! nil {return}if !token.Valid {err errors.New(invalid token)}return
}
Access Token 过期当 Access Token 失效时客户端会用 Refresh Token 请求新的 Access Token。
刷新Token的代码为
func RefreshToken(aToken, rToken string) (newAToken, newRToken string, err error) {// 验证 Refresh Token 是否有效if _, err jwt.Parse(rToken, keyFunc); err ! nil {return}// 解析 Access Token 提取用户信息var claims MyClaims_, err jwt.ParseWithClaims(aToken, claims, keyFunc)v, _ : err.(*jwt.ValidationError)// 如果 Access Token 是过期错误生成新的 Tokenif v.Errors jwt.ValidationErrorExpired {return GenToken(claims.UserID, claims.Username)}return
}
刷新 Token 过程 1. 客户端发送 Refresh Token 给 /refresh_token API。 2. 服务器验证 Refresh Token 是否有效。 3. 如果 Refresh Token 合法且未过期生成新的 Access Token 和 新的 Refresh Token。
2. 基于 JWT 的认证中间件
为了在路由处理函数中提取用户信息我们需要实现一个基于 JWT 的 Gin 中间件:
从请求头的 Authorization 字段提取 Token。验证 Token 的合法性。将解析出的用户信息保存到上下文中供后续的路由函数使用。 代码如下
package middlewaresimport (backend/controllerbackend/pkg/jwtfmtstringsgithub.com/gin-gonic/gin
)// JWTAuthMiddleware 基于JWT的认证中间件
func JWTAuthMiddleware() func(c *gin.Context) {return func(c *gin.Context) {// 客户端携带Token有三种方式 1.放在请求头 2.放在请求体 3.放在URI// 这里假设Token放在Header的Authorization中并使用Bearer开头// 这里的具体实现方式要依据你的实际业务情况决定authHeader : c.Request.Header.Get(Authorization)if authHeader {controller.ResponseErrorWithMsg(c, controller.CodeInvalidToken, 请求头缺少Auth Token)c.Abort()return}// 按空格分割parts : strings.SplitN(authHeader, , 2)if !(len(parts) 2) {controller.ResponseErrorWithMsg(c, controller.CodeInvalidToken, Token格式不对)c.Abort()return}// parts[1]是获取到的tokenString我们使用之前定义好的解析JWT的函数来解析它mc, err : jwt.ParseToken(parts[1])if err ! nil {fmt.Println(err)controller.ResponseError(c, controller.CodeInvalidToken)c.Abort()return}// 将当前请求的userID信息保存到请求的上下文c上c.Set(controller.ContextUserIDKey, mc.UserID)c.Next() // 后续的处理函数可以用过c.Get(ContextUserIDKey)来获取当前请求的用户信息}
} 3. 令牌桶限流算法
在现代 Web 开发中流量控制是确保系统稳定性的重要手段之一。令牌桶算法Token Bucket Algorithm是一种广泛使用的限流算法可以高效处理突发流量。其核心思想如下
固定速率发放令牌按照指定的时间间隔将令牌加入桶中。允许突发流量桶有一个固定的容量当令牌数量达到容量时新的令牌会被丢弃。请求消耗令牌每次请求需要消耗一定数量的令牌如果桶中没有足够的令牌请求将被拒绝或等待。
适用于需要控制 API 的访问频率、允许短时间内的突发请求如秒杀活动的场景。
令牌桶中间件实现
实现令牌桶限流中间件代码如下
package middlewaresimport (github.com/gin-gonic/gingithub.com/juju/ratelimitnet/httptime
)// RateLimitMiddleware 创建指定填充速率和容量大小的令牌桶
func RateLimitMiddleware(fillInterval time.Duration, cap int64) func(c *gin.Context) {// 创建令牌桶bucket : ratelimit.NewBucket(fillInterval, cap)return func(c *gin.Context) {// 检查是否能够获取令牌if bucket.TakeAvailable(1) 0 {// 如果令牌不足返回限流提示c.String(http.StatusOK, rate limit...)c.Abort() // 中断请求return}// 如果获取到令牌继续处理请求c.Next()}
}
参数说明
fillInterval令牌添加的时间间隔。cap桶的容量。
调用代码
本项目通过在所有路由之前设置令牌桶中间件实现了全局限流
//初始化 gin Engine 新建一个没有任何默认中间件的路由
r : gin.New()
//设置中间件
r.Use(middlewares.RateLimitMiddleware(2*time.Second, 40), // 每两秒钟添加十个令牌 全局限流
)r.LoadHTMLFiles(templates/index.html) // 加载htmlexp 和 iat 是 JWT 中的标准声明字段Standard Claims。这些字段遵循 RFC 7519 的规范表示 Token 的时间相关信息。 expExpiration Time表示 Token 的过期时间。单位为秒自 Unix 时间纪元1970-01-01 00:00:00 UTC以来的秒数。当客户端请求到达服务器时如果当前时间大于 expToken 会被判定为无效。例如1699844000 表示过期时间是 2023-11-12 10:00:00 UTC。 iatIssued At表示 Token 签发的时间。单位同样为秒用于标识 Token 的创建时间。它可以用来防止 Token 重放攻击Replay Attack。 ↩︎