mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-02 17:30:23 +08:00
feat: 添加 OAuth 认证支持及相关改进
- 新增 OAuth 模块,支持 LinuxDo/GitHub/Google 等第三方登录 - 用户邮箱改为可选字段,支持无邮箱注册 - 新增模块配置验证状态 (config_validated/config_error) - 系统设置界面改为分块独立保存 - 用户设置新增 OAuth 绑定管理和首次密码设置 - 登录界面支持 OAuth 按钮展示 - 邮箱验证设置移至邮件设置页面
This commit is contained in:
@@ -65,14 +65,14 @@ export interface VerificationStatusResponse {
|
||||
}
|
||||
|
||||
export interface RegisterRequest {
|
||||
email: string
|
||||
email?: string
|
||||
username: string
|
||||
password: string
|
||||
}
|
||||
|
||||
export interface RegisterResponse {
|
||||
user_id: string
|
||||
email: string
|
||||
email?: string
|
||||
username: string
|
||||
message: string
|
||||
}
|
||||
@@ -80,6 +80,7 @@ export interface RegisterResponse {
|
||||
export interface RegistrationSettingsResponse {
|
||||
enable_registration: boolean
|
||||
require_email_verification: boolean
|
||||
email_configured: boolean
|
||||
}
|
||||
|
||||
export interface AuthSettingsResponse {
|
||||
|
||||
@@ -3,7 +3,7 @@ import type { ActivityHeatmap } from '@/types/activity'
|
||||
|
||||
export interface Profile {
|
||||
id: string // UUID
|
||||
email: string
|
||||
email?: string | null
|
||||
username: string
|
||||
role: string
|
||||
is_active: boolean
|
||||
@@ -13,7 +13,8 @@ export interface Profile {
|
||||
created_at: string
|
||||
updated_at?: string
|
||||
last_login_at?: string
|
||||
auth_source?: 'local' | 'ldap'
|
||||
auth_source?: 'local' | 'ldap' | 'oauth'
|
||||
has_password?: boolean
|
||||
preferences?: UserPreferences
|
||||
}
|
||||
|
||||
@@ -132,7 +133,7 @@ export interface ApiKey {
|
||||
// 不再需要 ProviderBinding 接口
|
||||
|
||||
export interface ChangePasswordRequest {
|
||||
old_password: string
|
||||
old_password?: string // 可选:首次设置密码时不需要
|
||||
new_password: string
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@ export interface ModuleStatus {
|
||||
available: boolean
|
||||
enabled: boolean
|
||||
active: boolean
|
||||
config_validated: boolean
|
||||
config_error: string | null
|
||||
display_name: string
|
||||
description: string
|
||||
category: 'auth' | 'monitoring' | 'security' | 'integration'
|
||||
|
||||
136
frontend/src/api/oauth.ts
Normal file
136
frontend/src/api/oauth.ts
Normal file
@@ -0,0 +1,136 @@
|
||||
import apiClient from './client'
|
||||
|
||||
export interface OAuthProviderInfo {
|
||||
provider_type: string
|
||||
display_name: string
|
||||
}
|
||||
|
||||
export interface OAuthProvidersResponse {
|
||||
providers: OAuthProviderInfo[]
|
||||
}
|
||||
|
||||
export interface OAuthLinkInfo {
|
||||
provider_type: string
|
||||
display_name: string
|
||||
provider_username?: string | null
|
||||
provider_email?: string | null
|
||||
linked_at?: string | null
|
||||
last_login_at?: string | null
|
||||
provider_enabled?: boolean
|
||||
}
|
||||
|
||||
export interface OAuthLinksResponse {
|
||||
links: OAuthLinkInfo[]
|
||||
}
|
||||
|
||||
// Admin
|
||||
export interface SupportedOAuthType {
|
||||
provider_type: string
|
||||
display_name: string
|
||||
default_authorization_url: string
|
||||
default_token_url: string
|
||||
default_userinfo_url: string
|
||||
default_scopes: string[]
|
||||
}
|
||||
|
||||
export interface OAuthProviderAdminConfig {
|
||||
provider_type: string
|
||||
display_name: string
|
||||
client_id: string
|
||||
has_secret: boolean
|
||||
authorization_url_override?: string | null
|
||||
token_url_override?: string | null
|
||||
userinfo_url_override?: string | null
|
||||
scopes?: string[] | null
|
||||
redirect_uri: string
|
||||
frontend_callback_url: string
|
||||
attribute_mapping?: Record<string, any> | null
|
||||
extra_config?: Record<string, any> | null
|
||||
is_enabled: boolean
|
||||
}
|
||||
|
||||
export interface OAuthProviderUpsertRequest {
|
||||
display_name: string
|
||||
client_id: string
|
||||
client_secret?: string
|
||||
authorization_url_override?: string | null
|
||||
token_url_override?: string | null
|
||||
userinfo_url_override?: string | null
|
||||
scopes?: string[] | null
|
||||
redirect_uri: string
|
||||
frontend_callback_url: string
|
||||
attribute_mapping?: Record<string, any> | null
|
||||
extra_config?: Record<string, any> | null
|
||||
is_enabled: boolean
|
||||
force?: boolean
|
||||
}
|
||||
|
||||
export interface OAuthProviderTestResponse {
|
||||
authorization_url_reachable: boolean
|
||||
token_url_reachable: boolean
|
||||
secret_status: 'likely_valid' | 'invalid' | 'unknown' | 'not_provided' | string
|
||||
details?: string
|
||||
}
|
||||
|
||||
export interface OAuthProviderTestRequest {
|
||||
client_id: string
|
||||
client_secret?: string
|
||||
authorization_url_override?: string | null
|
||||
token_url_override?: string | null
|
||||
redirect_uri: string
|
||||
}
|
||||
|
||||
export const oauthApi = {
|
||||
async getProviders(): Promise<OAuthProviderInfo[]> {
|
||||
const response = await apiClient.get<OAuthProvidersResponse>('/api/oauth/providers')
|
||||
return response.data.providers || []
|
||||
},
|
||||
|
||||
async getBindableProviders(): Promise<OAuthProviderInfo[]> {
|
||||
const response = await apiClient.get<OAuthProvidersResponse>('/api/user/oauth/bindable-providers')
|
||||
return response.data.providers || []
|
||||
},
|
||||
|
||||
async getMyLinks(): Promise<OAuthLinkInfo[]> {
|
||||
const response = await apiClient.get<OAuthLinksResponse>('/api/user/oauth/links')
|
||||
return response.data.links || []
|
||||
},
|
||||
|
||||
async unbind(providerType: string): Promise<{ message: string }> {
|
||||
const response = await apiClient.delete<{ message: string }>(`/api/user/oauth/${providerType}`)
|
||||
return response.data
|
||||
},
|
||||
|
||||
admin: {
|
||||
async getSupportedTypes(): Promise<SupportedOAuthType[]> {
|
||||
const response = await apiClient.get<SupportedOAuthType[]>('/api/admin/oauth/supported-types')
|
||||
return response.data || []
|
||||
},
|
||||
|
||||
async listProviderConfigs(): Promise<OAuthProviderAdminConfig[]> {
|
||||
const response = await apiClient.get<OAuthProviderAdminConfig[]>('/api/admin/oauth/providers')
|
||||
return response.data || []
|
||||
},
|
||||
|
||||
async getProviderConfig(providerType: string): Promise<OAuthProviderAdminConfig> {
|
||||
const response = await apiClient.get<OAuthProviderAdminConfig>(`/api/admin/oauth/providers/${providerType}`)
|
||||
return response.data
|
||||
},
|
||||
|
||||
async upsertProviderConfig(providerType: string, payload: OAuthProviderUpsertRequest): Promise<OAuthProviderAdminConfig> {
|
||||
const response = await apiClient.put<OAuthProviderAdminConfig>(`/api/admin/oauth/providers/${providerType}`, payload)
|
||||
return response.data
|
||||
},
|
||||
|
||||
async deleteProviderConfig(providerType: string): Promise<{ message: string }> {
|
||||
const response = await apiClient.delete<{ message: string }>(`/api/admin/oauth/providers/${providerType}`)
|
||||
return response.data
|
||||
},
|
||||
|
||||
async testProviderConfig(providerType: string, payload: OAuthProviderTestRequest): Promise<OAuthProviderTestResponse> {
|
||||
const response = await apiClient.post<OAuthProviderTestResponse>(`/api/admin/oauth/providers/${providerType}/test`, payload)
|
||||
return response.data
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user