完善掉线诊断并优化二维码加载

This commit is contained in:
yml2213
2026-07-14 16:06:25 +08:00
parent 7b2d94e22d
commit 3a555c27b2
12 changed files with 388 additions and 31 deletions
+55 -5
View File
@@ -14,6 +14,34 @@ const (
var ErrInvalidToken = errors.New("invalid token")
// TokenValidationError 仅携带可安全记录的失败类别,不包含原始令牌或签名信息。
type TokenValidationError struct {
Reason string
err error
}
func (e *TokenValidationError) Error() string {
return "token validation failed: " + e.Reason
}
func (e *TokenValidationError) Unwrap() error {
return e.err
}
// AuthFailureReason 让 HTTP 鉴权层可在不依赖具体认证包的情况下读取失败类别。
func (e *TokenValidationError) AuthFailureReason() string {
return e.Reason
}
// TokenFailureReason 返回适合写入日志的令牌校验失败类别。
func TokenFailureReason(err error) string {
var validationErr *TokenValidationError
if errors.As(err, &validationErr) && validationErr.Reason != "" {
return validationErr.Reason
}
return "invalid"
}
type JWTManager struct {
secret []byte
accessTTL time.Duration
@@ -79,22 +107,44 @@ func (m *JWTManager) ParseSubject(tokenText, expectedType string, expectedSubjec
claims := &Claims{}
token, err := jwt.ParseWithClaims(tokenText, claims, func(token *jwt.Token) (any, error) {
if token.Method != m.signingMethod {
return nil, ErrInvalidToken
return nil, newTokenValidationError("signing_method")
}
return m.secret, nil
})
if err != nil || !token.Valid {
return nil, ErrInvalidToken
if err != nil {
return nil, newTokenValidationError(jwtFailureReason(err))
}
if !token.Valid {
return nil, newTokenValidationError("invalid")
}
if claims.TokenType != expectedType {
return nil, ErrInvalidToken
return nil, newTokenValidationError("token_type")
}
if expectedSubjectType != "" && claims.SubjectType != expectedSubjectType {
return nil, ErrInvalidToken
return nil, newTokenValidationError("subject_type")
}
return claims, nil
}
func newTokenValidationError(reason string) error {
return &TokenValidationError{Reason: reason, err: ErrInvalidToken}
}
func jwtFailureReason(err error) string {
switch {
case errors.Is(err, jwt.ErrTokenExpired):
return "expired"
case errors.Is(err, jwt.ErrTokenSignatureInvalid):
return "signature_invalid"
case errors.Is(err, jwt.ErrTokenMalformed):
return "malformed"
case errors.Is(err, jwt.ErrTokenNotValidYet):
return "not_valid_yet"
default:
return "invalid"
}
}
func (m *JWTManager) generate(userID uint64, subject string, subjectType string, tokenType string, tokenVersion int64, ttl time.Duration) (string, error) {
now := time.Now()
claims := Claims{