Documentation
¶
Index ¶
- Constants
- Variables
- func BuildDPoPBoundAccessTokenURI(fullURL string) (string, error)
- func BuildRedirectURL(baseURI, code, state string) (string, error)
- func BuildRequestURI(r *http.Request) string
- func ComputeJKT(jwk map[string]interface{}) (string, error)
- func ComputePKCEChallenge(method, verifier string) (string, error)
- func DPoPMiddleware(cache ReplayCache, required bool) func(http.Handler) http.Handler
- func DPoPOptionalMiddleware(cache ReplayCache) func(http.Handler) http.Handler
- func DPoPProtectedEndpoints() []string
- func DPoPRequiredMiddleware(cache ReplayCache) func(http.Handler) http.Handler
- func DecodeJSON(r io.Reader, v any) error
- func DeviceAuthorized(ctx context.Context, storage Storage, req *DeviceAuthorizedRequest) error
- func DeviceDenied(ctx context.Context, storage Storage, userCode string) error
- func EndSession(ctx context.Context, storage Storage, server interface{ ... }, ...) (string, error)
- func ExtractDPoPJKT(ctx context.Context) string
- func GeneratePKCEVerifier() (string, error)
- func GetSigningMethod(key crypto.PrivateKey) jwt.SigningMethod
- func Hash(method jwt.SigningMethod, str string) (string, error)
- func IsConfidentialClient(method string) bool
- func LoadTokenSecret() ([]byte, error)
- func ParseECDSAPublicKeyFromJWK(jwk *JSONWebKey) (*ecdsa.PublicKey, error)
- func ParseEd25519PublicKeyFromJWK(jwk *JSONWebKey) (ed25519.PublicKey, error)
- func ParseRSAPublicKeyFromJWK(jwk *JSONWebKey) (*rsa.PublicKey, error)
- func RandomString(n int) (string, error)
- func RefreshTokenRevoke(ctx context.Context, storage TokenStorage, secretManager *SecretManager, ...) error
- func RegisterMetrics()
- func ResponseAuthorized(ctx context.Context, storage AuthCodeStorage, req *AuthorizeRequest, ...) (string, error)
- func RevokeAccessToken(ctx context.Context, storage RevocationStorage, verifier TokenVerifier, ...) error
- func RevokeToken(ctx context.Context, storage Storage, secretManager *SecretManager, ...) error
- func SaveKey(path string, key Key, password []byte) error
- func SetServerTimeHeader(w http.ResponseWriter)
- func ShouldUseDPoP(path string) bool
- func UnregisterClient(ctx context.Context, storage ClientStorage, clientIDStr string) error
- func ValidateKeySecurity(key Key) error
- func ValidateRegistrationRequest(req *ClientRegistrationRequest, allowedSchemes map[string]struct{}) error
- func ValidateScopes(allowedScopeStr, requestedScopeStr string) error
- func ValidateStructuredRefreshToken(ctx context.Context, sm *SecretManager, token RefreshToken) error
- func ValidateURN(uri string) error
- func VerifyDPoPProof(ctx context.Context, req *http.Request, w http.ResponseWriter, ...) (jkt string, err error)
- func VerifyPKCE(challenge, method, verifier string) error
- type AMR
- type AccessToken
- type AccessTokenClaims
- type AuthCodeSession
- type AuthCodeStorage
- type AuthorizeRequest
- type BinaryUUID
- func (BinaryUUID) GormDBDataType(db *gorm.DB, _ *schema.Field) string
- func (b BinaryUUID) MarshalJSON() ([]byte, error)
- func (b *BinaryUUID) Scan(value interface{}) error
- func (b BinaryUUID) String() string
- func (b *BinaryUUID) UnmarshalJSON(data []byte) error
- func (b BinaryUUID) Value() (driver.Value, error)
- type Cache
- type ClientCache
- type ClientFactory
- type ClientMetadata
- func (c *ClientMetadata) Deserialize(data string) error
- func (c *ClientMetadata) GetBackchannelLogoutSessionRequired() bool
- func (c *ClientMetadata) GetBackchannelLogoutURI() string
- func (c *ClientMetadata) GetGrantTypes() []string
- func (c *ClientMetadata) GetID() BinaryUUID
- func (c *ClientMetadata) GetLogoutRedirectURIs() []string
- func (c *ClientMetadata) GetRedirectURIs() []string
- func (c *ClientMetadata) GetScope() string
- func (c *ClientMetadata) IsConfidential() bool
- func (c *ClientMetadata) Metadata() *ClientMetadata
- func (c *ClientMetadata) Serialize() (string, error)
- func (ClientMetadata) TableName() string
- func (c *ClientMetadata) ValidateSecret(ctx context.Context, hasher Hasher, secret string) error
- type ClientRegistrationRequest
- type ClientRegistrationResponse
- type ClientStorage
- type ClientUpdateRequest
- type ClientVerifier
- type Code
- type DPoPClaims
- type DPoPProof
- type DPoPTimeSkewError
- type DPoPTimeSkewInfo
- type DeviceAuthorizationRequest
- type DeviceAuthorizationResponse
- type DeviceAuthorizedRequest
- type DeviceCodeSession
- type DeviceCodeStorage
- type Discovery
- type DistributedLock
- type DpopContextKey
- type EndSessionRequest
- type Error
- func AccessDeniedError(description string) *Error
- func AuthorizationPendingError(description string) *Error
- func ExpiredTokenError(description string) *Error
- func InvalidClientError(description string) *Error
- func InvalidGrantError(description string) *Error
- func InvalidRequestError(description string) *Error
- func InvalidScopeError(description string) *Error
- func NewError(code string, description string, statusCode int) *Error
- func ServerError(description string) *Error
- func ServerErrorWithDescription(description string) *Error
- func SlowDownError(description string) *Error
- func TemporarilyUnavailableError(description string) *Error
- func UnauthorizedClientError(description string) *Error
- func UnsupportedGrantTypeError(description string) *Error
- type GCWorker
- type Hash256
- type Hasher
- type IDToken
- type IDTokenClaims
- type IntrospectionRequest
- type IntrospectionResponse
- type Issuer
- func (g *Issuer) IssueClientCredentialsToken(ctx context.Context, req *IssuerRequest) (*IssuerResponse, error)
- func (g *Issuer) IssueOAuthTokens(ctx context.Context, req *IssuerRequest) (*IssuerResponse, error)
- func (g *Issuer) IssueOIDCTokens(ctx context.Context, req *IssuerRequest) (*IssuerResponse, error)
- func (g *Issuer) IssuePasswordResetAccessToken(ctx context.Context, req *IssuerRequest) (*IssuerResponse, error)
- func (i *Issuer) Issuer() string
- func (g *Issuer) RefreshOAuthTokens(ctx context.Context, req *IssuerRequest) (*IssuerResponse, error)
- func (g *Issuer) RefreshOIDCTokens(ctx context.Context, req *IssuerRequest) (*IssuerResponse, error)
- func (i *Issuer) SecretManager() *SecretManager
- type IssuerConfig
- type IssuerRequest
- type IssuerResponse
- func DeviceTokenExchange(ctx context.Context, storage Storage, issuer *Issuer, req *TokenRequest) (*IssuerResponse, error)
- func ExchangeClientCredentials(ctx context.Context, storage ClientStorage, hasher Hasher, issuer *Issuer, ...) (*IssuerResponse, error)
- func ExchangeCode(ctx context.Context, storage Storage, hasher Hasher, issuer *Issuer, ...) (*IssuerResponse, error)
- func PasswordGrant(ctx context.Context, storage Storage, hasher Hasher, issuer *Issuer, ...) (*IssuerResponse, error)
- func RefreshTokens(ctx context.Context, storage Storage, secretManager *SecretManager, ...) (*IssuerResponse, error)
- type JSONWebKey
- type JSONWebKeySet
- type JWK
- type Key
- type KeyManager
- func (km *KeyManager) Add(ctx context.Context, key Key) (string, error)
- func (km *KeyManager) ExportJWKS(ctx context.Context) (*JSONWebKeySet, error)
- func (km *KeyManager) Generate(ctx context.Context, kty KeyType, setAsSigning bool) (string, error)
- func (km *KeyManager) GetKey(ctx context.Context, kid string) (crypto.PublicKey, error)
- func (km *KeyManager) GetKeyInternal(ctx context.Context, kid string) (Key, error)
- func (km *KeyManager) GetSigningKey(ctx context.Context) (string, Key, error)
- func (km *KeyManager) JWKGetSigning(ctx context.Context) (string, error)
- func (km *KeyManager) ListKeys(ctx context.Context) ([]string, error)
- func (km *KeyManager) RemoveKey(ctx context.Context, kid string) error
- func (km *KeyManager) SetSigningKeyID(ctx context.Context, kid string) error
- type KeyProvider
- type KeyRotationConfig
- type KeyRotationScheduler
- type KeySource
- type KeyStorage
- type KeyType
- type ListQuery
- type LogoutTokenClaims
- type MemoryKeyProvider
- func (m *MemoryKeyProvider) AddKey(kid string, key []byte) error
- func (m *MemoryKeyProvider) GetActiveKey(ctx context.Context) (string, []byte, error)
- func (m *MemoryKeyProvider) GetKey(ctx context.Context, kid string) ([]byte, error)
- func (m *MemoryKeyProvider) ListKeys(ctx context.Context) (map[string][]byte, error)
- func (m *MemoryKeyProvider) RemoveKey(kid string) error
- func (m *MemoryKeyProvider) RotateKey(newKID string, newKey []byte, gracePeriod time.Duration) error
- func (m *MemoryKeyProvider) SetActiveKey(kid string) error
- type PARRequest
- type PARResponse
- type PARStorage
- type Persistence
- type RefreshToken
- type RefreshTokenSession
- type RegisteredClient
- func AuthenticateClient(ctx context.Context, storage ClientStorage, clientIDStr, clientSecret string, ...) (RegisteredClient, error)
- func GetAndVerifyClient(ctx context.Context, storage ClientStorage, clientIDStr string) (RegisteredClient, error)
- func ListClient(ctx context.Context, storage ClientStorage, query ListQuery) ([]RegisteredClient, error)
- func RequestAuthorize(ctx context.Context, storage Storage, req *AuthorizeRequest) (RegisteredClient, error)
- type RemoteKeySet
- type RemoteKeySetOption
- type ReplayCache
- type ResourceVerifier
- type RevocationRequest
- type RevocationStorage
- type SecretBytes
- func (s SecretBytes) GoString() string
- func (SecretBytes) GormDBDataType(db *gorm.DB, _ *schema.Field) string
- func (s SecretBytes) MarshalJSON() ([]byte, error)
- func (s *SecretBytes) Scan(value interface{}) error
- func (s SecretBytes) String() string
- func (s *SecretBytes) UnmarshalJSON(b []byte) error
- func (s SecretBytes) Value() (driver.Value, error)
- type SecretManager
- func (s *SecretManager) AddKey(id string, hexSecret string) error
- func (s *SecretManager) GetSigningKey(ctx context.Context) ([]byte, string)
- func (s *SecretManager) GetVerificationKey(ctx context.Context, kid string) ([]byte, error)
- func (s *SecretManager) RotateKey(newKID string, newHexSecret string, gracePeriod time.Duration) error
- func (s *SecretManager) SetActiveKey(kid string) error
- type SecretString
- func (s SecretString) GoString() string
- func (SecretString) GormDBDataType(db *gorm.DB, _ *schema.Field) string
- func (s SecretString) MarshalJSON() ([]byte, error)
- func (s *SecretString) Scan(value interface{}) error
- func (s SecretString) String() string
- func (s *SecretString) UnmarshalJSON(b []byte) error
- func (s SecretString) Value() (driver.Value, error)
- type Server
- func (s *Server) ClientUpdate(ctx context.Context, req *ClientUpdateRequest) (*ClientRegistrationResponse, error)
- func (s *Server) Config() *ServerConfig
- func (s *Server) DeviceAuthorization(ctx context.Context, req *DeviceAuthorizationRequest) (*DeviceAuthorizationResponse, error)
- func (s *Server) Discovery() *Discovery
- func (s *Server) EndSession(ctx context.Context, req *EndSessionRequest) (string, error)
- func (s *Server) Exchange(ctx context.Context, req *TokenRequest) (resp *IssuerResponse, err error)
- func (s *Server) GetUserInfo(ctx context.Context, claims *AccessTokenClaims) (*UserInfo, error)
- func (s *Server) Introspect(ctx context.Context, tokenStr, clientIDStr, clientSecret string) (*IntrospectionResponse, error)
- func (s *Server) Issuer() *Issuer
- func (s *Server) KeyManager() *KeyManager
- func (s *Server) ListClient(ctx context.Context, query ListQuery) ([]RegisteredClient, error)
- func (s *Server) ParseAccessToken(ctx context.Context, tokenStr string) (*AccessTokenClaims, error)
- func (s *Server) PushedAuthorization(ctx context.Context, req *PARRequest) (*PARResponse, error)
- func (s *Server) RegisterClient(ctx context.Context, req *ClientRegistrationRequest) (*ClientRegistrationResponse, error)
- func (s *Server) RequestAuthorize(ctx context.Context, req *AuthorizeRequest) (client RegisteredClient, err error)
- func (s *Server) ResponseAuthorized(ctx context.Context, req *AuthorizeRequest) (redirectURL string, err error)
- func (s *Server) RevokeToken(ctx context.Context, req *RevocationRequest) error
- func (s *Server) SecretManager() *SecretManager
- func (s *Server) StartBackgroundWorkers(ctx context.Context)
- func (s *Server) StopBackgroundWorkers()
- func (s *Server) UnregisterClient(ctx context.Context, clientIDStr string) error
- func (s *Server) ValidateKeys(ctx context.Context) error
- func (s *Server) VerifyAccessToken(ctx context.Context, tokenStr string) (*AccessTokenClaims, error)
- type ServerConfig
- type StaticKeySet
- type Storage
- type StringSlice
- type TieredStorage
- func (s *TieredStorage) ClientCreate(ctx context.Context, metadata *ClientMetadata) (RegisteredClient, error)
- func (s *TieredStorage) ClientDeleteByID(ctx context.Context, clientID BinaryUUID) error
- func (s *TieredStorage) ClientGetByID(ctx context.Context, clientID BinaryUUID) (RegisteredClient, error)
- func (s *TieredStorage) ClientListAll(ctx context.Context, query ListQuery) ([]RegisteredClient, error)
- func (s *TieredStorage) ClientListByOwner(ctx context.Context, ownerID BinaryUUID, query ListQuery) ([]RegisteredClient, error)
- func (s *TieredStorage) ClientUpdate(ctx context.Context, metadata *ClientMetadata) (RegisteredClient, error)
- func (s *TieredStorage) JWKDelete(ctx context.Context, kid string) error
- func (s *TieredStorage) JWKGet(ctx context.Context, kid string) (jwk.Key, error)
- func (s *TieredStorage) JWKGetSigning(ctx context.Context) (string, error)
- func (s *TieredStorage) JWKList(ctx context.Context) ([]jwk.Key, error)
- func (s *TieredStorage) JWKMarkSigning(ctx context.Context, kid string) error
- func (s *TieredStorage) JWKSave(ctx context.Context, key jwk.Key) error
- func (s *TieredStorage) RefreshTokenCreate(ctx context.Context, session *RefreshTokenSession) error
- func (s *TieredStorage) RefreshTokenGet(ctx context.Context, tokenID Hash256) (*RefreshTokenSession, error)
- func (s *TieredStorage) RefreshTokenRevoke(ctx context.Context, tokenID Hash256) error
- func (s *TieredStorage) RefreshTokenRevokeUser(ctx context.Context, userID BinaryUUID) ([]Hash256, error)
- func (s *TieredStorage) RefreshTokenRotate(ctx context.Context, oldTokenID Hash256, newSession *RefreshTokenSession, ...) error
- type TieredStorageOption
- type TokenCache
- type TokenRequest
- type TokenStorage
- type TokenVerifier
- type UserAuthenticator
- type UserInfo
- type UserInfoGetter
Constants ¶
const ( DeviceCodeStatusPending = "pending" DeviceCodeStatusAllowed = "allowed" DeviceCodeStatusDenied = "denied" )
const ( // Response Types ResponseTypeCode = "code" // Grant Types GrantTypeAuthorizationCode = "authorization_code" GrantTypeRefreshToken = "refresh_token" GrantTypeClientCredentials = "client_credentials" GrantTypePassword = "password" GrantTypeDeviceCode = "urn:ietf:params:oauth:grant-type:device_code" // Subject Types SubjectTypePublic = "public" // Auth Methods AuthMethodClientSecretBasic = "client_secret_basic" AuthMethodClientSecretPost = "client_secret_post" // Scopes ScopeOpenID = "openid" ScopeProfile = "profile" ScopeEmail = "email" ScopePhone = "phone" ScopeOfflineAccess = "offline_access" )
const ( // CodeChallengeMethodS256 是推荐的 PKCE 转换方法 CodeChallengeMethodS256 = "S256" // CodeChallengeMethodPlain 是不推荐的方法,仅用于兼容性 CodeChallengeMethodPlain = "plain" )
const (
DefaultClientCacheTTL = time.Hour
)
const ( // DefaultKeyCacheTTL 是本地缓存签名 Key ID 的默认有效期 // 在分布式环境中,这决定了轮换后其他实例感知到的最大延迟 DefaultKeyCacheTTL = 30 * time.Second )
Variables ¶
var ( // ErrInvalidRequest 请求缺少必需的参数、包含无效的参数值、包含多个同名参数,或者格式不正确。 ErrInvalidRequest = errors.New("invalid_request") // ErrInvalidClient 客户端认证失败(例如:未知的客户端、未包含客户端认证信息、不支持的认证方法)。 ErrInvalidClient = errors.New("invalid_client") // ErrInvalidGrant 提供的授权许可(例如:授权码、资源所有者凭据)或刷新令牌无效、过期、已撤销、与重定向 URI 不匹配,或不属于该客户端。 ErrInvalidGrant = errors.New("invalid_grant") ErrUnauthorizedClient = errors.New("unauthorized_client") // ErrUnsupportedGrantType 授权服务器不支持该授权许可类型。 ErrUnsupportedGrantType = errors.New("unsupported_grant_type") // ErrInvalidScope 请求的范围无效、未知、格式不正确,或超出了资源所有者授予的范围。 ErrInvalidScope = errors.New("invalid_scope") // ErrAccessDenied 资源所有者或授权服务器拒绝了请求。 ErrAccessDenied = errors.New("access_denied") // ErrServerError 授权服务器遇到意外情况,无法完成请求。 ErrServerError = errors.New("server_error") ErrTemporarilyUnavailable = errors.New("temporarily_unavailable") )
var ( // ErrAuthorizationPending 设备授权请求待处理,客户端应继续轮询。 ErrAuthorizationPending = errors.New("authorization_pending") // ErrSlowDown 客户端轮询过于频繁,应减慢轮询速率。 ErrSlowDown = errors.New("slow_down") // ErrExpiredToken 设备码已过期。 ErrExpiredToken = errors.New("expired_token") )
var ( ErrTokenExpired = errors.New("token is expired") ErrTokenSignatureInvalid = errors.New("token signature is invalid") ErrInvalidIssuer = errors.New("invalid issuer") ErrInvalidAudience = errors.New("invalid audience") ErrInvalidNonce = errors.New("invalid nonce") ErrNotFound = errors.New("resource not found") ErrTokenFormatInvalid = errors.New("token format is invalid") ErrTokenForged = errors.New("token forged") )
var ( ErrClientNotFound = errors.New("client not found") ErrTokenNotFound = errors.New("token not found or expired") ErrCodeNotFound = errors.New("authorization code not found or consumed") ErrUserNotFound = errors.New("user not found") )
var ( // ErrKeyNil 密钥不能为 nil ErrKeyNil = errors.New("key cannot be nil") // ErrInvalidRSAKey 无效的 RSA 私钥 ErrInvalidRSAKey = errors.New("invalid RSA private key") // ErrRSAKeyTooSmall RSA 私钥必须至少 2048 位 ErrRSAKeyTooSmall = errors.New("RSA private key must be at least 2048 bits") // ErrInvalidEd25519KeySize 无效的 Ed25519 私钥大小 ErrInvalidEd25519KeySize = errors.New("invalid Ed25519 private key size") // ErrNoSigningKey 未配置签名密钥 ErrNoSigningKey = errors.New("no signing key configured") // ErrKeyNotFound 密钥未找到 ErrKeyNotFound = errors.New("key not found") // ErrTokenRevoked 表示 Access Token 已被撤销 (例如用户登出或安全事件) ErrTokenRevoked = errors.New("token has been revoked") // ErrCannotRemoveSigningKey 不能删除当前的签名密钥 ErrCannotRemoveSigningKey = errors.New("cannot remove current signing key") // ErrUnsupportedKeyType 不支持的密钥类型 ErrUnsupportedKeyType = errors.New("unsupported key type") // ErrCircuitBreakerOpen 断路器打开 ErrCircuitBreakerOpen = errors.New("remote JWKS unavailable (circuit breaker open)") // ErrKeyExpired 密钥已过期 ErrKeyExpired = errors.New("key expired") // ErrNoActiveKey 未设置活跃密钥 ErrNoActiveKey = errors.New("no active key set") // ErrKIDEmpty KID 不能为空 ErrKIDEmpty = errors.New("kid cannot be empty") // ErrKeyTooShort 密钥长度不足 ErrKeyTooShort = errors.New("key must be at least 32 bytes") // ErrCannotRemoveActiveKey 不能删除活跃密钥 ErrCannotRemoveActiveKey = errors.New("cannot remove active key") // ErrUnsupportedECDSACurve 不支持的 ECDSA 曲线 ErrUnsupportedECDSACurve = errors.New("unsupported ECDSA curve") // ErrUnsupportedPrivateKeyType 不支持的私钥类型 ErrUnsupportedPrivateKeyType = errors.New("unsupported private key type") // ErrSigningKeyMissing 当前签名密钥丢失 ErrSigningKeyMissing = errors.New("current signing key is missing") // ErrKeyInterfaceNotImplemented 存储的密钥未实现 Key 接口 ErrKeyInterfaceNotImplemented = errors.New("stored key does not implement Key interface") // ErrNoActiveRefreshTokenKey 没有用于刷新令牌的活跃密钥 ErrNoActiveRefreshTokenKey = errors.New("hmac key check failed: no active key for refresh tokens") // ErrSchedulerAlreadyStarted 调度器已启动 ErrSchedulerAlreadyStarted = errors.New("scheduler already started") // ErrRotationInProgress 另一个实例正在进行轮换 ErrRotationInProgress = errors.New("rotation already in progress by another instance") // ErrMemoryProviderOnly 操作仅支持 MemoryKeyProvider ErrMemoryProviderOnly = errors.New("operation only supported for MemoryKeyProvider") )
var ( // ErrPKCEVerifierEmpty PKCE verifier 不能为空 ErrPKCEVerifierEmpty = errors.New("pkce verifier cannot be empty") // ErrPKCEVerifierInvalidLength PKCE verifier 长度无效 ErrPKCEVerifierInvalidLength = errors.New("invalid pkce verifier length") // ErrPKCEVerifierInvalidChars PKCE verifier 包含无效字符 ErrPKCEVerifierInvalidChars = errors.New("invalid characters in pkce verifier") // ErrPKCEVerificationFailed PKCE 验证失败 ErrPKCEVerificationFailed = errors.New("pkce verification failed") // ErrPKCERandomnessGenerationFailed PKCE 随机数生成失败 ErrPKCERandomnessGenerationFailed = errors.New("failed to generate randomness for pkce") // ErrUnsupportedPKCEChallengeMethod 不支持的 PKCE challenge 方法 ErrUnsupportedPKCEChallengeMethod = errors.New("unsupported pkce challenge method") )
var ( // ErrKeyNotEC 密钥不是 EC 类型 ErrKeyNotEC = errors.New("key is not EC") // ErrKeyNotRSA 密钥不是 RSA 类型 ErrKeyNotRSA = errors.New("key is not RSA") // ErrKeyNotEd25519 密钥不是 Ed25519 类型 ErrKeyNotEd25519 = errors.New("key is not Ed25519") // ErrInvalidEd25519PublicKeySize 无效的 Ed25519 公钥大小 ErrInvalidEd25519PublicKeySize = errors.New("invalid Ed25519 public key size") // ErrInvalidJWKType 无效的 JWK 类型 ErrInvalidJWKType = errors.New("invalid JWK type") // ErrMissingJWKFields 缺少 JWK 字段 ErrMissingJWKFields = errors.New("missing JWK fields") // ErrUnsupportedJWKPublicKeyType 不支持的 JWK 公钥类型 ErrUnsupportedJWKPublicKeyType = errors.New("jwks: unsupported key type") // ErrUnsupportedKtyForThumbprint 不支持的 kty 用于指纹计算 ErrUnsupportedKtyForThumbprint = errors.New("unsupported kty for thumbprint") // ErrUnsupportedCurve 不支持的曲线 ErrUnsupportedCurve = errors.New("jwks: unsupported curve") )
var ( // ErrIssuerEmpty 发行者不能为空 ErrIssuerEmpty = errors.New("issuer cannot be empty") // ErrInvalidIssuerURL 发行者必须是有效的 URL ErrInvalidIssuerURL = errors.New("issuer must be a valid URL") // ErrInvalidTTL Token TTL 必须大于 0 ErrInvalidTTL = errors.New("token TTL must be greater than 0") // ErrKeyManagerNil KeyManager 不能为 nil ErrKeyManagerNil = errors.New("keyManager cannot be nil") // ErrSecretManagerNil SecretManager 不能为 nil ErrSecretManagerNil = errors.New("secretManager cannot be nil") // ErrFailedToGenerateUUID 生成 UUID 失败 ErrFailedToGenerateUUID = errors.New("failed to generate UUIDv7") // ErrUnsupportedSigningKeyType 不支持的签名密钥类型 ErrUnsupportedSigningKeyType = errors.New("unsupported signing key type") // ErrUnsupportedAlgForHash 不支持的哈希计算算法 ErrUnsupportedAlgForHash = errors.New("unsupported alg for hash calculation") )
var ( // ErrHash256InvalidLength Hash256 必须为 32 字节 ErrHash256InvalidLength = errors.New("Hash256 must be exactly 32 bytes") // ErrHash256ScanInvalidLength 扫描失败: Hash256 应为 32 字节 ErrHash256ScanInvalidLength = errors.New("scan failed: expected 32 bytes for Hash256") // ErrHash256UnsupportedType 扫描失败: Hash256 不支持的类型 ErrHash256UnsupportedType = errors.New("scan failed: unsupported type for Hash256") // ErrInvalidHexStringLength 无效的十六进制字符串长度 ErrInvalidHexStringLength = errors.New("invalid hex string length") // ErrBinaryUUIDUnsupportedType BinaryUUID 无法扫描的类型 ErrBinaryUUIDUnsupportedType = errors.New("BinaryUUID: cannot scan type") )
var ( // ErrUserIDRequired 生成授权码需要 user_id ErrUserIDRequired = errors.New("user_id is required to generate authorization code") // ErrTokenIsInvalid Token 无效 ErrTokenIsInvalid = errors.New("token is invalid") // ErrExpClaimRequired exp 声明是必需的 ErrExpClaimRequired = errors.New("exp claim is required") // ErrAZPRequired 当存在多个受众时需要 azp 声明 ErrAZPRequired = errors.New("azp claim is required when multiple audiences are present") // ErrAZPMismatch azp 与 client_id 不匹配 ErrAZPMismatch = errors.New("azp does not match client_id") // ErrAZPRequiredForTrust 受信任的客户端验证需要 azp 声明 ErrAZPRequiredForTrust = errors.New("azp claim is required for trusted client validation") // ErrAZPNotAuthorized azp 未被授权访问资源 ErrAZPNotAuthorized = errors.New("azp is not authorized to access resource") // ErrUnexpectedSigningMethod 意外的签名方法 ErrUnexpectedSigningMethod = errors.New("unexpected signing method") // ErrHasherNotConfigured Hasher 未配置 ErrHasherNotConfigured = errors.New("hasher not configured") // ErrInvalidIdentifier 无效的标识符 ErrInvalidIdentifier = errors.New("invalid identifier") // ErrUserNotConfirmed 用户未确认 ErrUserNotConfirmed = errors.New("user not confirmed") // ErrUserForbidden 用户被禁用 ErrUserForbidden = errors.New("user forbidden") // ErrDefaultPassword 使用默认密码 ErrDefaultPassword = errors.New("default password") // ErrIssuerURLRequired issuer URL 是必需的 ErrIssuerURLRequired = errors.New("issuer url is required") // ErrStorageRequired storage 实现是必需的 ErrStorageRequired = errors.New("storage implementation is required") // ErrHasherRequired hasher 实现是必需的 ErrHasherRequired = errors.New("hasher implementation is required") // ErrSecretHasherRequired 机密客户端需要 secret hasher ErrSecretHasherRequired = errors.New("secret hasher is required for confidential clients") // ErrEnvTokenSecretRequired 环境变量 OIDC_TOKEN_SECRET 是必需的 ErrEnvTokenSecretRequired = errors.New("env OIDC_TOKEN_SECRET is required") )
var ( // ErrPARNotSupported 服务器不支持 PAR ErrPARNotSupported = errors.New("server does not support PAR") // ErrDeviceFlowNotSupported 服务器不支持设备流 ErrDeviceFlowNotSupported = errors.New("server does not support device flow") // ErrRevocationNotSupported 服务器不支持撤销 ErrRevocationNotSupported = errors.New("server does not support revocation") // ErrIntrospectionNotSupported 服务器不支持内省 ErrIntrospectionNotSupported = errors.New("server does not support introspection") // ErrNonceMismatch nonce 不匹配 ErrNonceMismatch = errors.New("nonce mismatch") // ErrUnparseableError 请求失败且错误无法解析 ErrUnparseableError = errors.New("request failed with unparseable error") )
var AllowedSchemes = map[string]struct{}{
"http": {},
"https": {},
}
var DefaultSupportedSigningAlgs = []string{"RS256", "RS384", "RS512", "ES256", "ES384", "ES512", "EdDSA"}
DefaultSupportedSigningAlgs 默认支持的签名算法
var ErrInvalidURNFormat = errors.New("invalid urn format")
ErrInvalidURNFormat 无效的 URN 格式
Functions ¶
func BuildDPoPBoundAccessTokenURI ¶
BuildDPoPBoundAccessTokenURI 构建资源请求 URI (去除查询参数和片段) RFC 9449 要求 htu 与实际请求的 URI 匹配(不含查询参数)
func BuildRedirectURL ¶
BuildRedirectURL 拼接 URL 参数
func BuildRequestURI ¶
BuildRequestURI 构建 HTTP 请求的完整 URI (不含 query 和 fragment) RFC 9449 Section 4.2: htu 必须是 scheme + host + path,不包含 query 和 fragment
func ComputeJKT ¶
ComputeJKT 计算 JWK Thumbprint (RFC 7638) 用于生成 cnf.jkt claim
func ComputePKCEChallenge ¶
ComputePKCEChallenge 根据给定的 Verifier 和 Method 计算 Challenge。 目前主要支持 S256。
func DPoPMiddleware ¶
DPoPMiddleware 创建一个中间件来验证 DPoP proof 如果验证成功,将 DPoPClaims 存入 context 如果验证失败,返回 401 错误
使用方式:
middleware := oidc.DPoPMiddleware(server, replayCache, true) handler := middleware(yourHandler)
func DPoPOptionalMiddleware ¶
func DPoPOptionalMiddleware(cache ReplayCache) func(http.Handler) http.Handler
DPoPOptionalMiddleware 创建一个可选的 DPoP 中间件 如果提供了 DPoP header 则验证,否则继续处理
func DPoPProtectedEndpoints ¶
func DPoPProtectedEndpoints() []string
DPoPProtectedEndpoints 返回需要 DPoP 保护的端点列表 通常包括:/token, /userinfo, /introspect
func DPoPRequiredMiddleware ¶
func DPoPRequiredMiddleware(cache ReplayCache) func(http.Handler) http.Handler
DPoPRequiredMiddleware 创建一个必需的 DPoP 中间件 如果未提供 DPoP header 则返回 401 错误
func DecodeJSON ¶
DecodeJSON 是一个安全的 JSON 解码辅助函数。 它启用 UseNumber() 选项,防止大整数(如 expires_in 或 ID)被错误解析为 float64 导致精度丢失。
func DeviceAuthorized ¶
func DeviceAuthorized(ctx context.Context, storage Storage, req *DeviceAuthorizedRequest) error
DeviceAuthorized 处理设备授权确认 (用户在前端点击同意后调用)
func DeviceDenied ¶
补充:处理用户拒绝授权的逻辑 (建议添加)
func EndSession ¶
func EndSession(ctx context.Context, storage Storage, server interface { ParseAccessToken(ctx context.Context, tokenStr string) (*AccessTokenClaims, error) KeyManager() *KeyManager Config() *ServerConfig }, req *EndSessionRequest) (string, error)
EndSession 处理用户登出请求
func ExtractDPoPJKT ¶
ExtractDPoPJKT 是一个辅助函数,用于从 context 中提取 JKT 如果不存在则返回空字符串
func GeneratePKCEVerifier ¶
GeneratePKCEVerifier 生成一个符合 RFC 7636 标准的高熵随机字符串。 长度默认为 43 字符(32 字节熵)。
func GetSigningMethod ¶
func GetSigningMethod(key crypto.PrivateKey) jwt.SigningMethod
GetSigningMethod 根据私钥类型返回对应的 JWT 签名方法
func Hash ¶
func Hash(method jwt.SigningMethod, str string) (string, error)
Hash 根据签名算法计算字符串的哈希值 OIDC 规范:使用 ID 令牌头部指定的哈希算法对令牌 ASCII 表示的字节进行哈希处理。取哈希值的左半部分并进行 base64url 编码。
func IsConfidentialClient ¶ added in v0.3.9
IsConfidentialClient 判断客户端类型
func ParseECDSAPublicKeyFromJWK ¶
func ParseECDSAPublicKeyFromJWK(jwk *JSONWebKey) (*ecdsa.PublicKey, error)
ParseECDSAPublicKeyFromJWK 是一个辅助函数,用于将 JWK 转换回 *ecdsa.PublicKey (主要用于 Client 端验证)。
func ParseEd25519PublicKeyFromJWK ¶
func ParseEd25519PublicKeyFromJWK(jwk *JSONWebKey) (ed25519.PublicKey, error)
ParseEd25519PublicKeyFromJWK 解析 Ed25519 JWK
func ParseRSAPublicKeyFromJWK ¶
func ParseRSAPublicKeyFromJWK(jwk *JSONWebKey) (*rsa.PublicKey, error)
ParseRSAPublicKeyFromJWK 是一个辅助函数,用于将 JWK 转换回 *rsa.PublicKey。
func RandomString ¶
RandomString 生成指定长度的随机字符串 (URL Safe Base64)
func RefreshTokenRevoke ¶ added in v0.3.0
func RefreshTokenRevoke(ctx context.Context, storage TokenStorage, secretManager *SecretManager, tokenStr string, client RegisteredClient) error
RefreshTokenRevoke 处理 Opaque Refresh Token 的撤销 (物理删除/标记)
func RegisterMetrics ¶
func RegisterMetrics()
RegisterMetrics 注册 OIDC 相关的 metrics 到 o11y registry 这个函数应该在初始化 OIDC Server 之后,启动服务之前调用 通常在 main.go 中调用一次即可
示例用法:
shutdown := o11y.Init(cfg.O11y) defer shutdown(context.Background()) oidc.RegisterMetrics() // 注册 OIDC 指标
func ResponseAuthorized ¶
func ResponseAuthorized(ctx context.Context, storage AuthCodeStorage, req *AuthorizeRequest, codeTTL time.Duration) (string, error)
ResponseAuthorized 在用户通过身份验证并同意授权后调用。 它生成 Authorization Code,保存到存储层,并返回包含 code 和 state 的重定向 URL。
func RevokeAccessToken ¶
func RevokeAccessToken(ctx context.Context, storage RevocationStorage, verifier TokenVerifier, tokenStr string, client RegisteredClient) error
RevokeAccessToken 处理 JWT Access Token 的撤销 (加入黑名单)
func RevokeToken ¶
func RevokeToken(ctx context.Context, storage Storage, secretManager *SecretManager, hasher Hasher, verifier TokenVerifier, req *RevocationRequest) error
RevokeToken 是一个无状态函数,直接由 Server 调用
func SetServerTimeHeader ¶
func SetServerTimeHeader(w http.ResponseWriter)
SetServerTimeHeader 设置服务器时间响应头 帮助客户端计算时间偏差
func UnregisterClient ¶
func UnregisterClient(ctx context.Context, storage ClientStorage, clientIDStr string) error
UnregisterClient 注销客户端 注意:实际业务中通常需要验证是否有权删除(如验证 Registration Access Token 或 OwnerID)
func ValidateRegistrationRequest ¶
func ValidateRegistrationRequest(req *ClientRegistrationRequest, allowedSchemes map[string]struct{}) error
ValidateRegistrationRequest 集中处理校验逻辑
func ValidateScopes ¶
ValidateScopes 检查 requestedScope 是否是 allowedScope 的子集 支持通配符匹配: - "scope:*" 匹配 "scope:read", "scope:write" - "scope:read:*" 匹配 "scope:read:user" - "*" 匹配所有
func ValidateStructuredRefreshToken ¶
func ValidateStructuredRefreshToken(ctx context.Context, sm *SecretManager, token RefreshToken) error
验证 Token (在查库之前)
func VerifyDPoPProof ¶
func VerifyDPoPProof( ctx context.Context, req *http.Request, w http.ResponseWriter, cache ReplayCache, httpMethod, httpURI string, ) (jkt string, err error)
VerifyDPoPProof 验证 HTTP 请求中的 DPoP Proof 返回 JWK Thumbprint (jkt) 用于绑定到 Access Token
RFC 9449 验证步骤: 1. 解析 DPoP header 中的 JWT 2. 验证 JWT 签名 (公钥在 header 的 jwk 字段) 3. 验证 htm 和 htu 与请求匹配 4. 验证 iat 时间窗口 (推荐 ±60秒) 5. 验证 jti 防重放 (使用 ReplayCache) 6. 计算并返回 JKT (JWK Thumbprint)
w: 可选的 ResponseWriter,用于在验证失败时设置服务器时间响应头
func VerifyPKCE ¶
VerifyPKCE 验证前端传来的 Verifier 是否与存储的 Challenge 匹配。
Types ¶
type AMR ¶ added in v0.4.0
type AMR = string
AMR (Authentication Methods References) 标识了具体的认证手段。 这里的定义遵循 RFC 8176 标准及 IANA 注册表。
const ( // AMR_Face 面部识别 (Face Recognition) // 场景: Apple FaceID, Android Face Unlock AMR_Face AMR = "face" // AMR_Fingerprint 指纹识别 (Fingerprint) // 场景: TouchID, 安卓指纹 AMR_Fingerprint AMR = "fpt" // AMR_Geo 地理位置 (Geo-Location) // 场景: 基于用户地理位置的隐式认证或风控通过 AMR_Geo AMR = "geo" // AMR_Iris 虹膜扫描 (Iris Scan) AMR_Iris AMR = "iris" // AMR_Retina 视网膜扫描 (Retina Scan) AMR_Retina AMR = "retina" // AMR_Voice 语音生物特征 (Voice Biometric) // 场景: 声纹识别 AMR_Voice AMR = "vbm" // AMR_Bio 通用生物特征 (Biometric) // 场景: 当无法区分具体是脸还是指纹,或不想暴露具体细节时使用 AMR_Bio AMR = "bio" )
----------------------------------------------------------------------------- 1. 生物识别类 (Biometric) - RFC 8176 -----------------------------------------------------------------------------
const ( // AMR_Password 密码 (Password) // 场景: 用户输入了密码 AMR_Password AMR = "pwd" // AMR_PIN 个人识别码 (Personal Identification Number) // 场景: 银行卡PIN,只有数字的简短密码 AMR_PIN AMR = "pin" // AMR_KBA 基于知识的认证 (Knowledge-Based Authentication) // 场景: 安全问题 ("你母亲的姓氏是什么?") AMR_KBA AMR = "kba" )
----------------------------------------------------------------------------- 2. 知识类 (Knowledge - Something you know) - RFC 8176 -----------------------------------------------------------------------------
const ( // AMR_OTP 一次性密码 (One-Time Password) // 场景: TOTP (Google Authenticator), HOTP // 注意: 虽然短信验证码也是OTP,但通常建议用 "sms" 区分 AMR_OTP AMR = "otp" // AMR_HardwareKey 硬件持有的加密密钥 (Proof-of-Possession Hardware Secured Key) // 场景: WebAuthn, FIDO2, Passkey (Passkey通常结合 hwk + user) AMR_HardwareKey AMR = "hwk" // AMR_SoftwareKey 软件持有的加密密钥 (Proof-of-Possession Software Secured Key) // 场景: 客户端证书文件 (非硬件存储), 软件生成的非对称密钥签名 AMR_SoftwareKey AMR = "swk" // AMR_SmartCard 智能卡 (Smart Card) // 场景: 银行U盾, 身份证读卡器, PIV 卡 (通过 mTLS 认证) AMR_SmartCard AMR = "sc" // AMR_SMS 短信 (SMS) // 场景: 通过短信发送的验证码 AMR_SMS AMR = "sms" // AMR_Tel 电话回呼 (Telephone) // 场景: 接听电话并按键确认,或语音播报验证码 AMR_Tel AMR = "tel" // AMR_UserPresence 用户在场测试 (User Presence Test) // 场景: 触摸 YubiKey 的金属片 (仅证明有人在,不验证生物特征), 点击确认按钮 AMR_UserPresence AMR = "user" // AMR_WIA Windows 集成认证 (Windows Integrated Authentication) // 场景: 企业内网自动登录 (Kerberos/NTLM) AMR_WIA AMR = "wia" // AMR_PoP 密钥持有证明 (Proof of Possession) // 场景: 只有持有特定私钥才能签署的请求 (通用定义) AMR_PoP AMR = "pop" )
----------------------------------------------------------------------------- 3. 持有类 (Possession - Something you have) - RFC 8176 -----------------------------------------------------------------------------
const ( // AMR_MFA 多因素认证 (Multi-Factor Authentication) // 场景: 明确标记本次认证使用了多种因素 (如 pwd + otp) AMR_MFA AMR = "mfa" // AMR_MCA 多通道认证 (Multi-Channel Authentication) // 场景: 在网页登录,在手机App上点击确认 (Out-of-band) AMR_MCA AMR = "mca" // AMR_Risk 基于风险的认证 (Risk-based Authentication) // 场景: 系统判定环境安全,自动放行 (无交互) AMR_Risk AMR = "risk" )
----------------------------------------------------------------------------- 4. 逻辑与组合类 (Logic & Combination) - RFC 8176 -----------------------------------------------------------------------------
const ( // AMR_Email 电子邮件 (Email) - 非 RFC 8176 标准,但极常用 // 场景: Magic Link (魔术链接), 邮箱验证码 // RFC 倾向于用 "otp" (如果是码) 或 "mca" (如果是链接),但 "email" 语义更清晰 AMR_Email AMR = "email" // AMR_PhishingResistant 防钓鱼 (Phishing Resistant) - FIDO 联盟建议 // 场景: 明确标记使用了 FIDO/WebAuthn 等防中间人攻击的手段 // 许多高安全级应用 (如银行) 会检查此标记 AMR_PhishingResistant AMR = "phrh" )
----------------------------------------------------------------------------- 5. 工业界通用扩展 (Common Industry Practice / Non-RFC) -----------------------------------------------------------------------------
type AccessToken ¶
type AccessToken SecretString
func (AccessToken) Hash ¶
func (ac AccessToken) Hash(alg jwt.SigningMethod) (string, error)
Hash 根据签名算法计算 Access Token 的哈希值 规范要求:Hash 算法必须匹配 ID Token 的签名算法
type AccessTokenClaims ¶
type AccessTokenClaims struct {
jwt.RegisteredClaims
// --- OAuth2 协议核心字段 ---
Scope string `json:"scope,omitempty"` // 核心权限字段!例如 "read:orders write:profile"
// --- 扩展字段 ---
AuthorizedParty string `json:"azp,omitempty"` // 哪个 Client 发起的请求?(用于限流、审计)
// --- 认证强度 ---
AuthTime *jwt.NumericDate `json:"auth_time,omitempty"`
ACR string `json:"acr,omitempty"`
AMR []AMR `json:"amr,omitempty"`
// --- DPoP (RFC 9449) ---
// Confirmation claim: 用于 DPoP sender-constrained tokens
// 格式: {"jkt": "<JWK Thumbprint>"}
Confirmation map[string]interface{} `json:"cnf,omitempty"`
}
AccessTokenClaims 表示自定义的 Access Token 载荷。 虽然 OAuth2 没有严格规定 Access Token 格式,但使用 JWT 是常见做法。
func (*AccessTokenClaims) SignedString ¶
func (ac *AccessTokenClaims) SignedString(method jwt.SigningMethod, privateKey crypto.PrivateKey) (AccessToken, error)
type AuthCodeSession ¶
type AuthCodeSession struct {
// Code: 授权码本身作为主键,必须是唯一的
Code string `db:"code"`
// 关联索引:Token Exchange 时需验证 ClientID,且包含 UserID
ClientID BinaryUUID `db:"client_id"`
UserID BinaryUUID `db:"user_id"`
AuthTime time.Time `db:"auth_time"`
// ExpiresAt: 必须加索引,用于定期清理过期数据 (GC)
ExpiresAt time.Time `db:"expires_at"`
// ACR/AMR: 认证上下文 (可选)
ACR string `db:"acr"`
AMR []AMR `db:"amr"`
SessionID string `db:"session_id"` // SSO会话ID,用于注销广播
// 原始请求参数校验
RedirectURI string `db:"redirect_uri"`
Scope string `db:"scope"`
Nonce string `db:"nonce"`
// PKCE (RFC 7636): 必须字段
CodeChallenge string `db:"code_challenge"`
CodeChallengeMethod string `db:"code_challenge_method"`
// DPoP JKT (RFC 9449): 绑定指纹,防止 Code 窃取
DPoPJKT string `db:"d_pop_jkt"`
}
AuthCodeSession 授权码会话 (临时数据), 这些信息需要在 Exchange 阶段被恢复。 存活时间极短 (通常 < 10分钟),读写极高
func (AuthCodeSession) TableName ¶ added in v0.3.0
func (AuthCodeSession) TableName() string
type AuthCodeStorage ¶
type AuthCodeStorage interface {
// AuthCodeSave 存储生成的授权码及其上下文。
AuthCodeSave(ctx context.Context, session *AuthCodeSession) error
// AuthCodeConsume 查找并标记为已使用(防止重放)。
// 这是一个原子操作:读取的同时必须确保下次读取失败或标记为已消耗。
// 如果未找到或已过期/已消耗,应返回 ErrCodeNotFound。
AuthCodeConsume(ctx context.Context, code string) (*AuthCodeSession, error)
}
type AuthorizeRequest ¶
type AuthorizeRequest struct {
// 必需参数
ClientID string `form:"client_id" json:"client_id"`
RedirectURI string `form:"redirect_uri" json:"redirect_uri"`
ResponseType string `form:"response_type" json:"response_type"` // 目前仅支持 "code"
// 可选参数
Scope string `form:"scope" json:"scope"`
State string `form:"state" json:"state"`
Nonce string `form:"nonce" json:"nonce"`
CodeChallenge string `form:"code_challenge" json:"code_challenge"`
CodeChallengeMethod string `form:"code_challenge_method" json:"code_challenge_method"`
ACRValues string `form:"acr_values" json:"acr_values"`
// PAR (RFC 9126): 推送授权请求 URI
// 如果存在,忽略其他参数,从 PARStorage 加载完整请求
RequestURI string `form:"request_uri" json:"request_uri"`
// DPoP (RFC 9449): JWK Thumbprint from DPoP proof
// 由 HTTP Handler 验证 DPoP Proof 后提取并传入
// 将被绑定到 Auth Code,在 Token Exchange 时验证
DPoPJKT string `form:"-" json:"-"`
// 上下文数据 (由调用者在用户登录/确认后填充)
UserID string `form:"-" json:"-"`
SessionID string `form:"-" json:"-"` // SSO会话ID
FinalScope string `form:"-" json:"-"`
AuthTime *jwt.NumericDate `form:"-" json:"-"`
ACR string `form:"-" json:"-"`
AMR []AMR `form:"-" json:"-"`
}
AuthorizeRequest 封装授权端点的请求参数
func LoadPARSession ¶
func LoadPARSession(ctx context.Context, storage PARStorage, requestURI string) (*AuthorizeRequest, error)
LoadPARSession 从 request_uri 加载授权请求参数 仅在 /authorize 端点内部使用
type BinaryUUID ¶
BinaryUUID 包装标准 UUID,强制数据库交互使用二进制
func NewBinaryUUID ¶ added in v0.3.0
func NewBinaryUUID() (BinaryUUID, error)
NewBinaryUUID 创建一个 uuid v7
func (BinaryUUID) GormDBDataType ¶ added in v0.5.1
GormDBDataType 针对不同数据库返回合法的二进制字段类型
func (BinaryUUID) MarshalJSON ¶
func (b BinaryUUID) MarshalJSON() ([]byte, error)
MarshalJSON 必须重写!否则 Go 会把底层 [16]byte 转成 Base64 字符串
func (*BinaryUUID) Scan ¶
func (b *BinaryUUID) Scan(value interface{}) error
Scan 实现 sql.Scanner (从数据库读取)
func (*BinaryUUID) UnmarshalJSON ¶
func (b *BinaryUUID) UnmarshalJSON(data []byte) error
UnmarshalJSON 从字符串解析,空字符串映射为 uuid.Nil
type Cache ¶
type Cache interface {
AuthCodeStorage // 极短 TTL
DeviceCodeStorage // 短 TTL
DistributedLock // 分布式锁
PARStorage // 极短 TTL
ReplayCache // DPoP JTI 防重放
RevocationStorage // Access Token 黑名单 (高频读取)
// 用于多级缓存, “缓存穿透”和“回写”的逻辑
KeyStorage // JWK (基础设施)
ClientCache
TokenCache
}
Cache 负责临时、高频、需要自动过期的数据 建议实现:Redis
type ClientCache ¶
type ClientCache interface {
// ClientGetByID 从缓存获取客户端
ClientGetByID(ctx context.Context, clientID BinaryUUID) (RegisteredClient, error)
// ClientSave 将客户端存入缓存
ClientSave(ctx context.Context, client RegisteredClient, ttl time.Duration) error
// ClientInvalidate 从缓存中移除客户端
ClientInvalidate(ctx context.Context, clientID BinaryUUID) error
}
ClientCache 定义了客户端信息的缓存接口。
type ClientFactory ¶
type ClientFactory interface {
New() RegisteredClient
}
ClientFactory 定义了创建客户端的接口。
type ClientMetadata ¶
type ClientMetadata struct {
// ID: 主键,使用 UUID
ID BinaryUUID `db:"id"`
// OwnerID: 用于查询“我创建的应用”,需要索引
OwnerID BinaryUUID `db:"owner_id"`
// Secret: 客户端密钥,经过哈希,预留足够长度
Secret SecretString `db:"secret"`
// Name: 应用名称
Name string `db:"name"`
// 数组类型处理:
RedirectURIs StringSlice `db:"redirect_uris" json:"redirect_uris"`
LogoutRedirectURIs StringSlice `db:"logout_redirect_uris" json:"logout_redirect_uris"`
GrantTypes StringSlice `db:"grant_types" json:"grant_types"`
// Scope: 空格分隔的字符串,或者也可以用 type:text
Scope string `db:"scope"`
LogoURI string `db:"logo_uri"`
TokenEndpointAuthMethod string `db:"token_endpoint_auth_method"`
// IsConfidentialClient: 区分公开/机密客户端
IsConfidentialClient bool `db:"is_confidential_client"`
// Back-Channel Logout
BackchannelLogoutURI string `db:"backchannel_logout_uri"`
BackchannelLogoutSessionRequired bool `db:"backchannel_logout_session_required"`
CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"`
}
ClientMetadata 客户端注册信息 对应 OAuth 2.0 Dynamic Client Registration Protocol
func (*ClientMetadata) Deserialize ¶ added in v0.3.0
func (c *ClientMetadata) Deserialize(data string) error
func (*ClientMetadata) GetBackchannelLogoutSessionRequired ¶ added in v0.4.0
func (c *ClientMetadata) GetBackchannelLogoutSessionRequired() bool
func (*ClientMetadata) GetBackchannelLogoutURI ¶ added in v0.4.0
func (c *ClientMetadata) GetBackchannelLogoutURI() string
func (*ClientMetadata) GetGrantTypes ¶ added in v0.3.0
func (c *ClientMetadata) GetGrantTypes() []string
func (*ClientMetadata) GetID ¶ added in v0.3.0
func (c *ClientMetadata) GetID() BinaryUUID
func (*ClientMetadata) GetLogoutRedirectURIs ¶ added in v0.4.0
func (c *ClientMetadata) GetLogoutRedirectURIs() []string
func (*ClientMetadata) GetRedirectURIs ¶ added in v0.3.0
func (c *ClientMetadata) GetRedirectURIs() []string
func (*ClientMetadata) GetScope ¶ added in v0.3.0
func (c *ClientMetadata) GetScope() string
func (*ClientMetadata) IsConfidential ¶
func (c *ClientMetadata) IsConfidential() bool
func (*ClientMetadata) Metadata ¶ added in v0.3.2
func (c *ClientMetadata) Metadata() *ClientMetadata
func (*ClientMetadata) Serialize ¶ added in v0.3.0
func (c *ClientMetadata) Serialize() (string, error)
func (ClientMetadata) TableName ¶ added in v0.3.0
func (ClientMetadata) TableName() string
func (*ClientMetadata) ValidateSecret ¶ added in v0.3.0
ValidateSecret 需要 hasher 协助,这里只提供数据,逻辑在 Server 层或 Storage 方法中 为了满足接口,我们在 Storage 实现中处理,这里仅作占位
type ClientRegistrationRequest ¶
type ClientRegistrationRequest struct {
RedirectURIs []string `json:"redirect_uris"`
LogoutRedirectURIs []string `json:"logout_redirect_uris,omitempty"`
GrantTypes []string `json:"grant_types"`
ResponseTypes []string `json:"response_types"`
Scope string `json:"scope"`
ClientName string `json:"client_name"`
LogoURI string `json:"logo_uri,omitempty"`
ClientURI string `json:"client_uri,omitempty"`
// auth_method 决定了是否需要生成 secret
// options: client_secret_basic, client_secret_post, none, private_key_jwt
TokenEndpointAuthMethod string `json:"token_endpoint_auth_method"`
// 扩展字段:绑定所有者
OwnerID string `json:"-"`
}
ClientRegistrationRequest RFC 7591 Client Registration Request
type ClientRegistrationResponse ¶
type ClientRegistrationResponse struct {
ClientID string `json:"client_id"`
ClientSecret string `json:"client_secret,omitempty"` // 仅在创建或重置时返回明文
ClientSecretExpiresAt int64 `json:"client_secret_expires_at,omitempty"`
RedirectURIs []string `json:"redirect_uris"`
LogoutRedirectURIs []string `json:"logout_redirect_uris,omitempty"`
GrantTypes []string `json:"grant_types"`
Scope string `json:"scope"`
ClientName string `json:"client_name"`
LogoURI string `json:"logo_uri,omitempty"`
TokenEndpointAuthMethod string `json:"token_endpoint_auth_method"`
RegistrationAccessToken string `json:"registration_access_token,omitempty"`
RegistrationClientURI string `json:"registration_client_uri,omitempty"`
}
ClientRegistrationResponse RFC 7591 Response
func ClientUpdate ¶ added in v0.3.0
func ClientUpdate(ctx context.Context, storage ClientStorage, req *ClientUpdateRequest) (*ClientRegistrationResponse, error)
ClientUpdate 更新客户端信息 RFC 7592: Update Request
func RegisterClient ¶
func RegisterClient(ctx context.Context, storage ClientStorage, hasher Hasher, req *ClientRegistrationRequest) (*ClientRegistrationResponse, error)
RegisterClient 处理新客户端注册 hasher: 必填,用于对生成的 Secret 进行哈希处理后再存入 DB
type ClientStorage ¶
type ClientStorage interface {
// ClientGetByID 根据 ID 获取客户端详情。
// 如果未找到,应返回 ErrClientNotFound。
ClientGetByID(ctx context.Context, clientID BinaryUUID) (RegisteredClient, error)
// ClientCreate 注册新客户端
// 注意:metadata.Secret 必须已经通过 Hasher.Hash() 哈希处理
ClientCreate(ctx context.Context, metadata *ClientMetadata) (RegisteredClient, error)
// ClientUpdate 更新客户端元数据
ClientUpdate(ctx context.Context, metadata *ClientMetadata) (RegisteredClient, error)
// ClientDeleteByID 删除客户端
ClientDeleteByID(ctx context.Context, clientID BinaryUUID) error
// ClientListByOwner 根据所有者查询客户端 (可选)
ClientListByOwner(ctx context.Context, ownerID BinaryUUID, query ListQuery) ([]RegisteredClient, error)
// ClientListAll 列出所有客户端
ClientListAll(ctx context.Context, query ListQuery) ([]RegisteredClient, error)
}
ClientStorage 定义了获取客户端信息的接口。
type ClientUpdateRequest ¶
type ClientUpdateRequest struct {
ClientID string `json:"client_id"`
*ClientRegistrationRequest
}
ClientUpdateRequest RFC 7591 Client Update Request
type ClientVerifier ¶
type ClientVerifier struct {
// contains filtered or unexported fields
}
ClientVerifier 用于客户端验证 OIDC ID Token。
func NewClientVerifier ¶
func NewClientVerifier(issuer, clientID string, keySet KeySource) *ClientVerifier
NewClientVerifier 创建一个新的客户端验证器。 issuer: 必须完全匹配 Token 中的 iss。 clientID: 必须包含在 Token 的 aud 中。
func (*ClientVerifier) SetSupportedSigningAlgs ¶
func (v *ClientVerifier) SetSupportedSigningAlgs(algs []string)
SetSupportedSigningAlgs 设置支持的签名算法
func (*ClientVerifier) Verify ¶
func (v *ClientVerifier) Verify(ctx context.Context, rawToken string) (*IDTokenClaims, error)
Verify 解析并验证原始 ID Token 字符串。
type Code ¶
type Code SecretString
type DPoPClaims ¶
type DPoPClaims struct {
JKT string // JWK Thumbprint,用于绑定到 Access Token
ATH string // Access Token hash (RFC 9449)
}
DPoPClaims 存储 DPoP 验证后的信息
func DPoPFromContext ¶
func DPoPFromContext(ctx context.Context) (*DPoPClaims, bool)
DPoPFromContext 从 context 中提取 DPoP 验证结果 返回 (claims, ok),如果 ok == false 表示未使用 DPoP
type DPoPProof ¶
type DPoPProof struct {
jwt.RegisteredClaims
// htm: HTTP 方法 (必需)
HTM string `json:"htm"`
// htu: HTTP URI (必需,不包含查询参数和片段)
HTU string `json:"htu"`
// ath: Access Token 哈希 (DPoP 访问受保护资源时必需)
ATH string `json:"ath,omitempty"`
// Nonce: 可选,服务器可以要求客户端包含 nonce 以防重放
Nonce string `json:"nonce,omitempty"`
}
DPoPProof 表示 DPoP Proof JWT 的 Claims RFC 9449 Section 4.2
type DPoPTimeSkewError ¶
type DPoPTimeSkewError struct {
Info DPoPTimeSkewInfo
Err error
}
DPoPTimeSkewError DPoP 时间偏差错误 包含详细的时间信息以便客户端调试
func (*DPoPTimeSkewError) Error ¶
func (e *DPoPTimeSkewError) Error() string
func (*DPoPTimeSkewError) Unwrap ¶
func (e *DPoPTimeSkewError) Unwrap() error
type DPoPTimeSkewInfo ¶
DPoPTimeSkewInfo 记录 DPoP 时间偏差信息
type DeviceAuthorizationResponse ¶
type DeviceAuthorizationResponse struct {
DeviceCode string `json:"device_code"`
UserCode string `json:"user_code"`
VerificationURI string `json:"verification_uri"`
ExpiresIn int `json:"expires_in"`
Interval int `json:"interval,omitempty"` // Polling interval in seconds
}
func DeviceAuthorization ¶
func DeviceAuthorization(ctx context.Context, storage Storage, issuer string, req *DeviceAuthorizationRequest) (*DeviceAuthorizationResponse, error)
DeviceAuthorization 处理设备授权请求
type DeviceAuthorizedRequest ¶
type DeviceCodeSession ¶
type DeviceCodeSession struct {
// DeviceCode: 设备换取 Token 的凭证,主键
DeviceCode string `db:"device_code"`
// UserCode: 用户在浏览器输入的短码,必须唯一且有索引
UserCode string `db:"user_code"`
ClientID BinaryUUID `db:"client_id"`
UserID BinaryUUID `db:"user_id"` // 初始为空,用户授权后填充
ExpiresAt time.Time `db:"expires_at"` // 用于清理
LastPolled time.Time `db:"last_polled"` // 用于频率限制 (Rate Limiting)检查
Scope string `db:"scope"`
// Status: pending, allowed, denied
Status string `db:"status"`
AuthorizedScope string `db:"authorized_scope"` // 用户实际同意的 Scope
AuthTime time.Time `db:"auth_time"` // 用户完成认证的时间
}
DeviceCodeSession 设备流会话 (RFC 8628)
func (DeviceCodeSession) TableName ¶ added in v0.3.0
func (DeviceCodeSession) TableName() string
type DeviceCodeStorage ¶
type DeviceCodeStorage interface {
// DeviceCodeSave 存储设备码和用户码
DeviceCodeSave(ctx context.Context, session *DeviceCodeSession) error
// DeviceCodeGet 根据设备码获取会话
DeviceCodeGet(ctx context.Context, deviceCode string) (*DeviceCodeSession, error)
// DeviceCodeGetByUserCode 根据用户码获取会话 (用于用户授权页面)
DeviceCodeGetByUserCode(ctx context.Context, userCode string) (*DeviceCodeSession, error)
// DeviceCodeUpdate 更新会话状态 (例如用户同意后)
DeviceCodeUpdate(ctx context.Context, deviceCode string, session *DeviceCodeSession) error
// DeviceCodeDelete 删除设备码会话及其关联索引
DeviceCodeDelete(ctx context.Context, deviceCode string) error
}
type Discovery ¶
type Discovery struct {
Issuer string `json:"issuer"`
AuthorizationEndpoint string `json:"authorization_endpoint"`
TokenEndpoint string `json:"token_endpoint"`
JWKSURI string `json:"jwks_uri"`
UserInfoEndpoint string `json:"userinfo_endpoint,omitempty"`
RevocationEndpoint string `json:"revocation_endpoint,omitempty"`
IntrospectionEndpoint string `json:"introspection_endpoint,omitempty"`
EndSessionEndpoint string `json:"end_session_endpoint,omitempty"`
RegistrationEndpoint string `json:"registration_endpoint,omitempty"`
DeviceAuthorizationEndpoint string `json:"device_authorization_endpoint,omitempty"`
PushedAuthorizationRequestEndpoint string `json:"pushed_authorization_request_endpoint,omitempty"` // RFC 9126
// 关键能力标识
ScopesSupported []string `json:"scopes_supported,omitempty"`
ResponseTypesSupported []string `json:"response_types_supported"`
ResponseModesSupported []string `json:"response_modes_supported,omitempty"`
GrantTypesSupported []string `json:"grant_types_supported,omitempty"`
SubjectTypesSupported []string `json:"subject_types_supported"`
IDTokenSigningAlgValuesSupported []string `json:"id_token_signing_alg_values_supported"`
TokenEndpointAuthMethodsSupported []string `json:"token_endpoint_auth_methods_supported,omitempty"`
ClaimsSupported []string `json:"claims_supported,omitempty"`
// PKCE 支持
CodeChallengeMethodsSupported []string `json:"code_challenge_methods_supported,omitempty"`
}
Discovery 定义了完整的 OpenID Provider 元数据 参见: RFC 8414, OIDC Discovery 1.0
type DistributedLock ¶
type DistributedLock interface {
// Lock 尝试获取锁
// ttl: 锁的自动过期时间
// 返回: true 如果获取成功, false 如果已被占用
Lock(ctx context.Context, key string, ttl time.Duration) (bool, error)
// Unlock 释放锁
Unlock(ctx context.Context, key string) error
}
DistributedLock 定义了分布式锁接口 用于密钥轮换等需要互斥的操作
type EndSessionRequest ¶
type EndSessionRequest struct {
IDTokenHint string
PostLogoutRedirectURI string
State string
// AccessToken 当前有效的 Access Token (可选)
// 如果提供,将被加入黑名单以实现即时登出
AccessToken string
}
EndSessionRequest RP-Initiated Logout Request
type Error ¶
type Error struct {
Code string `json:"error"` // e.g. "invalid_request"
Description string `json:"error_description"` // e.g. "Missing client_id"
StatusCode int `json:"-"` // HTTP 状态码 (仅用于 Token 端点)
}
Error 代表一个标准的 OAuth2 错误
func AccessDeniedError ¶
AccessDeniedError 创建 access_denied 错误 (HTTP 403)
func AuthorizationPendingError ¶
AuthorizationPendingError 创建 authorization_pending 错误 (HTTP 400) 用于 Device Flow
func ExpiredTokenError ¶
ExpiredTokenError 创建 expired_token 错误 (HTTP 400) 用于 Device Flow
func InvalidClientError ¶
InvalidClientError 创建 invalid_client 错误 (HTTP 401)
func InvalidGrantError ¶
InvalidGrantError 创建 invalid_grant 错误 (HTTP 400)
func InvalidRequestError ¶
InvalidRequestError 创建 invalid_request 错误 (HTTP 400)
func InvalidScopeError ¶
InvalidScopeError 创建 invalid_scope 错误 (HTTP 400)
func ServerError ¶ added in v0.3.0
ServerError 创建 server_error 错误 (HTTP 500)
func ServerErrorWithDescription ¶
ServerError 创建 server_error 错误 (HTTP 500)
func SlowDownError ¶
SlowDownError 创建 slow_down 错误 (HTTP 400) 用于 Device Flow
func TemporarilyUnavailableError ¶
TemporarilyUnavailableError 创建 temporarily_unavailable 错误 (HTTP 503)
func UnauthorizedClientError ¶
UnauthorizedClientError 创建 unauthorized_client 错误 (HTTP 400)
func UnsupportedGrantTypeError ¶
UnsupportedGrantTypeError 创建 unsupported_grant_type 错误 (HTTP 400)
func (*Error) PublicMessage ¶
PublicMessage 实现 httpx.PublicError 接口 (隐式) OAuth2 错误(如 invalid_grant)需要返回给客户端以供调试或处理,因此视为 safe。
type GCWorker ¶
type GCWorker struct {
// contains filtered or unexported fields
}
GCWorker 垃圾回收 Worker 定期调用 Persistence.Cleanup() 清理过期数据
func NewGCWorker ¶
func NewGCWorker(persistence Persistence, interval time.Duration) *GCWorker
NewGCWorker 创建 GC Worker interval: 清理间隔,建议 1 小时
type Hash256 ¶
type Hash256 []byte
Hash256 自定义类型,零依赖
func (Hash256) GormDBDataType ¶ added in v0.5.1
GormDBDataType 针对不同数据库返回合法的字段类型
func (Hash256) MarshalJSON ¶
func (*Hash256) UnmarshalJSON ¶
type Hasher ¶
type Hasher interface {
// Hash 对给定的明文密码进行哈希处理。
// 返回哈希后的字节切片或错误。
Hash(ctx context.Context, password []byte) ([]byte, error)
// Compare 将明文密码与已有的哈希值进行比较。
// 如果匹配,则返回nil;否则返回错误。
Compare(ctx context.Context, hashedPassword []byte, password []byte) error
}
Hasher 定义了密码哈希和验证的接口。
type IDToken ¶
type IDToken SecretString
type IDTokenClaims ¶
type IDTokenClaims struct {
jwt.RegisteredClaims
// OIDC 特定声明
Nonce string `json:"nonce,omitempty"` // 关联客户端会话的字符串值,用于缓解重放攻击
AuthorizedParty string `json:"azp,omitempty"` // 授权方 (Authorized Party),当 aud 包含多个值时必须存在
AtHash string `json:"at_hash,omitempty"` // Access Token 的哈希值,用于验证 Access Token
CHash string `json:"c_hash,omitempty"` // Code 的哈希值
AuthTime *jwt.NumericDate `json:"auth_time,omitempty"` // 终端用户认证发生的时间
SessionID string `json:"sid,omitempty"` // OIDC Front/Back-Channel Logout 需要的 Session ID
// Profile 声明 (标准 Scope: profile, email, phone)
Name *string `json:"name,omitempty"`
PreferredUsername *string `json:"preferred_username,omitempty"`
Picture *string `json:"picture,omitempty"`
Email *string `json:"email,omitempty"`
EmailVerified *bool `json:"email_verified,omitempty"` // 指针用于区分 false 和 null
PhoneNumber *string `json:"phone_number,omitempty"`
PhoneNumberVerified *bool `json:"phone_number_verified,omitempty"`
}
IDTokenClaims 表示 OIDC ID Token 的标准载荷。 参见: OIDC Core 1.0, Section 2.
func (*IDTokenClaims) SignedString ¶
func (ic *IDTokenClaims) SignedString(method jwt.SigningMethod, privateKey crypto.PrivateKey) (IDToken, error)
type IntrospectionRequest ¶ added in v0.3.3
type IntrospectionRequest struct {
Token string `form:"token" json:"token"` // 必填
TokenTypeHint string `form:"token_type_hint" json:"token_type_hint"` // 选填
// Client 认证信息 (自动通过 ClientAuthBinder 注入)
ClientID string `form:"client_id" json:"client_id"`
ClientSecret string `form:"client_secret" json:"client_secret"`
}
IntrospectionRequest 定义 RFC 7662 请求体 必须支持 Form 表单和 Basic Auth
type IntrospectionResponse ¶
type IntrospectionResponse 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"`
// DPoP (RFC 9449): Confirmation claim
Cnf map[string]interface{} `json:"cnf,omitempty"`
}
IntrospectionResponse RFC 7662 Introspection Response
func Introspect ¶
func Introspect(ctx context.Context, storage Storage, verifier TokenVerifier, tokenStr, clientIDStr, clientSecret string, hasher Hasher) (*IntrospectionResponse, error)
Introspect 验证 Token 状态 RFC 7662: OAuth 2.0 Token Introspection
type Issuer ¶
type Issuer struct {
// contains filtered or unexported fields
}
Issuer 负责生成符合 OIDC/OAuth2 标准的 Token
func NewIssuer ¶
func NewIssuer(cfg IssuerConfig, keyManager *KeyManager) (*Issuer, error)
NewIssuer 创建一个新的 Token 发行者
func (*Issuer) IssueClientCredentialsToken ¶
func (g *Issuer) IssueClientCredentialsToken(ctx context.Context, req *IssuerRequest) (*IssuerResponse, error)
IssueClientCredentialsToken 专门用于客户端凭证模式 只生成 Access Token,不生成 Refresh Token,不生成 ID Token
func (*Issuer) IssueOAuthTokens ¶
func (g *Issuer) IssueOAuthTokens(ctx context.Context, req *IssuerRequest) (*IssuerResponse, error)
func (*Issuer) IssueOIDCTokens ¶
func (g *Issuer) IssueOIDCTokens(ctx context.Context, req *IssuerRequest) (*IssuerResponse, error)
IssueOIDCTokens 生成 OIDC 套件 (ID Token + Access Token + Refresh Token)
func (*Issuer) IssuePasswordResetAccessToken ¶ added in v0.3.0
func (g *Issuer) IssuePasswordResetAccessToken(ctx context.Context, req *IssuerRequest) (*IssuerResponse, error)
IssuePasswordResetAccessToken 生成密码修改 AccessToken
func (*Issuer) RefreshOAuthTokens ¶
func (g *Issuer) RefreshOAuthTokens(ctx context.Context, req *IssuerRequest) (*IssuerResponse, error)
RefreshOAuthTokens 刷新 OAuth2 Token 注意:调用者负责验证旧 Refresh Token 的合法性,并将旧 Token 关联的信息填入 req
func (*Issuer) RefreshOIDCTokens ¶
func (g *Issuer) RefreshOIDCTokens(ctx context.Context, req *IssuerRequest) (*IssuerResponse, error)
RefreshOIDCTokens 刷新 OIDC Token 区别:ID Token 在刷新时不应包含 Nonce (OIDC Core 1.0 Section 12.1)
func (*Issuer) SecretManager ¶
func (i *Issuer) SecretManager() *SecretManager
type IssuerConfig ¶
type IssuerConfig struct {
Issuer string
SecretManager *SecretManager
// 默认 TTL (兜底策略)
AccessTokenTTL time.Duration
IDTokenTTL time.Duration
RefreshTokenTTL time.Duration
RefreshTokenGracePeriod time.Duration
}
IssuerConfig 配置签发的默认参数
type IssuerRequest ¶
type IssuerRequest struct {
ClientID BinaryUUID
UserID BinaryUUID // Subject (sub)
Scopes string // Space delimited scopes
Audience []string // Resource Server URIs
Nonce string // 仅用于 Implicit/AuthCode Flow 的 Issue 阶段
Code Code // 关联的 Authorization Code (如果适用,用于计算 c_hash)
AuthTime *jwt.NumericDate // 用户完成认证的时间
ACR string // 认证强度
AMR []AMR // 认证方法
SessionID string // SSO会话ID
// --- TTL 覆盖策略 ---
// 如果设置了以下字段(大于0),则使用该时间;否则使用 Config 中的默认时间。
AccessTokenDuration time.Duration
RefreshTokenDuration time.Duration
IDTokenDuration time.Duration
// --- User Profile ---
Name *string
PreferredUsername *string
Picture *string
Email *string
EmailVerified *bool
PhoneNumber *string
PhoneNumberVerified *bool
// DPoP (RFC 9449): JWK Thumbprint from DPoP proof
// 如果不为空,将在 Access Token 中添加 cnf.jkt claim
DPoPJKT string
}
IssuerRequest 包含生成 Token 所需的上下文信息
type IssuerResponse ¶
type IssuerResponse struct {
TokenType string `json:"token_type"` // Bearer
AccessToken string `json:"access_token"`
RefreshToken string `json:"refresh_token,omitempty"`
IDToken string `json:"id_token,omitempty"` // 仅在 OIDC 流程中存在
ExpiresIn int64 `json:"expires_in"`
Scope string `json:"scope,omitempty"`
}
IssuerResponse OAuth2 /oauth/token 响应结构
func DeviceTokenExchange ¶
func DeviceTokenExchange(ctx context.Context, storage Storage, issuer *Issuer, req *TokenRequest) (*IssuerResponse, error)
DeviceTokenExchange 处理设备码换取 Token
func ExchangeClientCredentials ¶
func ExchangeClientCredentials(ctx context.Context, storage ClientStorage, hasher Hasher, issuer *Issuer, req *TokenRequest) (*IssuerResponse, error)
ExchangeClientCredentials 处理 client_credentials 流程 (M2M)
func ExchangeCode ¶
func ExchangeCode(ctx context.Context, storage Storage, hasher Hasher, issuer *Issuer, req *TokenRequest) (*IssuerResponse, error)
ExchangeCode 用于处理 authorization_code 流程
func PasswordGrant ¶
func PasswordGrant(ctx context.Context, storage Storage, hasher Hasher, issuer *Issuer, req *TokenRequest) (*IssuerResponse, error)
PasswordGrant 生产存根实现,总是返回 "unsupported grant type" 错误。 这个函数确保了在生产构建中调用 password grant 逻辑会安全地失败,并且二进制文件中不包含任何实际的处理代码。
func RefreshTokens ¶
func RefreshTokens(ctx context.Context, storage Storage, secretManager *SecretManager, hasher Hasher, issuer *Issuer, req *TokenRequest) (*IssuerResponse, error)
RefreshTokens 用于处理 refresh_token 流程
type JSONWebKey ¶
type JSONWebKey struct {
Kty string `json:"kty"` // Key Type (RSA, EC, OKP)
Kid string `json:"kid,omitempty"` // Key ID
Use string `json:"use,omitempty"` // Public Key Use (sig, enc)
Alg string `json:"alg,omitempty"` // Algorithm (RS256, ES256, EdDSA...)
// RSA 字段
N string `json:"n,omitempty"` // Modulus (Base64URL)
E string `json:"e,omitempty"` // Exponent (Base64URL)
// ECDSA / Ed25519 字段
Crv string `json:"crv,omitempty"` // Curve (P-256, P-384, P-521, Ed25519)
X string `json:"x,omitempty"` // X Coordinate (Base64URL)
Y string `json:"y,omitempty"` // Y Coordinate (Base64URL), Ed25519 不需要此字段
}
JSONWebKey 表示单个 JWK 的结构。
func PublicKeyToJWK ¶
func PublicKeyToJWK(pub crypto.PublicKey, kid, alg string) (JSONWebKey, error)
PublicKeyToJWK 将标准库的 crypto.PublicKey 转换为 JWK 结构体。
func (*JSONWebKey) Thumbprint ¶
func (jwk *JSONWebKey) Thumbprint() (string, error)
Thumbprint 根据 RFC 7638 计算 JWK Thumbprint (SHA-256) 常用于生成 kid
type JSONWebKeySet ¶
type JSONWebKeySet struct {
Keys []JSONWebKey `json:"keys"`
}
JSONWebKeySet 表示 JWKS 端点返回的顶级 JSON 结构。
type JWK ¶ added in v0.3.0
type JWK struct {
// KID: Key ID,主键
KID string `db:"kid"`
// JWK: 包含私钥的大段 JSON 文本,使用 text 类型
JWK SecretString `db:"jwk"`
CreatedAt time.Time `db:"created_at"`
}
JWK 存储轮转的加密密钥
type Key ¶
type Key interface {
crypto.PrivateKey
Public() crypto.PublicKey
Equal(x crypto.PrivateKey) bool
Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error)
}
Key 接口定义了一个可用于签名的私钥所需的方法。
func LoadOrGenerateKey ¶
LoadOrGenerateKey 尝试从指定路径加载私钥。 如果文件存在,则加载它;如果不存在,则生成一个新密钥并保存。
type KeyManager ¶
type KeyManager struct {
// contains filtered or unexported fields
}
KeyManager 负责管理服务端的私钥集合。 它支持密钥轮换、JWKS 导出以及查找当前签名密钥。 现在的实现是无状态的(依赖 KeyStorage),但保留了本地缓存以提高性能。
func NewKeyManager ¶
func NewKeyManager(storage KeyStorage, cacheTTL time.Duration) *KeyManager
NewKeyManager 创建密钥管理器
func (*KeyManager) ExportJWKS ¶
func (km *KeyManager) ExportJWKS(ctx context.Context) (*JSONWebKeySet, error)
ExportJWKS 导出所有公钥为 JWKS 结构。
func (*KeyManager) GetKeyInternal ¶
GetKeyInternal 获取私钥 (Key 接口)
func (*KeyManager) GetSigningKey ¶
GetSigningKey 获取当前用于签名的私钥和 kid。
func (*KeyManager) JWKGetSigning ¶ added in v0.3.0
func (km *KeyManager) JWKGetSigning(ctx context.Context) (string, error)
JWKGetSigning 获取当前签名密钥 ID
func (*KeyManager) ListKeys ¶
func (km *KeyManager) ListKeys(ctx context.Context) ([]string, error)
ListKeys 返回所有密钥的 KID 列表
func (*KeyManager) RemoveKey ¶
func (km *KeyManager) RemoveKey(ctx context.Context, kid string) error
RemoveKey 删除指定的密钥。
func (*KeyManager) SetSigningKeyID ¶
func (km *KeyManager) SetSigningKeyID(ctx context.Context, kid string) error
SetSigningKeyID 指定哪个 kid 用于签名。
type KeyProvider ¶
type KeyProvider interface {
// GetKey 获取指定版本的密钥
GetKey(ctx context.Context, kid string) ([]byte, error)
// GetActiveKey 获取当前活跃的签名密钥
GetActiveKey(ctx context.Context) (string, []byte, error)
// ListKeys 列出所有可用密钥(用于验证)
// 返回 map[kid]key,包括活跃密钥和处于宽限期的旧密钥
ListKeys(ctx context.Context) (map[string][]byte, error)
}
KeyProvider 定义密钥获取接口,支持内存、KMS、HSM 等多种实现 这是依赖倒置原则的体现:核心逻辑依赖抽象接口,而非具体实现
type KeyRotationConfig ¶
type KeyRotationConfig struct {
// RotationInterval 密钥轮换间隔(例如 30 天)
RotationInterval time.Duration
// GracePeriod 旧密钥保留期,用于验证旧 Token(例如 7 天)
GracePeriod time.Duration
// KeyType 生成的密钥类型
KeyType KeyType
// EnableAutoRotate 是否启用自动定时轮换
EnableAutoRotate bool
// CleanupInterval 清理过期密钥的检查间隔
// 如果为 0,默认为 1 分钟
// 测试时可设置为较短时间(如 1 秒)
CleanupInterval time.Duration
}
KeyRotationConfig 密钥轮换配置
type KeyRotationScheduler ¶
type KeyRotationScheduler struct {
// contains filtered or unexported fields
}
KeyRotationScheduler 密钥轮换调度器 负责编排密钥的完整生命周期:生成 → 签名 → 宽限期 → 删除
func NewKeyRotationScheduler ¶
func NewKeyRotationScheduler(manager *KeyManager, lock DistributedLock, config KeyRotationConfig) *KeyRotationScheduler
NewKeyRotationScheduler 创建密钥轮换调度器
func (*KeyRotationScheduler) GetCurrentKeyID ¶
func (s *KeyRotationScheduler) GetCurrentKeyID() string
GetCurrentKeyID 获取当前签名密钥 ID
func (*KeyRotationScheduler) GetPendingDeletes ¶
func (s *KeyRotationScheduler) GetPendingDeletes() map[string]time.Time
GetPendingDeletes 获取待删除密钥列表(用于监控)
func (*KeyRotationScheduler) RotateNow ¶
func (s *KeyRotationScheduler) RotateNow(ctx context.Context) error
RotateNow 立即触发一次密钥轮换 适用于安全事件响应或手动干预
type KeySource ¶
type KeySource interface {
// GetKey 根据 Key ID (kid) 返回对应的公钥。
// 如果 kid 为空,且源中只有一个 key,应返回该 key。
GetKey(ctx context.Context, kid string) (crypto.PublicKey, error)
}
KeySource 定义了验证器如何获取公钥。 它可以是静态的 JWKS,也可以是远程 URL (OIDC Discovery)。
type KeyStorage ¶
type KeyStorage interface {
// JWKSave 存储一个 JWK (包含私钥)
// 如果 key 已存在,应该覆盖或返回错误(取决于实现,通常是覆盖)
JWKSave(ctx context.Context, key jwk.Key) error
// JWKGet 获取指定 kid 的 JWK
JWKGet(ctx context.Context, kid string) (jwk.Key, error)
// JWKList 获取所有存储的 JWK
JWKList(ctx context.Context) ([]jwk.Key, error)
// JWKDelete 删除指定 kid 的 JWK
JWKDelete(ctx context.Context, kid string) error
// JWKMarkSigning 存储当前签名密钥 ID
JWKMarkSigning(ctx context.Context, kid string) error
// JWKGetSigning 获取当前签名密钥 ID
JWKGetSigning(ctx context.Context) (string, error)
}
KeyStorage 定义了私钥的持久化存储接口 必须支持分布式环境下的并发访问
type LogoutTokenClaims ¶ added in v0.4.0
type LogoutTokenClaims struct {
jwt.RegisteredClaims
Events map[string]interface{} `json:"events"`
SessionID string `json:"sid,omitempty"`
}
LogoutTokenClaims 表示 OIDC Back-Channel Logout Token 的标准载荷。
func (*LogoutTokenClaims) SignedString ¶ added in v0.4.0
func (lc *LogoutTokenClaims) SignedString(method jwt.SigningMethod, privateKey crypto.PrivateKey) (string, error)
type MemoryKeyProvider ¶
type MemoryKeyProvider struct {
// contains filtered or unexported fields
}
MemoryKeyProvider 内存实现,保持现有行为 适用于开发环境和不需要 KMS 的简单部署
func NewMemoryKeyProvider ¶
func NewMemoryKeyProvider() *MemoryKeyProvider
NewMemoryKeyProvider 创建内存密钥提供者
func (*MemoryKeyProvider) AddKey ¶
func (m *MemoryKeyProvider) AddKey(kid string, key []byte) error
AddKey 添加新密钥
func (*MemoryKeyProvider) GetActiveKey ¶
GetActiveKey 实现 KeyProvider 接口
func (*MemoryKeyProvider) RemoveKey ¶
func (m *MemoryKeyProvider) RemoveKey(kid string) error
RemoveKey 删除密钥 注意:不能删除当前活跃的密钥
func (*MemoryKeyProvider) RotateKey ¶
func (m *MemoryKeyProvider) RotateKey(newKID string, newKey []byte, gracePeriod time.Duration) error
RotateKey 轮换密钥(优雅轮换) 1. 添加新密钥 2. 切换活跃密钥 3. 将旧密钥标记为 deprecated(但保留验证能力)
func (*MemoryKeyProvider) SetActiveKey ¶
func (m *MemoryKeyProvider) SetActiveKey(kid string) error
SetActiveKey 设置活跃密钥
type PARRequest ¶
type PARRequest struct {
// 客户端认证信息 (必需)
ClientID string `form:"client_id" json:"client_id"`
ClientSecret string `form:"client_secret" json:"client_secret"` // 对于机密客户端
// 授权请求参数 (与标准 /authorize 端点相同)
RedirectURI string `form:"redirect_uri" json:"redirect_uri"`
ResponseType string `form:"response_type" json:"response_type"`
Scope string `form:"scope" json:"scope"`
State string `form:"state" json:"state"`
Nonce string `form:"nonce" json:"nonce"`
// PKCE
CodeChallenge string `form:"code_challenge" json:"code_challenge"`
CodeChallengeMethod string `form:"code_challenge_method" json:"code_challenge_method"`
// ACR
ACRValues string `form:"acr_values" json:"acr_values"`
ACR string `form:"-" json:"-"`
AMR []AMR `form:"-" json:"-"`
// DPoP (RFC 9449): JWK Thumbprint from DPoP proof
// 由 HTTP Handler 验证 DPoP Proof 后提取并传入
DPoPJKT string `form:"-" json:"-"`
// 扩展参数
AdditionalParams map[string]string `form:"-" json:"-"`
}
PARRequest 表示推送授权请求的参数 RFC 9126 Section 2
type PARResponse ¶
type PARResponse struct {
RequestURI string `json:"request_uri"` // 格式: urn:ietf:params:oauth:request_uri:...
ExpiresIn int `json:"expires_in"` // 秒数,典型值 60
}
PARResponse 表示 PAR 端点的响应 RFC 9126 Section 2.2
func PushedAuthorization ¶
func PushedAuthorization( ctx context.Context, storage Storage, hasher Hasher, req *PARRequest, ) (*PARResponse, error)
PushedAuthorization 处理推送授权请求 RFC 9126: 客户端通过后端通道提交授权参数,获得 request_uri
安全要求: - 必须验证客户端身份 (Client Secret 或 mTLS) - 所有授权参数必须经过验证 - request_uri 只能使用一次 - TTL 应较短 (推荐 60 秒)
type PARStorage ¶
type PARStorage interface {
// PARSessionSave 保存 PAR 会话
// requestURI: 格式为 "urn:ietf:params:oauth:request_uri:<唯一标识>"
// req: 完整的授权请求参数
// ttl: 会话有效期,RFC 建议 60 秒
PARSessionSave(ctx context.Context, requestURI string, req *AuthorizeRequest, ttl time.Duration) error
// PARSessionConsume 获取并删除 PAR 会话(原子操作)
// PAR request_uri 只能使用一次
PARSessionConsume(ctx context.Context, requestURI string) (*AuthorizeRequest, error)
}
PARStorage 管理推送授权请求 (Pushed Authorization Requests) 会话 RFC 9126: OAuth 2.0 Pushed Authorization Requests
type Persistence ¶
type Persistence interface {
ClientStorage
KeyStorage // JWK (基础设施)
TokenStorage // Refresh Token (长效)
UserInfoGetter // 用户数据
UserAuthenticator
// Cleanup 清理过期的数据 (Garbage Collection)
// 此方法应删除已过期的 RefreshToken, AuthCode, DeviceCode 等临时数据
// 建议由后台 Worker 定期调用(例如每小时一次)
// 返回被清理的记录数和错误
Cleanup(ctx context.Context) (deleted int64, err error)
Close()
}
Persistence 负责长久存储的数据 建议实现:GORM (PostgreSQL)
type RefreshToken ¶
type RefreshToken SecretString
func IssueStructuredRefreshToken ¶
func IssueStructuredRefreshToken(ctx context.Context, sm *SecretManager, userID string, ttl time.Duration) (RefreshToken, error)
IssueStructuredRefreshToken 生成一个结构化的 Refresh Token
func (RefreshToken) HashForDB ¶
func (t RefreshToken) HashForDB() Hash256
HashForDB 刷新 token 使用 sha256 进行 hash 如果是结构化 Token (kid.meta.rand.sig),只 Hash 随机部分 (rand) 这配合签名验证可防止数据库 DoS,同时保证数据库索引的唯一性和安全性
type RefreshTokenSession ¶
type RefreshTokenSession struct {
// ID 默认为主键,无需标签
// GORM 默认将 Hash256 映射为对应类型(需实现 Scanner/Valuer)
ID Hash256
// 默认映射为 client_id,但在 db 标签中指定 index
ClientID BinaryUUID `db:"client_id"`
// 默认映射为 user_id,指定 index
UserID BinaryUUID `db:"user_id"`
// 指定数据库类型为 text
Scope string `db:"scope"`
// 默认映射 auth_time
AuthTime time.Time `db:"auth_time"`
// 默认映射 expires_at,指定 index
ExpiresAt time.Time `db:"expires_at"`
// 上下文信息
Nonce string `db:"nonce"` // 默认 varchar
ACR string `db:"acr"` // 默认 varchar
AMR StringSlice `db:"amr"`
SessionID string `db:"session_id"` // SSO会话ID
}
RefreshTokenSession 包含刷新令牌关联的上下文信息。
func (RefreshTokenSession) TableName ¶ added in v0.3.0
func (RefreshTokenSession) TableName() string
type RegisteredClient ¶
type RegisteredClient interface {
// GetID 返回客户端 ID
GetID() BinaryUUID
// GetRedirectURIs 返回注册的回调地址列表
GetRedirectURIs() []string
// GetLogoutRedirectURIs 返回注册的注销后回调地址列表 (OIDC RP-Initiated Logout)
GetLogoutRedirectURIs() []string
// GetGrantTypes 返回允许的授权类型 (e.g., "authorization_code", "refresh_token")
GetGrantTypes() []string
// GetScope 返回客户端注册的允许 Scopes 字符串 (空格分隔)
// OIDC Core 逻辑会用此与请求的 Scope 取交集
GetScope() string
// IsConfidential 返回是否为机密客户端 (Confidential vs Public)
IsConfidential() bool
// GetBackchannelLogoutURI 返回后端注销回调地址 (OIDC Back-Channel Logout)
GetBackchannelLogoutURI() string
// GetBackchannelLogoutSessionRequired 返回是否在注销时需要包含 sid
GetBackchannelLogoutSessionRequired() bool
// ValidateSecret 验证输入的明文密钥。
// 对于 Public Client,此方法应直接返回 nil。
// 对于 Confidential Client,实现层应处理哈希比对 (如 bcrypt/argon2)。
ValidateSecret(ctx context.Context, hasher Hasher, secret string) error
// 提供给Redis一个序列化和反序列化的方法
Serialize() (string, error)
Deserialize(string) error
// Metadata 获取客户端的元数据以便进行更新
Metadata() *ClientMetadata
}
RegisteredClient 定义了 OIDC 协议流程中所需的客户端视图。
func AuthenticateClient ¶
func AuthenticateClient(ctx context.Context, storage ClientStorage, clientIDStr, clientSecret string, hasher Hasher) (RegisteredClient, error)
AuthenticateClient 验证客户端身份
func GetAndVerifyClient ¶ added in v0.4.2
func GetAndVerifyClient(ctx context.Context, storage ClientStorage, clientIDStr string) (RegisteredClient, error)
GetAndVerifyClient 解析 clientID 并从存储中获取验证客户端
func ListClient ¶
func ListClient(ctx context.Context, storage ClientStorage, query ListQuery) ([]RegisteredClient, error)
ListClient 列出所有客户端
func RequestAuthorize ¶
func RequestAuthorize(ctx context.Context, storage Storage, req *AuthorizeRequest) (RegisteredClient, error)
RequestAuthorize 校验授权请求的基本参数。 这一步通常在显示登录页面或授权同意页面之前调用。 如果返回 error,调用者应直接向用户显示错误页,而不是重定向(因为 RedirectURI 可能尚未验证)。
PAR 支持 (RFC 9126): - 如果 req.RequestURI 存在,从 PARStorage 加载完整请求参数 - request_uri 只能使用一次
type RemoteKeySet ¶
type RemoteKeySet struct {
// contains filtered or unexported fields
}
RemoteKeySet 实现了 KeySource 接口。 它能够从远程 JWKS URI 获取公钥,并支持 Stale-While-Revalidate 缓存机制。
func NewRemoteKeySet ¶
func NewRemoteKeySet(ctx context.Context, jwksURI string, httpClient *http.Client, opts ...RemoteKeySetOption) *RemoteKeySet
NewRemoteKeySet 创建一个新的远程密钥集。 ctx: 用于控制 HTTP 请求的生命周期。 jwksURI: 远程 JWKS 地址。
type RemoteKeySetOption ¶
type RemoteKeySetOption func(*RemoteKeySet)
RemoteKeySetOption allows configuring RemoteKeySet
func WithCacheDuration ¶
func WithCacheDuration(d time.Duration) RemoteKeySetOption
WithCacheDuration sets the default cache duration
type ReplayCache ¶
type ReplayCache interface {
// CheckAndStore 原子性地检查 JTI 是否已使用,若未使用则存储。
// 返回 true 表示 JTI 已存在 (重放攻击),false 表示首次使用。
// ttl 参数指定 JTI 在缓存中的有效期。
CheckAndStore(ctx context.Context, jti string, ttl time.Duration) (bool, error)
}
ReplayCache 定义了防重放攻击的缓存接口。 用于 DPoP (RFC 9449) 的 JTI (JWT ID) 去重。
type ResourceVerifier ¶
type ResourceVerifier struct {
// contains filtered or unexported fields
}
ResourceVerifier 用于资源服务器验证 OIDC ID Token。
func NewResourceVerifier ¶
func NewResourceVerifier(issuer, resourceURI string, keySet KeySource, trustedClients []string) *ResourceVerifier
NewResourceVerifier 创建一个新的客户端验证器。 issuer: 必须完全匹配 Token 中的 iss。 resourceURI: 必须包含在 Token 的 aud 中。 trustedClients: 如果不为nil, 会限制使用本服务的请求客户端
func (*ResourceVerifier) SetSupportedSigningAlgs ¶
func (v *ResourceVerifier) SetSupportedSigningAlgs(algs []string)
SetSupportedSigningAlgs 设置支持的签名算法
func (*ResourceVerifier) Verify ¶
func (v *ResourceVerifier) Verify(ctx context.Context, rawToken string) (*AccessTokenClaims, error)
Verify 解析并验证原始 ID Token 字符串。
type RevocationRequest ¶
type RevocationRequest struct {
Token string `form:"token" json:"token"`
TokenTypeHint string `form:"token_type_hint" json:"token_type_hint"` // "access_token" 或 "refresh_token" (可选)
ClientID string `form:"client_id" json:"client_id"`
ClientSecret string `form:"client_secret" json:"client_secret"`
}
RevocationRequest 封装 RFC 7009 撤销请求参数
type RevocationStorage ¶
type RevocationStorage interface {
// AccessTokenRevoke 将 JTI (JWT ID) 加入黑名单,直到 expiration 时间。
AccessTokenRevoke(ctx context.Context, jti string, expiration time.Time) error
// AccessTokenIsRevoked 检查 JTI 是否在黑名单中。
AccessTokenIsRevoked(ctx context.Context, jti string) (bool, error)
}
RevocationStorage 用于管理 Access Token 的黑名单 (Revocation JWKList)。 Access Token 通常是无状态 JWT,一旦签发无法修改,撤销只能通过黑名单 (JTI) 实现。
type SecretBytes ¶ added in v0.3.0
type SecretBytes []byte
func (SecretBytes) GoString ¶ added in v0.3.0
func (s SecretBytes) GoString() string
func (SecretBytes) GormDBDataType ¶ added in v0.5.1
GormDBDataType 针对不同数据库返回合法的二进制字段类型
func (SecretBytes) MarshalJSON ¶ added in v0.3.0
func (s SecretBytes) MarshalJSON() ([]byte, error)
func (*SecretBytes) Scan ¶ added in v0.3.0
func (s *SecretBytes) Scan(value interface{}) error
func (SecretBytes) String ¶ added in v0.3.0
func (s SecretBytes) String() string
func (*SecretBytes) UnmarshalJSON ¶ added in v0.5.1
func (s *SecretBytes) UnmarshalJSON(b []byte) error
UnmarshalJSON 允许从 JSON 中读取原始值。 注意:Go 标准 JSON(及 sonic)对 []byte 的编解码使用 base64, 因此 JSON 中的值必须是 base64 编码的字符串,而非普通字符串。
type SecretManager ¶
type SecretManager struct {
// contains filtered or unexported fields
}
SecretManager 管理 HMAC 密钥,用于 Refresh Token 签名 现在使用 KeyProvider 抽象,支持内存、KMS、HSM 等多种实现
func NewSecretManagerWithProvider ¶
func NewSecretManagerWithProvider(provider KeyProvider) *SecretManager
NewSecretManagerWithProvider 创建密钥管理器(使用自定义提供者)
func (*SecretManager) AddKey ¶
func (s *SecretManager) AddKey(id string, hexSecret string) error
AddKey 添加密钥(向后兼容的便捷方法) 注意:仅在 provider 是 MemoryKeyProvider 时可用
func (*SecretManager) GetSigningKey ¶
func (s *SecretManager) GetSigningKey(ctx context.Context) ([]byte, string)
GetSigningKey 获取签名用的密钥 (HMAC Key) 返回 (key, kid)
func (*SecretManager) GetVerificationKey ¶
GetVerificationKey 根据 Token 中的 kid 获取验证密钥
func (*SecretManager) RotateKey ¶
func (s *SecretManager) RotateKey(newKID string, newHexSecret string, gracePeriod time.Duration) error
RotateKey 轮换密钥(优雅轮换) gracePeriod: 旧密钥保留用于验证的时间
func (*SecretManager) SetActiveKey ¶
func (s *SecretManager) SetActiveKey(kid string) error
SetActiveKey 设置活跃密钥(向后兼容的便捷方法) 注意:仅在 provider 是 MemoryKeyProvider 时可用
type SecretString ¶ added in v0.3.0
type SecretString string
func (SecretString) GoString ¶ added in v0.3.0
func (s SecretString) GoString() string
func (SecretString) GormDBDataType ¶ added in v0.5.1
GormDBDataType 针对不同数据库返回合法的字段类型
func (SecretString) MarshalJSON ¶ added in v0.3.0
func (s SecretString) MarshalJSON() ([]byte, error)
func (*SecretString) Scan ¶ added in v0.3.0
func (s *SecretString) Scan(value interface{}) error
func (SecretString) String ¶ added in v0.3.0
func (s SecretString) String() string
func (*SecretString) UnmarshalJSON ¶ added in v0.5.1
func (s *SecretString) UnmarshalJSON(b []byte) error
UnmarshalJSON 允许从 JSON 中读取原始值(JSON string → SecretString)
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
Server 是 OIDC 协议的核心控制器。 它是一个 Facade (门面),组合了 Authorizer, Issuer, TokenHandler 等组件。 调用者应通过 NewServer 创建实例,并将其挂载到 HTTP 路由上。
func NewServer ¶
func NewServer(cfg ServerConfig) (*Server, error)
NewServer 初始化一个新的 OIDC 服务。 注意:初始化后,必须: 1. 调用 server.KeyManager().Add(...) 添加至少一个签名密钥 (RSA/EC) 2. 调用 server.SecretManager().AddKey(...) 添加至少一个 HMAC 密钥 (用于 Refresh Token) 3. 调用 server.ValidateKeys() 验证密钥配置 4. 启动 HTTP 服务
func (*Server) ClientUpdate ¶ added in v0.3.0
func (s *Server) ClientUpdate(ctx context.Context, req *ClientUpdateRequest) (*ClientRegistrationResponse, error)
ClientUpdate 处理动态客户端更新
func (*Server) Config ¶
func (s *Server) Config() *ServerConfig
func (*Server) DeviceAuthorization ¶
func (s *Server) DeviceAuthorization(ctx context.Context, req *DeviceAuthorizationRequest) (*DeviceAuthorizationResponse, error)
DeviceAuthorization 处理设备授权请求
func (*Server) Discovery ¶
Discovery 返回符合 OIDC Discovery 标准的元数据结构。 调用者应将其序列化为 JSON 并通过 /.well-known/openid-configuration 暴露。
func (*Server) EndSession ¶
EndSession 处理用户登出
func (*Server) Exchange ¶
func (s *Server) Exchange(ctx context.Context, req *TokenRequest) (resp *IssuerResponse, err error)
Exchange 处理 Token 交换
func (*Server) GetUserInfo ¶
GetUserInfo 获取用户信息
func (*Server) Introspect ¶
func (s *Server) Introspect(ctx context.Context, tokenStr, clientIDStr, clientSecret string) (*IntrospectionResponse, error)
Introspect 验证 Token 状态
func (*Server) KeyManager ¶
func (s *Server) KeyManager() *KeyManager
KeyManager 返回密钥管理器,用于添加、删除密钥或导出 JWKS。
func (*Server) ListClient ¶
ListClient 列出所有客户端
func (*Server) ParseAccessToken ¶
ParseAccessToken 解析并验证 Token 签名和 Issuer,但不检查撤销状态。
func (*Server) PushedAuthorization ¶
func (s *Server) PushedAuthorization(ctx context.Context, req *PARRequest) (*PARResponse, error)
PushedAuthorization 处理推送授权请求 (PAR - RFC 9126)
func (*Server) RegisterClient ¶
func (s *Server) RegisterClient(ctx context.Context, req *ClientRegistrationRequest) (*ClientRegistrationResponse, error)
RegisterClient 处理动态客户端注册
func (*Server) RequestAuthorize ¶
func (s *Server) RequestAuthorize(ctx context.Context, req *AuthorizeRequest) (client RegisteredClient, err error)
RequestAuthorize 校验授权请求
func (*Server) ResponseAuthorized ¶
func (s *Server) ResponseAuthorized(ctx context.Context, req *AuthorizeRequest) (redirectURL string, err error)
ResponseAuthorized 用户同意后生成重定向URL
func (*Server) RevokeToken ¶
func (s *Server) RevokeToken(ctx context.Context, req *RevocationRequest) error
RevokeToken 处理 Token 撤销
func (*Server) SecretManager ¶
func (s *Server) SecretManager() *SecretManager
SecretManager 返回 HMAC 密钥管理器,用于 Refresh Token 的签名管理。
func (*Server) StartBackgroundWorkers ¶
StartBackgroundWorkers 启动所有后台 Worker 应在 HTTP 服务启动之前调用 ctx 用于传递取消信号和 tracing context
func (*Server) StopBackgroundWorkers ¶
func (s *Server) StopBackgroundWorkers()
StopBackgroundWorkers 停止所有后台 Worker 应在 HTTP 服务关闭时调用
func (*Server) UnregisterClient ¶
UnregisterClient 处理动态客户端注销
func (*Server) ValidateKeys ¶
ValidateKeys 检查密钥管理器是否至少配置了一个签名密钥。 应在启动 HTTP 服务前调用,以尽早发现配置错误。
返回 ErrNoSigningKey 如果未配置任何签名密钥。
func (*Server) VerifyAccessToken ¶
func (s *Server) VerifyAccessToken(ctx context.Context, tokenStr string) (*AccessTokenClaims, error)
VerifyAccessToken 用于验证 Bearer Token 的有效性。 此实现不校验 Audience,因为 UserInfo 端点信任本 Issuer 签发的任何包含 openid scope 的 Token。
type ServerConfig ¶
type ServerConfig struct {
// Issuer 是服务的唯一标识符 (URL),例如 "https://auth.example.com"
Issuer string
// Storage 是数据持久层接口实现
Storage Storage
// Hasher 是密码哈希器
Hasher Hasher
// SecretManager 用于管理 Refresh Token 签名的对称密钥 (HMAC)
// 如果为 nil,NewServer 会初始化一个默认的 MemoryKeyProvider,但该 Provider 初始无密钥,
// 需要通过 server.SecretManager() 获取实例后添加密钥,或者在 Config 中直接传入配置好的实例。
SecretManager *SecretManager
// 令牌有效期配置 (若为 0,NewServer 会设置默认值)
CodeTTL time.Duration // 默认 5 分钟
AccessTokenTTL time.Duration // 默认 1 小时
RefreshTokenTTL time.Duration // 默认 30 天
IDTokenTTL time.Duration // 默认 1 小时
RefreshTokenGracePeriod time.Duration // 默认 30 秒
// SupportedSigningAlgs 支持的签名算法 (默认为 RS256, ES256)
SupportedSigningAlgs []string
// EnableGC 是否启用垃圾回收 Worker (默认为 true)
EnableGC bool
// GCInterval GC 执行间隔 (默认 1 小时)
GCInterval time.Duration
}
ServerConfig 用于初始化 OIDC Server 的配置
type StaticKeySet ¶
StaticKeySet 是 KeySource 的一个简单实现,用于基于本地 JWKS 验证 (单元测试或本地开发用)
func NewStaticKeySet ¶
func NewStaticKeySet() *StaticKeySet
type StringSlice ¶ added in v0.3.0
type StringSlice []string
func (StringSlice) GormDBDataType ¶ added in v0.5.1
GormDBDataType 针对不同的数据库返回不同的 JSON 类型定义
func (*StringSlice) Scan ¶ added in v0.3.0
func (ss *StringSlice) Scan(value interface{}) error
type TieredStorage ¶
type TieredStorage struct {
Persistence
Cache
ClientCacheTTL time.Duration
}
TieredStorage implements a two-layer storage strategy.
Consistency guarantees:
- Reads: Read-Through with version check
- Creates: Write-Through (fresh data, no race)
- Updates: Cache-Aside with version stamp
- Deletes: DB → invalidate cache
All cache failures are logged but never block the caller. TTL acts as the ultimate consistency backstop.
func NewTieredStorage ¶
func NewTieredStorage(db Persistence, cache Cache, opts ...TieredStorageOption) *TieredStorage
func (*TieredStorage) ClientCreate ¶ added in v0.3.0
func (s *TieredStorage) ClientCreate(ctx context.Context, metadata *ClientMetadata) (RegisteredClient, error)
func (*TieredStorage) ClientDeleteByID ¶ added in v0.3.0
func (s *TieredStorage) ClientDeleteByID(ctx context.Context, clientID BinaryUUID) error
func (*TieredStorage) ClientGetByID ¶ added in v0.3.0
func (s *TieredStorage) ClientGetByID(ctx context.Context, clientID BinaryUUID) (RegisteredClient, error)
func (*TieredStorage) ClientListAll ¶ added in v0.3.0
func (s *TieredStorage) ClientListAll(ctx context.Context, query ListQuery) ([]RegisteredClient, error)
func (*TieredStorage) ClientListByOwner ¶ added in v0.3.0
func (s *TieredStorage) ClientListByOwner(ctx context.Context, ownerID BinaryUUID, query ListQuery) ([]RegisteredClient, error)
func (*TieredStorage) ClientUpdate ¶ added in v0.3.0
func (s *TieredStorage) ClientUpdate(ctx context.Context, metadata *ClientMetadata) (RegisteredClient, error)
func (*TieredStorage) JWKDelete ¶ added in v0.3.0
func (s *TieredStorage) JWKDelete(ctx context.Context, kid string) error
func (*TieredStorage) JWKGetSigning ¶ added in v0.3.0
func (s *TieredStorage) JWKGetSigning(ctx context.Context) (string, error)
func (*TieredStorage) JWKMarkSigning ¶ added in v0.3.0
func (s *TieredStorage) JWKMarkSigning(ctx context.Context, kid string) error
func (*TieredStorage) RefreshTokenCreate ¶ added in v0.3.0
func (s *TieredStorage) RefreshTokenCreate(ctx context.Context, session *RefreshTokenSession) error
func (*TieredStorage) RefreshTokenGet ¶ added in v0.3.0
func (s *TieredStorage) RefreshTokenGet(ctx context.Context, tokenID Hash256) (*RefreshTokenSession, error)
func (*TieredStorage) RefreshTokenRevoke ¶ added in v0.3.0
func (s *TieredStorage) RefreshTokenRevoke(ctx context.Context, tokenID Hash256) error
func (*TieredStorage) RefreshTokenRevokeUser ¶ added in v0.3.0
func (s *TieredStorage) RefreshTokenRevokeUser(ctx context.Context, userID BinaryUUID) ([]Hash256, error)
func (*TieredStorage) RefreshTokenRotate ¶ added in v0.3.0
func (s *TieredStorage) RefreshTokenRotate( ctx context.Context, oldTokenID Hash256, newSession *RefreshTokenSession, gracePeriod time.Duration, ) error
type TieredStorageOption ¶ added in v0.5.1
type TieredStorageOption func(*TieredStorage)
func WithClientCacheTTL ¶ added in v0.5.1
func WithClientCacheTTL(ttl time.Duration) TieredStorageOption
type TokenCache ¶
type TokenCache interface {
// RefreshTokenGet 从缓存获取
RefreshTokenGet(ctx context.Context, tokenID Hash256) (*RefreshTokenSession, error)
// RefreshTokenSave 存入缓存
RefreshTokenSave(ctx context.Context, session *RefreshTokenSession, ttl time.Duration) error
// RefreshTokenRotate 令牌轮换:删除旧的,保存新的。如果保存新令牌失败,旧令牌也不应被删除(或者整个操作回滚)。
RefreshTokenRotate(ctx context.Context, oldTokenID Hash256, newSession *RefreshTokenSession, gracePeriod time.Duration) error
// RefreshTokenInvalidate 从缓存移除
RefreshTokenInvalidate(ctx context.Context, tokenID Hash256) error
// RefreshTokensInvalidate 批量从缓存移除
RefreshTokensInvalidate(ctx context.Context, tokenIDs []Hash256) error
}
TokenCache 定义了 Refresh Token 的缓存接口
type TokenRequest ¶
type TokenRequest struct {
GrantType string `form:"grant_type" json:"grant_type"`
ClientID string `form:"client_id" json:"client_id"`
ClientSecret string `form:"client_secret" json:"client_secret"`
RedirectURI string `form:"redirect_uri" json:"redirect_uri"`
// authorization_code 参数
Code string `form:"code" json:"code"`
CodeVerifier string `form:"code_verifier" json:"code_verifier"` // PKCE
// device_code 参数
DeviceCode string `form:"device_code" json:"device_code"`
// refresh_token 参数
RefreshToken string `form:"refresh_token" json:"refresh_token"`
// client_credentials 参数 (可选扩展)
Scope string `form:"scope" json:"scope"`
// password 参数 (可选扩展, 仅用于测试)
Username string `form:"username" json:"username"`
Password string `form:"password" json:"password"`
// DPoP (RFC 9449): JWK Thumbprint from DPoP proof
// 如果请求包含 DPoP header,验证后提取的 JKT
DPoPJKT string `form:"-" json:"-"` // 不从 body 绑定
}
TokenRequest 封装了 /token 端点的标准参数 对应 RFC 6749 Section 4.1.3 & 6
type TokenStorage ¶
type TokenStorage interface {
// RefreshTokenCreate 存储新的刷新令牌。
RefreshTokenCreate(ctx context.Context, session *RefreshTokenSession) error
// RefreshTokenGet 根据令牌 ID (或哈希) 查找。
// 如果未找到或过期,应返回 ErrTokenNotFound。
RefreshTokenGet(ctx context.Context, tokenID Hash256) (*RefreshTokenSession, error)
// RefreshTokenRotate 令牌轮换:删除旧的,保存新的。
// 强烈建议在事务中执行:如果保存新令牌失败,旧令牌也不应被删除(或者整个操作回滚)。
RefreshTokenRotate(ctx context.Context, oldTokenID Hash256, newSession *RefreshTokenSession, gracePeriod time.Duration) error
// RefreshTokenRevoke 撤销指定的刷新令牌。
RefreshTokenRevoke(ctx context.Context, tokenID Hash256) error
// RefreshTokenRevokeUser 撤销指定用户的所有令牌 (例如用户登出或修改密码时)。
RefreshTokenRevokeUser(ctx context.Context, userID BinaryUUID) ([]Hash256, error)
// RefreshTokenListByUser 列出指定用户的所有活跃令牌。
RefreshTokenListByUser(ctx context.Context, userID BinaryUUID) ([]*RefreshTokenSession, error)
}
TokenStorage 负责持久化刷新令牌 (Long-lived tokens)。
type TokenVerifier ¶
type TokenVerifier interface {
VerifyAccessToken(ctx context.Context, tokenStr string) (*AccessTokenClaims, error)
// ParseAccessToken 解析并验证 Token 签名和 Issuer,但不检查撤销状态。
// 用于撤销操作或需要自行处理撤销检查的场景。
ParseAccessToken(ctx context.Context, tokenStr string) (*AccessTokenClaims, error)
}
TokenVerifier 定义了 UserInfoHandler 所需的令牌验证能力。 由 Server 层实现,通常包括验签、验证 Issuer、验证过期时间、验证撤销状态。 注意:该接口不应在内部强制验证 Audience,因为 UserInfo 的 Audience 可能是动态的 ClientID。
type UserAuthenticator ¶
type UserAuthenticator interface {
// AuthenticateByPassword 根据用户名和密码进行认证。
// 成功时返回用户 ID,失败时应返回 ErrUserNotFound。
// 注意:此方法应实现速率限制和防暴力破解机制。
AuthenticateByPassword(ctx context.Context, username, password string) (BinaryUUID, string, error)
}
UserAuthenticator 定义用户认证接口。 此接口仅用于特殊场景(如负载测试的 Password Grant 流程),不应在生产环境的标准 OIDC 流程中使用。
type UserInfo ¶
type UserInfo struct {
Subject string `json:"sub"`
Name *string `json:"name,omitempty"`
GivenName *string `json:"given_name,omitempty"`
FamilyName *string `json:"family_name,omitempty"`
Nickname *string `json:"nickname,omitempty"`
PreferredUsername *string `json:"preferred_username,omitempty"`
Profile *string `json:"profile,omitempty"`
Picture *string `json:"picture,omitempty"`
Website *string `json:"website,omitempty"`
Email *string `json:"email,omitempty"`
EmailVerified *bool `json:"email_verified,omitempty"`
Gender *string `json:"gender,omitempty"`
Birthdate *string `json:"birthdate,omitempty"`
Zoneinfo *string `json:"zoneinfo,omitempty"`
Locale *string `json:"locale,omitempty"`
PhoneNumber *string `json:"phone_number,omitempty"`
PhoneNumberVerified *bool `json:"phone_number_verified,omitempty"`
UpdatedAt int64 `json:"updated_at,omitempty"`
// Metadata 存储扩展字段 (Custom Claims)。
// json:"-" 表示标准库忽略该字段,我们将在 MarshalJSON 中手动将其合并到顶层。
Metadata map[string]interface{} `json:"-"`
}
UserInfo 表示 OIDC UserInfo 端点的标准响应结构。 参见: OIDC Core 1.0, Section 5.1.
func GetUserInfo ¶
func GetUserInfo(ctx context.Context, storage UserInfoGetter, verifier TokenVerifier, claims *AccessTokenClaims) (*UserInfo, error)
GetUserInfo 根据 claims 获取用户信息
func (*UserInfo) MarshalJSON ¶ added in v0.3.0
MarshalJSON 自定义序列化逻辑
func (*UserInfo) UnmarshalJSON ¶ added in v0.3.0
UnmarshalJSON 自定义反序列化逻辑
type UserInfoGetter ¶
type UserInfoGetter interface {
// 测试中需要添加可查询的用户信息
UserCreateInfo(ctx context.Context, userInfo *UserInfo) error
// UserGetInfoByID 根据 UserID 和请求的 Scopes 返回用户信息。
// scope 参数允许实现层根据权限过滤返回字段 (例如:没有 'email' scope 就不查邮箱)。
UserGetInfoByID(ctx context.Context, userID BinaryUUID, scopes []string) (*UserInfo, error)
}
UserInfoGetter 用于从业务系统获取用户信息,以填充 ID Token 或响应 UserInfo 端点。
Source Files
¶
- amr.go
- authorize.go
- claims.go
- device_flow.go
- discovery.go
- dpop.go
- dpop_middleware.go
- dpop_time.go
- errors.go
- exchange.go
- gc_worker.go
- index.go
- interfaces.go
- introspection.go
- issuer.go
- jwks.go
- key.go
- key_manager.go
- key_provider.go
- key_rotation.go
- metrics.go
- par.go
- password_stub.go
- pkce.go
- registration.go
- revocation.go
- secret.go
- server.go
- server_lifecycle.go
- session.go
- storage.go
- types.go
- userinfo.go
- utils.go
- verifier.go