[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"article-24":3},{"id":4,"title":5,"title_en":6,"abstract":7,"abstract_en":8,"content":9,"content_en":10,"category":11,"banner_id":12,"banner_path":13,"tags":14,"is_recommend":17,"prev_article":18,"next_article":22,"created_at":26},24,"JWT (JSON Web Token) 技术指南","JWT (JSON Web Token) Technical Guide","## 什么是JWT？\n\nJWT是一种开放标准（RFC 7519），用于在各方之间安全地传输信息。它是","What is JWT?\n\nJWT is an open standard (RFC 7519) used to securely transfer information between parties. It is","## 什么是JWT？\n\nJWT是一种开放标准（RFC 7519），用于在各方之间安全地传输信息。它是一个紧凑的、URL安全的令牌，通常用于身份验证和信息交换。\n\n在现代Web应用中，JWT已成为无状态身份认证的首选方案，特别适合微服务架构和API服务。\n\n## JWT结构\n\nJWT由三部分组成，用点（.）分隔：\n\n```\nheader.payload.signature\n```\n\n### 1. Header（头部）\n包含令牌类型和签名算法信息：\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n```\n\n### 2. Payload（载荷）\n包含声明（claims），即实际要传输的数据：\n```json\n{\n  \"sub\": \"1234567890\",\n  \"name\": \"用户名\",\n  \"role\": \"admin\",\n  \"iat\": 1516239022,\n  \"exp\": 1516242622\n}\n```\n\n### 3. Signature（签名）\n用于验证令牌的完整性：\n```\nHMACSHA256(\n  base64UrlEncode(header) + \".\" +\n  base64UrlEncode(payload),\n  secret\n)\n```\n\n## 常用声明类型\n\n### 标准声明\n- `iss` (issuer): 签发者\n- `sub` (subject): 主题\n- `aud` (audience): 受众\n- `exp` (expiration): 过期时间\n- `iat` (issued at): 签发时间\n- `nbf` (not before): 生效时间\n\n### 自定义声明\n可以添加任何自定义字段，如用户角色、权限等。\n\n## JWT的优势\n\n- **无状态**: 服务器不需要存储会话信息\n- **跨域支持**: 可以在不同域之间使用\n- **移动友好**: 适合移动应用和API\n- **性能好**: 避免了数据库查询\n- **标准化**: 基于开放标准\n\n## 使用场景\n\n### 1. 身份认证\n用户登录后获取JWT，后续请求携带此令牌进行身份验证。\n\n### 2. 信息交换\n在不同服务之间安全地传输信息。\n\n### 3. 单点登录(SSO)\n一次登录，多个应用共享认证状态。\n\n## 安全考虑\n\n### 存储安全\n- 避免存储在localStorage（XSS风险）\n- 推荐使用httpOnly Cookie\n- 考虑使用sessionStorage\n\n### 令牌安全\n- 设置合理的过期时间\n- 使用强密钥进行签名\n- 考虑令牌刷新机制\n- 实现令牌黑名单\n\n### 传输安全\n- 始终使用HTTPS\n- 在Authorization头中传输\n- 避免在URL中传输令牌\n\n## 项目架构设计\n\n### 双令牌机制\n本项目采用Access Token + Refresh Token的双令牌架构：\n\n- **Access Token**: 短期有效（配置化过期时间），用于API访问认证\n- **Refresh Token**: 长期有效（配置化过期时间），用于刷新Access Token\n\n### 核心组件\n\n#### 1. 配置管理\n```yaml\njwt:\n  access_expire: 24    # 小时\n  refresh_expire: 168  # 小时（7天）\n  access_secret: \"your-access-secret\"\n  refresh_secret: \"your-refresh-secret\"\n  issuer: \"your-app-name\"\n```\n\n#### 2. 声明结构设计\n```go\n\u002F\u002F Access Token声明\ntype AccessClaims struct {\n    UserID   uint   `json:\"user_id\"`\n    Username string `json:\"username\"`\n    Role     string `json:\"role\"`\n    jwt.RegisteredClaims\n}\n\n\u002F\u002F Refresh Token声明\ntype RefreshClaims struct {\n    UserID uint `json:\"user_id\"`\n    jwt.RegisteredClaims\n}\n```\n\n### 安全特性\n\n#### 1. 双密钥设计\n- Access Token和Refresh Token使用不同的签名密钥\n- 降低密钥泄露风险\n- 支持独立的密钥轮换策略\n\n#### 2. 令牌黑名单机制\n```go\n\u002F\u002F 添加令牌到黑名单\nfunc AddToBlacklist(token string, expiration time.Duration) error {\n    key := \"blacklist:\" + token\n    return redis.Set(key, \"1\", expiration).Err()\n}\n\n\u002F\u002F 检查令牌是否在黑名单中\nfunc IsBlacklisted(token string) bool {\n    key := \"blacklist:\" + token\n    _, err := redis.Get(key).Result()\n    return err == nil\n}\n```\n\n#### 3. 地理位置追踪\n登录时记录用户IP和地理位置信息，增强安全审计能力。\n\n## 中间件实现\n\n### 1. 基础认证中间件\n```go\nfunc AuthMiddleware() gin.HandlerFunc {\n    return func(c *gin.Context) {\n        token := c.GetHeader(\"Authorization\")\n        if token == \"\" {\n            c.JSON(401, gin.H{\"error\": \"未提供令牌\"})\n            c.Abort()\n            return\n        }\n        \n        \u002F\u002F 验证令牌\n        claims, err := ValidateToken(token)\n        if err != nil {\n            c.JSON(401, gin.H{\"error\": \"无效令牌\"})\n            c.Abort()\n            return\n        }\n        \n        \u002F\u002F 检查黑名单\n        if IsBlacklisted(token) {\n            c.JSON(401, gin.H{\"error\": \"令牌已失效\"})\n            c.Abort()\n            return\n        }\n        \n        c.Set(\"user_id\", claims.UserID)\n        c.Next()\n    }\n}\n```\n\n### 2. 权限控制中间件\n```go\nfunc RequireRole(requiredRole string) gin.HandlerFunc {\n    return func(c *gin.Context) {\n        userRole, exists := c.Get(\"user_role\")\n        if !exists {\n            c.JSON(403, gin.H{\"error\": \"权限不足\"})\n            c.Abort()\n            return\n        }\n        \n        if userRole != requiredRole {\n            c.JSON(403, gin.H{\"error\": \"角色权限不足\"})\n            c.Abort()\n            return\n        }\n        \n        c.Next()\n    }\n}\n```\n\n### 3. 令牌刷新中间件\n- 验证Refresh Token有效性\n- 检查令牌黑名单状态\n- 提取用户身份信息\n- 为令牌刷新做准备\n\n## API设计模式\n\n### 1. 登录流程\n```go\nfunc Login(username, password string) (*TokenPair, error) {\n    \u002F\u002F 验证用户凭证\n    user, err := ValidateCredentials(username, password)\n    if err != nil {\n        return nil, err\n    }\n    \n    \u002F\u002F 生成Access Token\n    accessToken, err := GenerateAccessToken(user.ID, user.Role)\n    if err != nil {\n        return nil, err\n    }\n    \n    \u002F\u002F 生成Refresh Token\n    refreshToken, err := GenerateRefreshToken(user.ID)\n    if err != nil {\n        return nil, err\n    }\n    \n    return &TokenPair{\n        AccessToken:  accessToken,\n        RefreshToken: refreshToken,\n    }, nil\n}\n```\n\n### 2. 令牌刷新流程\n```go\nfunc RefreshToken(refreshToken string) (*TokenPair, error) {\n    \u002F\u002F 验证Refresh Token\n    claims, err := ValidateRefreshToken(refreshToken)\n    if err != nil {\n        return nil, err\n    }\n    \n    \u002F\u002F 检查黑名单\n    if IsBlacklisted(refreshToken) {\n        return nil, errors.New(\"令牌已失效\")\n    }\n    \n    \u002F\u002F 获取最新用户信息\n    user, err := GetUserByID(claims.UserID)\n    if err != nil {\n        return nil, err\n    }\n    \n    \u002F\u002F 生成新的令牌对\n    newAccessToken, _ := GenerateAccessToken(user.ID, user.Role)\n    newRefreshToken, _ := GenerateRefreshToken(user.ID)\n    \n    \u002F\u002F 将旧令牌加入黑名单\n    AddToBlacklist(refreshToken, time.Hour*24*7)\n    \n    return &TokenPair{\n        AccessToken:  newAccessToken,\n        RefreshToken: newRefreshToken,\n    }, nil\n}\n```\n\n### 3. 注销流程\n```go\nfunc Logout(accessToken, refreshToken string) error {\n    \u002F\u002F 解析令牌获取过期时间\n    accessClaims, _ := ParseToken(accessToken)\n    refreshClaims, _ := ParseToken(refreshToken)\n    \n    \u002F\u002F 计算剩余有效时间\n    accessTTL := time.Until(accessClaims.ExpiresAt.Time)\n    refreshTTL := time.Until(refreshClaims.ExpiresAt.Time)\n    \n    \u002F\u002F 添加到黑名单\n    AddToBlacklist(accessToken, accessTTL)\n    AddToBlacklist(refreshToken, refreshTTL)\n    \n    return nil\n}\n```\n\n## 实现最佳实践\n\n### 1. 令牌生命周期管理\n```go\n\u002F\u002F 令牌生成示例\nfunc GenerateAccessToken(userID uint, role string) (string, error) {\n    claims := AccessClaims{\n        UserID: userID,\n        Role:   role,\n        RegisteredClaims: jwt.RegisteredClaims{\n            ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * 24)),\n            IssuedAt:  jwt.NewNumericDate(time.Now()),\n            Issuer:    \"your-app\",\n        },\n    }\n    \n    token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)\n    return token.SignedString([]byte(\"your-secret\"))\n}\n```\n\n### 2. 错误处理策略\n```go\ntype APIError struct {\n    Code    int    `json:\"code\"`\n    Message string `json:\"message\"`\n    Details string `json:\"details,omitempty\"`\n}\n\nfunc HandleJWTError(err error) APIError {\n    switch {\n    case errors.Is(err, jwt.ErrTokenExpired):\n        return APIError{Code: 401, Message: \"令牌已过期\"}\n    case errors.Is(err, jwt.ErrTokenMalformed):\n        return APIError{Code: 401, Message: \"令牌格式错误\"}\n    default:\n        return APIError{Code: 401, Message: \"认证失败\"}\n    }\n}\n```\n\n### 3. 性能优化\n- Redis缓存用户信息\n- 令牌解析结果缓存\n- 批量令牌验证\n- 异步日志记录\n\n### 4. 监控和审计\n- 登录行为日志\n- 异常访问检测\n- 令牌使用统计\n- 地理位置异常告警\n\n## 常见问题与解决方案\n\n### Q: 如何处理令牌泄露？\n**解决方案**：\n- 实现Redis黑名单机制\n- 设置合理的令牌过期时间\n- 监控异常IP和地理位置访问\n- 支持用户主动注销所有设备\n\n### Q: 双令牌机制的优势？\n**优势**：\n- Access Token短期有效，降低泄露风险\n- Refresh Token长期有效，提升用户体验\n- 独立的密钥和过期策略\n- 支持细粒度的权限控制\n\n### Q: 如何实现跨设备登录管理？\n**实现方式**：\n- 令牌中包含设备标识信息\n- 缓存存储用户活跃设备列表\n- 支持远程设备注销\n- 可配置的设备数量限制\n\n### Q: 性能优化建议？\n**优化策略**：\n- 缓存用户权限信息\n- 令牌预验证机制\n- 批量令牌操作处理\n- 异步状态更新\n\n### Q: 如何处理时钟偏移问题？\n**解决方案**：\n- 设置合理的时钟偏移容忍度\n- 使用NTP同步服务器时间\n- 在令牌验证中增加时间缓冲\n- 监控服务器时间同步状态\n\n## 项目特色与优势\n\n### 1. 架构优势\n- **双令牌设计**：平衡安全性与用户体验\n- **配置化管理**：灵活的过期时间和密钥配置\n- **中间件模式**：统一的认证和授权处理\n- **Redis集成**：高性能的令牌状态管理\n\n### 2. 安全特性\n- **多层验证**：令牌有效性 + 黑名单检查 + 角色权限\n- **地理位置追踪**：增强安全审计能力\n- **密钥分离**：Access和Refresh Token使用不同密钥\n- **渐进式过期**：支持优雅的令牌续期\n\n### 3. 运维友好\n- **详细日志**：完整的认证和授权日志记录\n- **错误处理**：统一的错误响应和异常处理\n- **监控支持**：内置的性能和安全监控点\n- **扩展性**：支持多种认证方式和权限模型\n","## What is JWT?\n\nJWT is an open standard (RFC 7519) used to securely transfer information between parties. It is a compact, URL-secure token commonly used for authentication and information exchange.\n\nIn modern web applications, JWT has become the preferred solution for stateless authentication, especially suitable for microservice architectures and API services.\n\n## JWT Structure\n\nThe JWT consists of three parts, separated by dots (.):\n\n```\nheader.payload.signature\n```\n\n### 1. Header\nContains token type and signature algorithm information:\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n```\n\n### 2. Payload\nContains claims, i.e. the data that is actually to be transferred:\n```json\n{\n  \"sub\": \"1234567890\",\n  \"name\": \"username\",\n  \"role\": \"admin\",\n  \"iat\": 1516239022,\n  \"exp\": 1516242622\n}\n```\n\n### 3. Signature\nUsed to verify the integrity of the token:\n```\nHMACSHA256(\n  base64UrlEncode(header) + \".\" +\n  base64UrlEncode(payload),\n  secret\n)\n```\n\n## Common Claim Types\n\n### Standard Statement\n- 'iss' (issuer): issuer\n- 'sub' (subject): Subject\n- 'aud' (audience): Audience\n- 'exp' (expiration): Expiration time\n- 'iat' (issued at): The time of issue\n- 'nbf' (not before): effective time\n\n### Custom Statements\nAny custom fields can be added, such as user roles, permissions, etc.\n\n## Advantages of JWT\n\n- **Stateless**: The server does not need to store session information\n- **Cross-Domain Support**: Can be used between different domains\n- **Mobile-Friendly**: Suitable for mobile apps and APIs\n- **Good Performance**: Avoids database queries\n- **Standardization**: Based on open standards\n\n## Usage Scenarios\n\n### 1. Identity authentication\nThe user logs in to obtain the JWT and subsequently requests to carry this token for authentication.\n\n### 2. Information exchange\nSecurely transfer information between different services.\n\n### 3. Single Sign-On (SSO)\nLog in once, and multiple apps share the authentication status.\n\n## Security Considerations\n\n### Storage security\n- Avoid storing in localStorage (XSS risk)\n- httpOnly cookies are recommended\n- Consider using sessionStorage\n\n### Token Security\n- Set a reasonable expiration time\n- Sign with a strong key\n- Consider the token refresh mechanism\n- Implement token blacklists\n\n### Transmission Security\n- Always use HTTPS\n- Transfer in the Authorization header\n- Avoid transferring tokens in URLs\n\n## Project Architecture Design\n\n### Dual token mechanism\nThis project adopts a dual-token architecture of Access Token + Refresh Token:\n\n- Access Token: Short-term validity (configured expiration time) for API access authentication\n- **Refresh Token**: Long-term validity (configured expiration time) to refresh the Access Token\n\n### Core Components\n\n#### 1. Configuration management\n```yaml\njwt:\n  access_expire: 24# hours\n  refresh_expire: 168 # hours (7 days)\n  access_secret: \"your-access-secret\"\n  refresh_secret: \"your-refresh-secret\"\n  issuer: \"your-app-name\"\n```\n\n#### 2. Declare the structural design\n```go\nAccess Token statement\ntype AccessClaims struct {\n    UserID   uint   `json:\"user_id\"`\n    Username string `json:\"username\"`\n    Role     string `json:\"role\"`\n    jwt. RegisteredClaims\n}\n\nRefresh Token statement\ntype RefreshClaims struct {\n    UserID uint `json:\"user_id\"`\n    jwt. RegisteredClaims\n}\n```\n\n### Security features\n\n#### 1. Dual-key design\n- Access Token and Refresh Token use different signing keys\n- Reduce the risk of key compromise\n- Support for independent key rotation policies\n\n#### 2. Token blacklist mechanism\n```go\nAdd a token to the blacklist\nfunc AddToBlacklist(token string, expiration time. Duration) error {\n    key := \"blacklist:\" + token\n    return redis. Set(key, \"1\", expiration). Err()\n}\n\nCheck if the token is on the blacklist\nfunc IsBlacklisted(token string) bool {\n    key := \"blacklist:\" + token\n    _, err := redis. Get(key). Result()\n    return err == nil\n}\n```\n\n#### 3. Geolocation tracking\nRecord user IP and geographical location information when logging in to enhance security auditing capabilities.\n\n## Middleware implementation\n\n### 1. Basic certification middleware\n```go\nfunc AuthMiddleware() gin. HandlerFunc {\n    return func(c *gin. Context) {\n        token := c.GetHeader(\"Authorization\")\n        if token == \"\" {\n            c.JSON(401, gin. H{\"error\": \"Token not provided\"})\n            c.Abort()\n            return\n        }\n        \n        Validate the token\n        claims, err := ValidateToken(token)\n        if err != nil {\n            c.JSON(401, gin. H{\"error\": \"Invalid token\"})\n            c.Abort()\n            return\n        }\n        \n        Check the blacklist\n        if IsBlacklisted(token) {\n            c.JSON(401, gin. H{\"error\": \"Token has expired\"})\n            c.Abort()\n            return\n        }\n        \n        c.Set(\"user_id\", claims. UserID)\n        c.Next()\n    }\n}\n```\n\n### 2. Privilege control middleware\n```go\nfunc RequireRole(requiredRole string) gin. HandlerFunc {\n    return func(c *gin. Context) {\n        userRole, exists := c.Get(\"user_role\")\n        if !exists {\n            c.JSON(403, gin. H{\"error\": \"Insufficient permissions\"})\n            c.Abort()\n            return\n        }\n        \n        if userRole != requiredRole {\n            c.JSON(403, gin. H{\"error\": \"Insufficient Role Privileges\"})\n            c.Abort()\n            return\n        }\n        \n        c.Next()\n    }\n}\n```\n\n### 3. Token refresh middleware\n- Verify the validity of the Refresh Token\n- Check the token blacklist status\n- Extract user identification information\n- Prepare for token refreshes\n\n## API Design Patterns\n\n### 1. Login process\n```go\nfunc Login(username, password string) (*TokenPair, error) {\n    Verify user credentials\n    user, err := ValidateCredentials(username, password)\n    if err != nil {\n        return nil, err\n    }\n    \n    Generate an Access Token\n    accessToken, err := GenerateAccessToken(user.ID, user. Role)\n    if err != nil {\n        return nil, err\n    }\n    \n    Generate Refresh Token\n    refreshToken, err := GenerateRefreshToken(user.ID)\n    if err != nil {\n        return nil, err\n    }\n    \n    return &TokenPair{\n        AccessToken:  accessToken,\n        RefreshToken: refreshToken,\n    }, nil\n}\n```\n\n### 2. Token refresh process\n```go\nfunc RefreshToken(refreshToken string) (*TokenPair, error) {\n    Verify the Refresh Token\n    claims, err := ValidateRefreshToken(refreshToken)\n    if err != nil {\n        return nil, err\n    }\n    \n    Check the blacklist\n    if IsBlacklisted(refreshToken) {\n        return nil, errors. New(\"Token Expired\")\n    }\n    \n    Get the latest user information\n    user, err := GetUserByID(claims. UserID)\n    if err != nil {\n        return nil, err\n    }\n    \n    Generate a new token pair\n    newAccessToken, _ := GenerateAccessToken(user.ID, user. Role)\n    newRefreshToken, _ := GenerateRefreshToken(user.ID)\n    \n    Add old tokens to the blacklist\n    AddToBlacklist(refreshToken, time. Hour*24*7)\n    \n    return &TokenPair{\n        AccessToken:  newAccessToken,\n        RefreshToken: newRefreshToken,\n    }, nil\n}\n```\n\n### 3. Cancel the process\n```go\nfunc Logout(accessToken, refreshToken string) error {\n    Parse tokens to get expiration time\n    accessClaims, _ := ParseToken(accessToken)\n    refreshClaims, _ := ParseToken(refreshToken)\n    \n    Calculate the remaining valid time\n    accessTTL := time. Until(accessClaims.ExpiresAt.Time)\n    refreshTTL := time. Until(refreshClaims.ExpiresAt.Time)\n    \n    Add to the blacklist\n    AddToBlacklist(accessToken, accessTTL)\n    AddToBlacklist(refreshToken, refreshTTL)\n    \n    return nil\n}\n```\n\n## Implement best practices\n\n### 1. Token lifecycle management\n```go\nToken generation example\nfunc GenerateAccessToken(userID uint, role string) (string, error) {\n    claims := AccessClaims{\n        UserID: userID,\n        Role:   role,\n        RegisteredClaims: jwt. RegisteredClaims{\n            ExpiresAt: jwt. NewNumericDate(time. Now(). Add(time. Hour * 24)),\n            IssuedAt:  jwt. NewNumericDate(time. Now()),\n            Issuer:    \"your-app\",\n        },\n    }\n    \n    token := jwt. NewWithClaims(jwt. SigningMethodHS256, claims)\n    return token. SignedString([]byte(\"your-secret\"))\n}\n```\n\n### 2. Error handling strategy\n```go\ntype APIError struct {\n    Code    int    `json:\"code\"`\n    Message string `json:\"message\"`\n    Details string `json:\"details,omitempty\"`\n}\n\nfunc HandleJWTError(err error) APIError {\n    switch {\n    case errors. Is(err, jwt. ErrTokenExpired):\n        return APIError{Code: 401, Message: \"Token expired\"}\n    case errors. Is(err, jwt. ErrTokenMalformed):\n        return APIError{Code: 401, Message: \"Token Malform\"}\n    default:\n        return APIError{Code: 401, Message: \"Authentication failed\"}\n    }\n}\n```\n\n### 3. Performance optimization\n- Redis caches user information\n- Token parsing result caching\n- Bulk token validation\n- Asynchronous logging\n\n### 4. Monitoring and auditing\n- Log in behavior logs\n- Abnormal access detection\n- Token usage statistics\n- Geolocation anomaly alerts\n\n## Common Problems and Solutions\n\n### Q: How to deal with token leaks?\n**Solution**:\n- Implement Redis blacklist mechanism\n- Set a reasonable token expiration time\n- Monitor for anomalous IPs and geolocation access\n- Allow users to actively log out of all devices\n\n### Q: What are the advantages of the dual-token mechanism?\n**Advantage**:\n- Access Token is effective in the short term, reducing the risk of leakage\n- Refresh Token is valid for a long time, enhancing user experience\n- Separate key and expiration policies\n- Supports fine-grained permission control\n\n### Q: How to implement cross-device login management?\n**Implementation method**:\n- The token contains device identification information\n- Cache storage of the user's active device list\n- Support remote device logout\n- Limit on the number of devices that can be configured\n\n### Q: What are the performance optimization recommendations?\n**Optimization Strategy**:\n- Caching user permission information\n- Token pre-validation mechanism\n- Bulk token operation processing\n- Asynchronous status updates\n\n### Q: How do I deal with clock offset issues?\n**Solution**:\n- Set a reasonable clock offset tolerance\n- Synchronize server time using NTP\n- Added time buffer in token validation\n- Monitor server time synchronization status\n\n## Project Features and Advantages\n\n### 1. Architectural advantages\n- **Dual Token Design**: Balancing security with user experience\n- **Configurable Management**: Flexible expiration time and key configuration\n- **Middleware Mode**: Unified authentication and authorization processing\n- **Redis Integration**: High-performance token state management\n\n### 2. Safety features\n- **Multi-Layer Verification**: Token validity + blacklist check + role permissions\n- **Geolocation Tracking**: Enhance security auditing capabilities\n- Key Separation: Access and Refresh Tokens use different keys\n- **Progressive Expiration**: Supports elegant token renewals\n\n### 3. O&M friendly\n- **Detailed Logs**: Complete authentication and authorization logging\n- **Error Handling**: Unified error response and exception handling\n- **Monitoring Support**: Built-in performance and safety monitoring points\n- **Scalability**: Supports multiple authentication methods and permission models\n","企业必备",0,"https:\u002F\u002Fblog4-1316398321.cos.ap-nanjing.myqcloud.com\u002Fblog5\u002F20250712010832__【哲风壁纸】女孩-黑猫女孩.png",[15,16],"GO","JWT",false,{"id":19,"title":20,"title_en":21},22,"Go 交叉编译缓存导致的诡异 Bug","Weird Bug caused by Go cross-compiled caching",{"id":23,"title":24,"title_en":25},26,"Go 项目中稳健使用 GORM 的实践与思考","Practice and Thinking on Robust Use of GORM in Go Projects","2025-08-23T06:51:39+08:00"]