|
|
|
|
|
//
|
|
|
|
|
|
// Copyright (C) 2024 veypi <i@veypi.com>
|
|
|
|
|
|
// 2025-07-24 15:27:31
|
|
|
|
|
|
// Distributed under terms of the MIT license.
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
|
|
package oauth
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
|
"time"
|
|
|
|
|
|
|
|
|
|
|
|
"github.com/veypi/OneAuth/models"
|
|
|
|
|
|
"gorm.io/gorm"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// User 用户表
|
|
|
|
|
|
type User struct {
|
|
|
|
|
|
models.BaseModel
|
|
|
|
|
|
Username string `json:"username" gorm:"uniqueIndex;not null;size:50;comment:用户名""`
|
|
|
|
|
|
Email string `json:"email" gorm:"uniqueIndex;size:100;comment:邮箱地址"`
|
|
|
|
|
|
Phone string `json:"phone" gorm:"uniqueIndex;size:20;comment:手机号码"`
|
|
|
|
|
|
PasswordHash string `json:"-" gorm:"not null;size:255;comment:密码哈希"`
|
|
|
|
|
|
Nickname string `json:"nickname" gorm:"size:50;comment:昵称"`
|
|
|
|
|
|
Avatar string `json:"avatar" gorm:"size:255;comment:头像URL"`
|
|
|
|
|
|
IsActive bool `json:"is_active" gorm:"default:true;comment:是否激活"`
|
|
|
|
|
|
IsSuperuser bool `json:"is_superuser" gorm:"default:false;comment:是否为超级用户"`
|
|
|
|
|
|
LastLoginAt *time.Time `json:"last_login_at" gorm:"comment:最后登录时间"`
|
|
|
|
|
|
EmailVerified bool `json:"email_verified" gorm:"default:false;comment:邮箱是否已验证"`
|
|
|
|
|
|
PhoneVerified bool `json:"phone_verified" gorm:"default:false;comment:手机是否已验证"`
|
|
|
|
|
|
TwoFactorAuth bool `json:"two_factor_auth" gorm:"default:false;comment:是否启用双因素认证"`
|
|
|
|
|
|
Locale string `json:"locale" gorm:"size:10;default:zh-CN;comment:语言偏好"`
|
|
|
|
|
|
Timezone string `json:"timezone" gorm:"size:50;default:Asia/Shanghai;comment:时区"`
|
|
|
|
|
|
Bio string `json:"bio" gorm:"type:text;comment:个人简介"`
|
|
|
|
|
|
|
|
|
|
|
|
// 关联关系
|
|
|
|
|
|
Roles []Role `json:"roles" gorm:"many2many:user_roles;"`
|
|
|
|
|
|
UserRoles []UserRole `json:"-"`
|
|
|
|
|
|
OAuthAccounts []OAuthAccount `json:"oauth_accounts"`
|
|
|
|
|
|
Tokens []UserToken `json:"-"`
|
|
|
|
|
|
MetaData []byte `json:"meta_data" gorm:"type:jsonb;comment:用户元数据"` // 存储用户自定义的元数据
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Role 角色表
|
|
|
|
|
|
type Role struct {
|
|
|
|
|
|
models.BaseModel
|
|
|
|
|
|
Name string `json:"name" gorm:"uniqueIndex;not null;size:50;comment:角色名称" validate:"required"`
|
|
|
|
|
|
DisplayName string `json:"display_name" gorm:"size:100;comment:显示名称"`
|
|
|
|
|
|
Description string `json:"description" gorm:"type:text;comment:角色描述"`
|
|
|
|
|
|
IsSystem bool `json:"is_system" gorm:"default:false;comment:是否为系统角色"`
|
|
|
|
|
|
IsActive bool `json:"is_active" gorm:"default:true;comment:是否激活"`
|
|
|
|
|
|
|
|
|
|
|
|
// 关联关系
|
|
|
|
|
|
Users []User `json:"-" gorm:"many2many:user_roles;"`
|
|
|
|
|
|
UserRoles []UserRole `json:"-"`
|
|
|
|
|
|
Permissions []Permission `json:"permissions" gorm:"many2many:role_permissions;"`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Permission 权限表
|
|
|
|
|
|
type Permission struct {
|
|
|
|
|
|
models.BaseModel
|
|
|
|
|
|
Name string `json:"name" gorm:"uniqueIndex;not null;size:100;comment:权限名称" validate:"required"`
|
|
|
|
|
|
DisplayName string `json:"display_name" gorm:"size:100;comment:显示名称"`
|
|
|
|
|
|
Description string `json:"description" gorm:"type:text;comment:权限描述"`
|
|
|
|
|
|
Resource string `json:"resource" gorm:"not null;size:50;comment:资源名称" validate:"required"`
|
|
|
|
|
|
Action string `json:"action" gorm:"not null;size:50;comment:操作类型" validate:"required"`
|
|
|
|
|
|
IsSystem bool `json:"is_system" gorm:"default:false;comment:是否为系统权限"`
|
|
|
|
|
|
|
|
|
|
|
|
// 关联关系
|
|
|
|
|
|
Roles []Role `json:"-" gorm:"many2many:role_permissions;"`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// UserRole 用户角色关联表
|
|
|
|
|
|
type UserRole struct {
|
|
|
|
|
|
UserID string `json:"user_id" gorm:"primaryKey;type:varchar(32);comment:用户ID"`
|
|
|
|
|
|
RoleID string `json:"role_id" gorm:"primaryKey;type:varchar(32);comment:角色ID"`
|
|
|
|
|
|
GrantedBy string `json:"granted_by" gorm:"type:varchar(32);comment:授权人ID"`
|
|
|
|
|
|
GrantedAt time.Time `json:"granted_at" gorm:"autoCreateTime;comment:授权时间"`
|
|
|
|
|
|
ExpiresAt *time.Time `json:"expires_at" gorm:"comment:过期时间"`
|
|
|
|
|
|
|
|
|
|
|
|
// 关联关系
|
|
|
|
|
|
User *User `json:"user" gorm:"foreignKey:UserID"`
|
|
|
|
|
|
Role *Role `json:"role" gorm:"foreignKey:RoleID"`
|
|
|
|
|
|
GrantedByUser *User `json:"granted_by_user" gorm:"foreignKey:GrantedBy"`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// RolePermission 角色权限关联表
|
|
|
|
|
|
type RolePermission struct {
|
|
|
|
|
|
RoleID string `json:"role_id" gorm:"primaryKey;type:varchar(32);comment:角色ID"`
|
|
|
|
|
|
PermissionID string `json:"permission_id" gorm:"primaryKey;type:varchar(32);comment:权限ID"`
|
|
|
|
|
|
GrantedBy string `json:"granted_by" gorm:"type:varchar(32);comment:授权人ID"`
|
|
|
|
|
|
GrantedAt time.Time `json:"granted_at" gorm:"autoCreateTime;comment:授权时间"`
|
|
|
|
|
|
|
|
|
|
|
|
// 关联关系
|
|
|
|
|
|
Role *Role `json:"role" gorm:"foreignKey:RoleID"`
|
|
|
|
|
|
Permission *Permission `json:"permission" gorm:"foreignKey:PermissionID"`
|
|
|
|
|
|
GrantedByUser *User `json:"granted_by_user" gorm:"foreignKey:GrantedBy"`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// UserLoginLog 用户登录日志表
|
|
|
|
|
|
type UserLoginLog struct {
|
|
|
|
|
|
models.BaseModel
|
|
|
|
|
|
UserID string `json:"user_id" gorm:"not null;type:varchar(32);index;comment:用户ID"`
|
|
|
|
|
|
IPAddress string `json:"ip_address" gorm:"size:45;comment:IP地址"`
|
|
|
|
|
|
UserAgent string `json:"user_agent" gorm:"type:text;comment:用户代理"`
|
|
|
|
|
|
LoginAt time.Time `json:"login_at" gorm:"autoCreateTime;comment:登录时间"`
|
|
|
|
|
|
Success bool `json:"success" gorm:"default:true;comment:是否成功"`
|
|
|
|
|
|
FailReason string `json:"fail_reason" gorm:"size:255;comment:失败原因"`
|
|
|
|
|
|
Location string `json:"location" gorm:"size:100;comment:地理位置"` // 地理位置
|
|
|
|
|
|
|
|
|
|
|
|
// 关联关系
|
|
|
|
|
|
User User `json:"user" gorm:"foreignKey:UserID"`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// GORM Hooks
|
|
|
|
|
|
func (u *User) BeforeCreate(tx *gorm.DB) error {
|
|
|
|
|
|
if err := u.BaseModel.BeforeCreate(tx); err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
if u.Locale == "" {
|
|
|
|
|
|
u.Locale = "zh-CN"
|
|
|
|
|
|
}
|
|
|
|
|
|
if u.Timezone == "" {
|
|
|
|
|
|
u.Timezone = "Asia/Shanghai"
|
|
|
|
|
|
}
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 用户方法
|
|
|
|
|
|
func (u *User) HasRole(roleName string) bool {
|
|
|
|
|
|
for _, role := range u.Roles {
|
|
|
|
|
|
if role.Name == roleName {
|
|
|
|
|
|
return true
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return false
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (u *User) HasPermission(resource, action string) bool {
|
|
|
|
|
|
for _, role := range u.Roles {
|
|
|
|
|
|
for _, permission := range role.Permissions {
|
|
|
|
|
|
if permission.Resource == resource && permission.Action == action {
|
|
|
|
|
|
return true
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return false
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (u *User) GetPermissions() []Permission {
|
|
|
|
|
|
var permissions []Permission
|
|
|
|
|
|
permissionMap := make(map[string]bool)
|
|
|
|
|
|
|
|
|
|
|
|
for _, role := range u.Roles {
|
|
|
|
|
|
for _, permission := range role.Permissions {
|
|
|
|
|
|
if !permissionMap[permission.ID] {
|
|
|
|
|
|
permissions = append(permissions, permission)
|
|
|
|
|
|
permissionMap[permission.ID] = true
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return permissions
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 角色方法
|
|
|
|
|
|
func (r *Role) HasPermission(resource, action string) bool {
|
|
|
|
|
|
for _, permission := range r.Permissions {
|
|
|
|
|
|
if permission.Resource == resource && permission.Action == action {
|
|
|
|
|
|
return true
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return false
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ===== OAuth 服务器相关模型 =====
|
|
|
|
|
|
|
|
|
|
|
|
// OAuthClient OAuth客户端表
|
|
|
|
|
|
type OAuthClient struct {
|
|
|
|
|
|
models.BaseModel
|
|
|
|
|
|
ClientID string `json:"client_id" gorm:"uniqueIndex;not null;size:255;comment:客户端ID"`
|
|
|
|
|
|
ClientSecret string `json:"-" gorm:"not null;size:255;comment:客户端密钥"`
|
|
|
|
|
|
ClientName string `json:"client_name" gorm:"not null;size:255;comment:客户端名称"`
|
|
|
|
|
|
ClientURI string `json:"client_uri" gorm:"size:500;comment:客户端主页"`
|
|
|
|
|
|
LogoURI string `json:"logo_uri" gorm:"size:500;comment:客户端Logo"`
|
|
|
|
|
|
TermsOfServiceURI string `json:"tos_uri" gorm:"size:500;comment:服务条款URL"`
|
|
|
|
|
|
PolicyURI string `json:"policy_uri" gorm:"size:500;comment:隐私政策URL"`
|
|
|
|
|
|
RedirectURIs string `json:"redirect_uris" gorm:"type:text;comment:重定向URI列表,JSON格式"`
|
|
|
|
|
|
ResponseTypes string `json:"response_types" gorm:"size:255;default:'code';comment:响应类型"`
|
|
|
|
|
|
GrantTypes string `json:"grant_types" gorm:"size:255;default:'authorization_code,refresh_token';comment:授权类型"`
|
|
|
|
|
|
Scope string `json:"scope" gorm:"type:text;comment:授权范围"`
|
|
|
|
|
|
Contacts string `json:"contacts" gorm:"type:text;comment:联系人邮箱,JSON格式"`
|
|
|
|
|
|
IsPublic bool `json:"is_public" gorm:"default:false;comment:是否为公开客户端"`
|
|
|
|
|
|
IsActive bool `json:"is_active" gorm:"default:true;comment:是否激活"`
|
|
|
|
|
|
OwnerID string `json:"owner_id" gorm:"type:varchar(32);comment:客户端拥有者ID"`
|
|
|
|
|
|
|
|
|
|
|
|
// 关联关系
|
|
|
|
|
|
Owner *User `json:"owner" gorm:"foreignKey:OwnerID"`
|
|
|
|
|
|
AuthorizationCodes []OAuthAuthorizationCode `json:"-"`
|
|
|
|
|
|
AccessTokens []OAuthAccessToken `json:"-"`
|
|
|
|
|
|
RefreshTokens []OAuthRefreshToken `json:"-"`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// OAuthAuthorizationCode 授权码表
|
|
|
|
|
|
type OAuthAuthorizationCode struct {
|
|
|
|
|
|
models.BaseModel
|
|
|
|
|
|
Code string `json:"code" gorm:"uniqueIndex;not null;size:255;comment:授权码"`
|
|
|
|
|
|
ClientID string `json:"client_id" gorm:"not null;type:varchar(32);index;comment:客户端ID"`
|
|
|
|
|
|
UserID string `json:"user_id" gorm:"not null;type:varchar(32);index;comment:用户ID"`
|
|
|
|
|
|
RedirectURI string `json:"redirect_uri" gorm:"not null;size:500;comment:重定向URI"`
|
|
|
|
|
|
Scope string `json:"scope" gorm:"type:text;comment:授权范围"`
|
|
|
|
|
|
CodeChallenge string `json:"code_challenge" gorm:"size:255;comment:PKCE代码挑战"`
|
|
|
|
|
|
CodeChallengeMethod string `json:"code_challenge_method" gorm:"size:50;comment:PKCE挑战方法"`
|
|
|
|
|
|
ExpiresAt time.Time `json:"expires_at" gorm:"not null;comment:过期时间"`
|
|
|
|
|
|
Used bool `json:"used" gorm:"default:false;comment:是否已使用"`
|
|
|
|
|
|
|
|
|
|
|
|
// 关联关系
|
|
|
|
|
|
Client *OAuthClient `json:"client" gorm:"foreignKey:ClientID"`
|
|
|
|
|
|
User *User `json:"user" gorm:"foreignKey:UserID"`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// OAuthAccessToken 访问令牌表
|
|
|
|
|
|
type OAuthAccessToken struct {
|
|
|
|
|
|
models.BaseModel
|
|
|
|
|
|
Token string `json:"token" gorm:"uniqueIndex;not null;size:500;comment:访问令牌"`
|
|
|
|
|
|
ClientID string `json:"client_id" gorm:"not null;type:varchar(32);index;comment:客户端ID"`
|
|
|
|
|
|
UserID string `json:"user_id" gorm:"not null;type:varchar(32);index;comment:用户ID"`
|
|
|
|
|
|
Scope string `json:"scope" gorm:"type:text;comment:授权范围"`
|
|
|
|
|
|
ExpiresAt time.Time `json:"expires_at" gorm:"not null;comment:过期时间"`
|
|
|
|
|
|
Revoked bool `json:"revoked" gorm:"default:false;comment:是否已撤销"`
|
|
|
|
|
|
|
|
|
|
|
|
// 关联关系
|
|
|
|
|
|
Client *OAuthClient `json:"client" gorm:"foreignKey:ClientID"`
|
|
|
|
|
|
User *User `json:"user" gorm:"foreignKey:UserID"`
|
|
|
|
|
|
RefreshToken *OAuthRefreshToken `json:"refresh_token"`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// OAuthRefreshToken 刷新令牌表
|
|
|
|
|
|
type OAuthRefreshToken struct {
|
|
|
|
|
|
models.BaseModel
|
|
|
|
|
|
Token string `json:"token" gorm:"uniqueIndex;not null;size:500;comment:刷新令牌"`
|
|
|
|
|
|
AccessTokenID string `json:"access_token_id" gorm:"type:varchar(32);uniqueIndex;comment:访问令牌ID"`
|
|
|
|
|
|
ClientID string `json:"client_id" gorm:"not null;type:varchar(32);index;comment:客户端ID"`
|
|
|
|
|
|
UserID string `json:"user_id" gorm:"not null;type:varchar(32);index;comment:用户ID"`
|
|
|
|
|
|
Scope string `json:"scope" gorm:"type:text;comment:授权范围"`
|
|
|
|
|
|
ExpiresAt time.Time `json:"expires_at" gorm:"not null;comment:过期时间"`
|
|
|
|
|
|
Revoked bool `json:"revoked" gorm:"default:false;comment:是否已撤销"`
|
|
|
|
|
|
|
|
|
|
|
|
// 关联关系
|
|
|
|
|
|
Client *OAuthClient `json:"client" gorm:"foreignKey:ClientID"`
|
|
|
|
|
|
User *User `json:"user" gorm:"foreignKey:UserID"`
|
|
|
|
|
|
AccessToken *OAuthAccessToken `json:"access_token" gorm:"foreignKey:AccessTokenID"`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// OAuthScope OAuth授权范围表
|
|
|
|
|
|
type OAuthScope struct {
|
|
|
|
|
|
models.BaseModel
|
|
|
|
|
|
Name string `json:"name" gorm:"uniqueIndex;not null;size:100;comment:范围名称"`
|
|
|
|
|
|
DisplayName string `json:"display_name" gorm:"size:100;comment:显示名称"`
|
|
|
|
|
|
Description string `json:"description" gorm:"type:text;comment:范围描述"`
|
|
|
|
|
|
IsDefault bool `json:"is_default" gorm:"default:false;comment:是否为默认范围"`
|
|
|
|
|
|
IsSystem bool `json:"is_system" gorm:"default:false;comment:是否为系统范围"`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// OAuthClientScope 客户端授权范围关联表
|
|
|
|
|
|
type OAuthClientScope struct {
|
|
|
|
|
|
ClientID string `json:"client_id" gorm:"primaryKey;type:varchar(32);comment:客户端ID"`
|
|
|
|
|
|
ScopeID string `json:"scope_id" gorm:"primaryKey;type:varchar(32);comment:范围ID"`
|
|
|
|
|
|
|
|
|
|
|
|
// 关联关系
|
|
|
|
|
|
Client *OAuthClient `json:"client" gorm:"foreignKey:ClientID"`
|
|
|
|
|
|
Scope *OAuthScope `json:"scope" gorm:"foreignKey:ScopeID"`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// OAuthProvider 第三方OAuth提供商表(用于OAuth客户端模式)
|
|
|
|
|
|
type OAuthProvider struct {
|
|
|
|
|
|
models.BaseModel
|
|
|
|
|
|
Name string `json:"name" gorm:"uniqueIndex;not null;size:100;comment:提供商名称"`
|
|
|
|
|
|
DisplayName string `json:"display_name" gorm:"size:100;comment:显示名称"`
|
|
|
|
|
|
ClientID string `json:"client_id" gorm:"not null;size:255;comment:客户端ID"`
|
|
|
|
|
|
ClientSecret string `json:"-" gorm:"not null;size:255;comment:客户端密钥"`
|
|
|
|
|
|
AuthURL string `json:"auth_url" gorm:"not null;size:500;comment:授权URL"`
|
|
|
|
|
|
TokenURL string `json:"token_url" gorm:"not null;size:500;comment:令牌URL"`
|
|
|
|
|
|
UserInfoURL string `json:"user_info_url" gorm:"size:500;comment:用户信息URL"`
|
|
|
|
|
|
Scope string `json:"scope" gorm:"type:text;comment:默认授权范围"`
|
|
|
|
|
|
IsActive bool `json:"is_active" gorm:"default:true;comment:是否激活"`
|
|
|
|
|
|
|
|
|
|
|
|
// 关联关系
|
|
|
|
|
|
OAuthAccounts []OAuthAccount `json:"oauth_accounts"`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// OAuthAccount 用户OAuth账户表(第三方登录)
|
|
|
|
|
|
type OAuthAccount struct {
|
|
|
|
|
|
models.BaseModel
|
|
|
|
|
|
UserID string `json:"user_id" gorm:"not null;type:varchar(32);index;comment:用户ID"`
|
|
|
|
|
|
ProviderID string `json:"provider_id" gorm:"not null;type:varchar(32);index;comment:提供商ID"`
|
|
|
|
|
|
ProviderUserID string `json:"provider_user_id" gorm:"not null;size:255;comment:提供商用户ID"`
|
|
|
|
|
|
Email string `json:"email" gorm:"size:255;comment:邮箱"`
|
|
|
|
|
|
Username string `json:"username" gorm:"size:255;comment:用户名"`
|
|
|
|
|
|
Nickname string `json:"nickname" gorm:"size:255;comment:昵称"`
|
|
|
|
|
|
Avatar string `json:"avatar" gorm:"size:500;comment:头像URL"`
|
|
|
|
|
|
AccessToken string `json:"-" gorm:"type:text;comment:访问令牌"`
|
|
|
|
|
|
RefreshToken string `json:"-" gorm:"type:text;comment:刷新令牌"`
|
|
|
|
|
|
ExpiresAt *time.Time `json:"expires_at" gorm:"comment:令牌过期时间"`
|
|
|
|
|
|
|
|
|
|
|
|
// 关联关系
|
|
|
|
|
|
User *User `json:"user" gorm:"foreignKey:UserID"`
|
|
|
|
|
|
Provider *OAuthProvider `json:"provider" gorm:"foreignKey:ProviderID"`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// UserToken 用户令牌表(API令牌等)
|
|
|
|
|
|
type UserToken struct {
|
|
|
|
|
|
models.BaseModel
|
|
|
|
|
|
UserID string `json:"user_id" gorm:"not null;type:varchar(32);index;comment:用户ID"`
|
|
|
|
|
|
TokenType string `json:"token_type" gorm:"not null;size:50;comment:令牌类型"` // api, session, etc.
|
|
|
|
|
|
Token string `json:"token" gorm:"uniqueIndex;not null;size:500;comment:令牌值"`
|
|
|
|
|
|
Name string `json:"name" gorm:"size:100;comment:令牌名称"`
|
|
|
|
|
|
Description string `json:"description" gorm:"type:text;comment:令牌描述"`
|
|
|
|
|
|
Scope string `json:"scope" gorm:"type:text;comment:授权范围"`
|
|
|
|
|
|
ExpiresAt *time.Time `json:"expires_at" gorm:"comment:过期时间"`
|
|
|
|
|
|
LastUsedAt *time.Time `json:"last_used_at" gorm:"comment:最后使用时间"`
|
|
|
|
|
|
IsActive bool `json:"is_active" gorm:"default:true;comment:是否激活"`
|
|
|
|
|
|
|
|
|
|
|
|
// 关联关系
|
|
|
|
|
|
User *User `json:"user" gorm:"foreignKey:UserID"`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// UserSession 用户会话表
|
|
|
|
|
|
type UserSession struct {
|
|
|
|
|
|
models.BaseModel
|
|
|
|
|
|
UserID string `json:"user_id" gorm:"not null;type:varchar(32);index;comment:用户ID"`
|
|
|
|
|
|
SessionID string `json:"session_id" gorm:"uniqueIndex;not null;size:255;comment:会话ID"`
|
|
|
|
|
|
IPAddress string `json:"ip_address" gorm:"size:45;comment:IP地址"`
|
|
|
|
|
|
UserAgent string `json:"user_agent" gorm:"type:text;comment:用户代理"`
|
|
|
|
|
|
ExpiresAt time.Time `json:"expires_at" gorm:"not null;comment:过期时间"`
|
|
|
|
|
|
IsActive bool `json:"is_active" gorm:"default:true;comment:是否激活"`
|
|
|
|
|
|
LastActivity time.Time `json:"last_activity" gorm:"comment:最后活动时间"`
|
|
|
|
|
|
|
|
|
|
|
|
// 关联关系
|
|
|
|
|
|
User *User `json:"user" gorm:"foreignKey:UserID"`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// OAuthUserConsent 用户授权同意表
|
|
|
|
|
|
type OAuthUserConsent struct {
|
|
|
|
|
|
models.BaseModel
|
|
|
|
|
|
UserID string `json:"user_id" gorm:"not null;type:varchar(32);index;comment:用户ID"`
|
|
|
|
|
|
ClientID string `json:"client_id" gorm:"not null;type:varchar(32);index;comment:客户端ID"`
|
|
|
|
|
|
Scope string `json:"scope" gorm:"type:text;comment:授权范围"`
|
|
|
|
|
|
ConsentAt time.Time `json:"consent_at" gorm:"autoCreateTime;comment:同意时间"`
|
|
|
|
|
|
ExpiresAt *time.Time `json:"expires_at" gorm:"comment:同意过期时间"`
|
|
|
|
|
|
|
|
|
|
|
|
// 关联关系
|
|
|
|
|
|
User *User `json:"user" gorm:"foreignKey:UserID"`
|
|
|
|
|
|
Client *OAuthClient `json:"client" gorm:"foreignKey:ClientID"`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ===== OAuth 模型方法 =====
|
|
|
|
|
|
|
|
|
|
|
|
// OAuthClient 方法
|
|
|
|
|
|
func (c *OAuthClient) IsRedirectURIValid(uri string) bool {
|
|
|
|
|
|
// 这里应该解析 RedirectURIs JSON 并验证
|
|
|
|
|
|
// 简化实现,实际使用时需要完善
|
|
|
|
|
|
return true
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (c *OAuthClient) HasScope(scope string) bool {
|
|
|
|
|
|
// 这里应该解析 Scope 并检查
|
|
|
|
|
|
// 简化实现,实际使用时需要完善
|
|
|
|
|
|
return true
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// OAuthAuthorizationCode 方法
|
|
|
|
|
|
func (code *OAuthAuthorizationCode) IsExpired() bool {
|
|
|
|
|
|
return time.Now().After(code.ExpiresAt)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// OAuthAccessToken 方法
|
|
|
|
|
|
func (token *OAuthAccessToken) IsExpired() bool {
|
|
|
|
|
|
return time.Now().After(token.ExpiresAt)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (token *OAuthAccessToken) IsValid() bool {
|
|
|
|
|
|
return !token.Revoked && !token.IsExpired()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// OAuthRefreshToken 方法
|
|
|
|
|
|
func (token *OAuthRefreshToken) IsExpired() bool {
|
|
|
|
|
|
return time.Now().After(token.ExpiresAt)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (token *OAuthRefreshToken) IsValid() bool {
|
|
|
|
|
|
return !token.Revoked && !token.IsExpired()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// UserSession 方法
|
|
|
|
|
|
func (s *UserSession) IsExpired() bool {
|
|
|
|
|
|
return time.Now().After(s.ExpiresAt)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (s *UserSession) IsValid() bool {
|
|
|
|
|
|
return s.IsActive && !s.IsExpired()
|
|
|
|
|
|
}
|