Skip to content

错误处理

CyberGo JWT 使用哨兵错误(sentinel errors)模式,所有错误通过 errors.Is() 判断。

基本模式

go
claims, valid, err := processor.Validate(tokenString)
if err != nil {
    switch {
    case errors.Is(err, jwt.ErrTokenExpired):
        // 令牌过期
    case errors.Is(err, jwt.ErrTokenRevoked):
        // 令牌已吊销
    case errors.Is(err, jwt.ErrTokenInvalidIssuer):
        // 签发者不匹配
    case errors.Is(err, jwt.ErrTokenInvalidAudience):
        // 受众不匹配
    case errors.Is(err, jwt.ErrInvalidToken):
        // 签名无效或格式错误
    case errors.Is(err, jwt.ErrProcessorClosed):
        // Processor 已关闭
    default:
        // 其他错误
    }
}

使用 errors.Is()

不要使用 err == jwt.ErrTokenExpired 或字符串匹配。errors.Is() 能正确处理包装后的错误。

错误分类

配置阶段

jwt.New() 可能返回以下错误:

错误原因解决方法
ErrInvalidConfig多项配置不合法检查 Config 各字段
ErrInvalidSecretKeyHMAC 密钥不足 32 字节或为弱密钥使用更强的密钥
ErrInvalidSigningMethod不支持的签名算法使用内置的 12 种算法

令牌操作

错误方法处理建议
ErrEmptyToken所有令牌操作方法检查请求头
ErrInvalidTokenValidate, Refresh, ValidateInto, RefreshInto, Revoke, IsRevoked签名不匹配,拒绝访问
ErrAlgorithmMismatchValidate, Refresh, ValidateInto, RefreshInto令牌算法与配置不匹配,拒绝访问
ErrExpirationRequiredValidate, Refresh, ValidateInto, RefreshInto启用 RequireExpiration 但令牌缺少 exp 声明
ErrTokenTypeMismatchRefresh, RefreshInto用访问令牌(token_type=access)尝试刷新,拒绝访问
ErrTokenExpiredValidate, Refresh, ValidateInto, RefreshInto引导用户刷新令牌
ErrTokenNotValidYetValidate, Refresh, ValidateInto, RefreshInto检查时钟同步
ErrTokenInvalidIssuerValidate, Refresh, ValidateInto, RefreshInto, Revoke, IsRevoked签发者不匹配
ErrTokenInvalidAudienceValidate, Refresh, ValidateInto, RefreshInto, Revoke, IsRevoked受众不匹配
ErrTokenRevokedValidate, Refresh, ValidateInto, RefreshInto令牌已吊销,拒绝访问
ErrInvalidClaimsCreate, CreateRefresh, Validate, Refresh, ValidateInto, RefreshInto业务验证失败
ErrTokenMissingIDRevoke, IsRevoked令牌缺少 jti

限流与黑名单

错误方法处理建议
ErrRateLimitExceededCreate, CreateRefresh, Refresh, RefreshInto返回 429
ErrBlacklistNotConfiguredRevoke配置黑名单

生命周期

错误方法处理建议
ErrProcessorClosed所有方法重新创建 Processor
ErrStoreClosedRevoke 等存储已关闭

错误类型

ValidationError

字段级验证失败时返回,包含具体的字段和错误信息:

go
type ValidationError struct {
    Field   string  // 出错的字段名
    Message string  // 错误描述
    Err     error   // 内部错误
}

Web 服务中的错误处理

go
func handleProtected(w http.ResponseWriter, r *http.Request) {
    tokenString := extractToken(r)
    claims, valid, err := processor.Validate(tokenString)
    if err != nil {
        switch {
        case errors.Is(err, jwt.ErrTokenExpired):
            http.Error(w, "token expired", http.StatusUnauthorized)
        case errors.Is(err, jwt.ErrTokenRevoked):
            http.Error(w, "token revoked", http.StatusUnauthorized)
        case errors.Is(err, jwt.ErrInvalidToken):
            http.Error(w, "invalid token", http.StatusUnauthorized)
        default:
            http.Error(w, "auth failed", http.StatusUnauthorized)
        }
        return
    }
    if !valid {
        http.Error(w, "invalid token", http.StatusUnauthorized)
        return
    }
    // 处理请求
}

下一步