更新依赖项,优化 OAuth2 服务,添加 PKCE 支持,增强 OIDC 处理器,新增客户端注册和令牌管理端点,改进数据库模型以支持新功能。
This commit is contained in:
114
services/token.go
Normal file
114
services/token.go
Normal file
@@ -0,0 +1,114 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/golang-jwt/jwt/v4"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type TokenService struct {
|
||||
db *gorm.DB
|
||||
keyManager *KeyManager
|
||||
}
|
||||
|
||||
type TokenInfo struct {
|
||||
Active bool `json:"active"`
|
||||
Scope string `json:"scope,omitempty"`
|
||||
ClientID string `json:"client_id,omitempty"`
|
||||
Username string `json:"username,omitempty"`
|
||||
TokenType string `json:"token_type,omitempty"`
|
||||
Exp int64 `json:"exp,omitempty"`
|
||||
Iat int64 `json:"iat,omitempty"`
|
||||
Nbf int64 `json:"nbf,omitempty"`
|
||||
Sub string `json:"sub,omitempty"`
|
||||
Aud string `json:"aud,omitempty"`
|
||||
Iss string `json:"iss,omitempty"`
|
||||
Jti string `json:"jti,omitempty"`
|
||||
}
|
||||
|
||||
type RevokedToken struct {
|
||||
gorm.Model
|
||||
Token string `gorm:"uniqueIndex;not null"`
|
||||
ExpiresAt time.Time `gorm:"not null"`
|
||||
}
|
||||
|
||||
func NewTokenService(db *gorm.DB, keyManager *KeyManager) *TokenService {
|
||||
return &TokenService{
|
||||
db: db,
|
||||
keyManager: keyManager,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *TokenService) RevokeToken(token, tokenTypeHint string) error {
|
||||
// 验证令牌
|
||||
claims, err := s.parseToken(token)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 保存到撤销列表
|
||||
revokedToken := &RevokedToken{
|
||||
Token: token,
|
||||
ExpiresAt: time.Unix(claims["exp"].(int64), 0),
|
||||
}
|
||||
|
||||
return s.db.Create(revokedToken).Error
|
||||
}
|
||||
|
||||
func (s *TokenService) IntrospectToken(token, tokenTypeHint string) (*TokenInfo, error) {
|
||||
// 检查令牌是否被撤销
|
||||
var revokedToken RevokedToken
|
||||
if err := s.db.Where("token = ?", token).First(&revokedToken).Error; err == nil {
|
||||
return &TokenInfo{Active: false}, nil
|
||||
}
|
||||
|
||||
// 解析令牌
|
||||
claims, err := s.parseToken(token)
|
||||
if err != nil {
|
||||
return &TokenInfo{Active: false}, nil
|
||||
}
|
||||
|
||||
// 检查令牌是否过期
|
||||
exp := time.Unix(claims["exp"].(int64), 0)
|
||||
if time.Now().After(exp) {
|
||||
return &TokenInfo{Active: false}, nil
|
||||
}
|
||||
|
||||
// 构建令牌信息
|
||||
info := &TokenInfo{
|
||||
Active: true,
|
||||
Scope: claims["scope"].(string),
|
||||
ClientID: claims["iss"].(string),
|
||||
TokenType: "Bearer",
|
||||
Exp: claims["exp"].(int64),
|
||||
Iat: claims["iat"].(int64),
|
||||
Sub: claims["sub"].(string),
|
||||
}
|
||||
|
||||
return info, nil
|
||||
}
|
||||
|
||||
func (s *TokenService) parseToken(token string) (jwt.MapClaims, error) {
|
||||
parsedToken, err := jwt.Parse(token, func(token *jwt.Token) (interface{}, error) {
|
||||
if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {
|
||||
return nil, errors.New("unexpected signing method")
|
||||
}
|
||||
return s.keyManager.GetPrivateKey().Public(), nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if claims, ok := parsedToken.Claims.(jwt.MapClaims); ok && parsedToken.Valid {
|
||||
return claims, nil
|
||||
}
|
||||
|
||||
return nil, errors.New("invalid token")
|
||||
}
|
||||
|
||||
func (s *TokenService) AutoMigrate() error {
|
||||
return s.db.AutoMigrate(&RevokedToken{})
|
||||
}
|
||||
Reference in New Issue
Block a user