Files
BYW-VoiceHub/server/utils/oauth-strategies.ts
T
Henry_Du 604749d08a
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Successful in 2m13s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Successful in 10m0s
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Successful in 7s
chore(auth): 临时硬关闭微信聚合登录(aggregate=false)\n\n用户反馈:先暂时不做微信登录了。\n\n双重保险:\n1) 构建期开关:nuxt.config.ts runtimeConfig.public.oauth.aggregate 由\n 原来的 !!process.env.AGGREGATE_OAUTH_APP_ID 改为硬编码 false。\n 影响范围:\n - 登录页 OAuthButtons.vue 中的 v-if 分支不再渲染绿色微信按钮\n - app/pages/account/index.vue 中 hasOAuthProviders aggregate=false → 个人页\n 第三方绑定分区即使其他 provider 都没配也会显示其它 provider,\n 但微信卡片 OAuthBindingCard.vue 因 config.public.oauth.aggregate=false\n 被 v-if 直接拿掉不渲染\n - app/utils/oauth.ts getProviderDisplayName 中 aggregate→微信 映射还保留,\n 恢复时无需再改\n2) 运行期强制关:server/utils/oauth-strategies.ts loadAggregateSettings\n 返回值 aggregateOAuthEnabled 硬编码 false(即使 process.env.AGGREGATE_OAUTH_APP_ID\n 和 system_settings 表都配齐也不启用)。并加 _hardDisabledReason 字段给后续日志\n 留解释,避免以后排查为何 ENV/DB 都有值却 500 说未配置。\n\n后续恢复步骤(两处同时改回即可):\n A. nuxt.config.ts public.oauth.aggregate 改回\n aggregate: !!process.env.AGGREGATE_OAUTH_APP_ID\n B. server/utils/oauth-strategies.ts loadAggregateSettings 返回对象\n aggregateOAuthEnabled 改回原本逻辑:\n enabled && !!(appId && appKey && endpoint)\n 并删除 _hardDisabledReason 字段即可。\n\n注意:Gitea Repository Secrets 中的 6 条 AGGREGATE_OAUTH / OAUTH_* 没有删除,\n保留在仓库里,下次恢复不用重新输入一遍。
2026-09-13 09:29:05 +08:00

611 lines
23 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { createError } from 'h3'
import { createHmac, randomUUID } from 'node:crypto'
import { db } from '~/drizzle/db'
import { systemSettings } from '~/drizzle/schema'
import { asc } from 'drizzle-orm'
import {
isSafeAggregateOAuthUrl,
getAggregateOAuthLoginTypesOrDefault
} from './oauth-providers'
export interface OAuthUserInfo {
id: string
username: string
email?: string
name?: string
avatar?: string
}
export interface OAuthStrategy {
/**
* 获取授权跳转 URL
*/
getAuthorizeUrl(redirectUri: string, state: string): string
/**
* 使用 code 换取 access_token
*/
exchangeToken(code: string, redirectUri: string): Promise<string>
/**
* 获取用户信息
*/
getUserInfo(accessToken: string): Promise<OAuthUserInfo>
}
// GitHub 策略实现
const githubStrategy: OAuthStrategy = {
getAuthorizeUrl(redirectUri: string, state: string) {
const clientId = process.env.GITHUB_CLIENT_ID
if (!clientId)
throw createError({ statusCode: 500, message: 'GitHub Client ID not configured' })
return `https://github.com/login/oauth/authorize?client_id=${clientId}&redirect_uri=${encodeURIComponent(redirectUri)}&scope=user:email&state=${encodeURIComponent(state)}`
},
async exchangeToken(code: string, redirectUri: string) {
const clientId = process.env.GITHUB_CLIENT_ID
const clientSecret = process.env.GITHUB_CLIENT_SECRET
if (!clientId || !clientSecret) {
throw createError({ statusCode: 500, message: 'GitHub config missing' })
}
try {
const tokenResponse = await $fetch<any>('https://github.com/login/oauth/access_token', {
method: 'POST',
body: {
client_id: clientId,
client_secret: clientSecret,
code,
redirect_uri: redirectUri
},
headers: { Accept: 'application/json' }
})
if (tokenResponse.error) {
console.error('GitHub Token Error:', tokenResponse.error)
throw new Error('授权失败,请重试')
}
if (!tokenResponse.access_token) {
console.error('GitHub Token Response missing access_token')
throw new Error('未能获取访问令牌')
}
return tokenResponse.access_token
} catch (e: any) {
console.error('GitHub token exchange failed', e.message || e)
const errorMessage = e.data?.error_description || e.message || '令牌请求失败'
throw new Error(errorMessage)
}
},
async getUserInfo(accessToken: string) {
try {
const userInfo = await $fetch<any>('https://api.github.com/user', {
headers: { Authorization: `Bearer ${accessToken}` }
})
return {
id: String(userInfo.id),
username: userInfo.login,
name: userInfo.name,
email: userInfo.email,
avatar: userInfo.avatar_url
}
} catch (e: any) {
console.error('GitHub user info failed', e)
throw new Error('获取用户信息失败')
}
}
}
// Casdoor 策略实现
const casdoorStrategy: OAuthStrategy = {
getAuthorizeUrl(redirectUri: string, state: string) {
const clientId = process.env.CASDOOR_CLIENT_ID
const endpoint = process.env.CASDOOR_ENDPOINT
if (!clientId || !endpoint)
throw createError({ statusCode: 500, message: 'Casdoor config missing' })
return `${endpoint}/login/oauth/authorize?client_id=${clientId}&response_type=code&redirect_uri=${encodeURIComponent(redirectUri)}&scope=read&state=${encodeURIComponent(state)}`
},
async exchangeToken(code: string, redirectUri: string) {
const clientId = process.env.CASDOOR_CLIENT_ID
const clientSecret = process.env.CASDOOR_CLIENT_SECRET
const endpoint = process.env.CASDOOR_ENDPOINT
if (!clientId || !clientSecret || !endpoint) {
throw createError({ statusCode: 500, message: 'Casdoor config missing' })
}
try {
const tokenResponse = await $fetch<any>(`${endpoint}/login/oauth/access_token`, {
method: 'POST',
body: {
client_id: clientId,
client_secret: clientSecret,
code,
grant_type: 'authorization_code',
redirect_uri: redirectUri
},
headers: { Accept: 'application/json' }
})
if (tokenResponse.error) {
console.error('Casdoor Token Error:', tokenResponse.error, tokenResponse.error_description)
throw new Error(tokenResponse.error_description || '授权失败,请重试')
}
if (!tokenResponse.access_token) {
console.error('Casdoor Token Response missing access_token')
throw new Error('未能获取访问令牌,请检查 Casdoor 配置')
}
return tokenResponse.access_token
} catch (e: any) {
console.error('Casdoor token exchange failed', e.message || e)
const errorMessage = e.data?.error_description || e.message || '令牌请求失败'
throw new Error(errorMessage)
}
},
async getUserInfo(accessToken: string) {
const endpoint = process.env.CASDOOR_ENDPOINT
if (!endpoint) throw createError({ statusCode: 500, message: 'Casdoor config missing' })
let userInfo: any = {}
try {
// Casdoor 用户信息端点通常是 /api/get-account 或 /api/userinfo
// 标准 OIDC 使用 /userinfo
try {
userInfo = await $fetch(`${endpoint}/api/userinfo`, {
headers: { Authorization: `Bearer ${accessToken}` }
})
} catch (e) {
// 尝试备用端点
userInfo = await $fetch(`${endpoint}/api/get-account`, {
headers: { Authorization: `Bearer ${accessToken}` }
})
}
return {
id: String(userInfo.id || userInfo.sub),
username: userInfo.name || userInfo.preferred_username || userInfo.username,
name: userInfo.displayName || userInfo.name,
email: userInfo.email,
avatar: userInfo.avatar
}
} catch (e: any) {
console.error('Casdoor user info failed', e)
throw new Error('获取用户信息失败')
}
}
}
// Google 策略实现
const googleStrategy: OAuthStrategy = {
getAuthorizeUrl(redirectUri: string, state: string) {
const clientId = process.env.GOOGLE_CLIENT_ID
if (!clientId)
throw createError({ statusCode: 500, message: 'Google Client ID not configured' })
return `https://accounts.google.com/o/oauth2/v2/auth?client_id=${clientId}&redirect_uri=${encodeURIComponent(redirectUri)}&response_type=code&scope=openid%20email%20profile&state=${encodeURIComponent(state)}`
},
async exchangeToken(code: string, redirectUri: string) {
const clientId = process.env.GOOGLE_CLIENT_ID
const clientSecret = process.env.GOOGLE_CLIENT_SECRET
if (!clientId || !clientSecret) {
throw createError({ statusCode: 500, message: 'Google config missing' })
}
try {
const tokenResponse = await $fetch<any>('https://oauth2.googleapis.com/token', {
method: 'POST',
body: {
client_id: clientId,
client_secret: clientSecret,
code,
grant_type: 'authorization_code',
redirect_uri: redirectUri
},
headers: { Accept: 'application/json' }
})
if (tokenResponse.error) {
console.error('Google Token Error:', tokenResponse.error)
throw new Error('授权失败,请重试')
}
if (!tokenResponse.access_token) {
console.error('Google Token Response missing access_token')
throw new Error('未能获取访问令牌')
}
return tokenResponse.access_token
} catch (e: any) {
console.error('Google token exchange failed', e.message || e)
const errorMessage = e.data?.error_description || e.message || '令牌请求失败'
throw new Error(errorMessage)
}
},
async getUserInfo(accessToken: string) {
try {
const userInfo = await $fetch<any>('https://www.googleapis.com/oauth2/v3/userinfo', {
headers: { Authorization: `Bearer ${accessToken}` }
})
return {
id: userInfo.sub,
username: userInfo.email, // Google doesn't have a username, use email
name: userInfo.name,
email: userInfo.email,
avatar: userInfo.picture
}
} catch (e: any) {
console.error('Google user info failed', e)
throw new Error('获取用户信息失败')
}
}
}
// 策略注册表
const strategies: Record<string, OAuthStrategy> = {
github: githubStrategy,
casdoor: casdoorStrategy,
google: googleStrategy
}
async function loadAggregateSettings() {
const envAppId = process.env.AGGREGATE_OAUTH_APP_ID
const envAppKey = process.env.AGGREGATE_OAUTH_APP_KEY
const envLoginType = process.env.AGGREGATE_OAUTH_LOGIN_TYPE
const envEndpoint = process.env.AGGREGATE_OAUTH_ENDPOINT
const hasEnvConfig = !!(envAppId && envAppKey && envEndpoint)
let base: any = null
try {
const row = await db
.select({
aggregateOAuthEnabled: systemSettings.aggregateOAuthEnabled,
aggregateOAuthAppId: systemSettings.aggregateOAuthAppId,
aggregateOAuthAppKey: systemSettings.aggregateOAuthAppKey,
aggregateOAuthLoginType: systemSettings.aggregateOAuthLoginType,
aggregateOAuthEndpoint: systemSettings.aggregateOAuthEndpoint
})
.from(systemSettings)
.orderBy(asc(systemSettings.id))
.limit(1)
base = row[0] ?? null
} catch (e: any) {
console.warn(
'[AggregateOAuth][WARN] loadAggregateSettings 查询 DB 失败,回退只用 process.env 配置。' +
` DB 错误:${e?.message || String(e)}。 envAppId=${envAppId ? '已配置(len=' + String(envAppId).length + ')' : '空'} ` +
` envEndpoint=${envEndpoint ? '已配置(' + envEndpoint + ')' : '空'}`
)
}
const dbEnabled = base?.aggregateOAuthEnabled
const dbHasConfig = !!(
base?.aggregateOAuthAppId &&
base?.aggregateOAuthAppKey &&
base?.aggregateOAuthEndpoint
)
const enabled = Boolean(dbEnabled ?? hasEnvConfig)
const appId = (base?.aggregateOAuthAppId || envAppId || '') as string
const appKey = (base?.aggregateOAuthAppKey || envAppKey || '') as string
const loginType = ((base?.aggregateOAuthLoginType as string) || envLoginType || '') as string
const endpoint = ((base?.aggregateOAuthEndpoint as string) || envEndpoint || '') as string
const result: any = {
aggregateOAuthEnabled: false,
aggregateOAuthAppId: appId,
aggregateOAuthAppKey: appKey,
aggregateOAuthLoginType: loginType,
aggregateOAuthEndpoint: endpoint,
_dbHasConfig: dbHasConfig,
_hasEnvConfig: hasEnvConfig,
_hardDisabledReason:
'[hard-disabled] nuxt.config.ts public.oauth.aggregate 已硬编码 false,暂时关闭微信聚合登录;恢复时同时改 nuxt.config.ts 改回 !!process.env.AGGREGATE_OAUTH_APP_ID 以及删除此处的强制 false'
}
console.log(
'[AggregateOAuth] loadAggregateSettings -> ' +
` enabled=${result.aggregateOAuthEnabled}` +
` appId=${appId ? 'len=' + String(appId).length : 'EMPTY'}` +
` appKey=${appKey ? 'len=' + String(appKey).length : 'EMPTY'}` +
` loginType=${loginType || 'EMPTY'}` +
` endpoint=${endpoint || 'EMPTY'}` +
` (DB=${dbHasConfig ? '有' : '无'}配置, ENV=${hasEnvConfig ? '有' : '无'}配置, dbEnabled=${dbEnabled ?? '未设置->回退ENV'})`
)
return result
}
function normalizeEndpoint(endpoint: string): string {
return endpoint.replace(/\/+$/, '')
}
function aggregateSign(params: Record<string, string>, appKey: string): string {
const sorted = Object.keys(params)
.filter((k) => params[k] !== undefined && params[k] !== null && params[k] !== '')
.sort()
.map((k) => `${k}=${params[k]}`)
.join('&')
return createHmac('sha256', appKey).update(sorted).digest('hex')
}
const auxxUserInfoCache = new Map<string, any>()
function isAuxxEndpoint(endpoint: string): boolean {
return /(^|\.)auxx\.cn(\/|$)/i.test(endpoint)
}
const auxxStrategy: OAuthStrategy = {
async getAuthorizeUrl(redirectUri: string, state: string) {
const settings = await loadAggregateSettings()
console.log(
'[AggregateOAuth][auxx][getAuthorizeUrl] ' +
`enabled=${settings?.aggregateOAuthEnabled}` +
` endpoint=${settings?.aggregateOAuthEndpoint || 'EMPTY'}` +
` endpoint_safe_ok=${isSafeAggregateOAuthUrl(settings?.aggregateOAuthEndpoint || '')}` +
` redirect_uri=${redirectUri}` +
` state_len=${String(state || '').length}`
)
if (!settings?.aggregateOAuthEnabled || !settings.aggregateOAuthAppId || !settings.aggregateOAuthAppKey || !settings.aggregateOAuthEndpoint) {
const hint = []
if (!settings?.aggregateOAuthEnabled) hint.push('aggregateOAuthEnabled=false')
if (!settings?.aggregateOAuthAppId) hint.push('APP_ID 空')
if (!settings?.aggregateOAuthAppKey) hint.push('APP_KEY 空')
if (!settings?.aggregateOAuthEndpoint) hint.push('ENDPOINT 空')
console.error('[AggregateOAuth][auxx][getAuthorizeUrl] 配置缺失:', hint.join(' | '))
throw createError({ statusCode: 500, message: '聚合登录未配置:' + hint.join(' / ') })
}
if (!isSafeAggregateOAuthUrl(settings.aggregateOAuthEndpoint)) {
console.error(
'[AggregateOAuth][auxx][getAuthorizeUrl] endpoint 不合法,' +
'isSafeAggregateOAuthUrl 返回 false。endpoint=' +
JSON.stringify(settings.aggregateOAuthEndpoint)
)
throw createError({
statusCode: 500,
message:
'聚合登录端点不安全或格式错误:endpoint 必须是 https://xxx 或内网 http://localhost,当前值=' +
settings.aggregateOAuthEndpoint
})
}
const loginTypes = getAggregateOAuthLoginTypesOrDefault(settings.aggregateOAuthLoginType)
const loginType = loginTypes[0] || 'qq'
const endpoint = normalizeEndpoint(settings.aggregateOAuthEndpoint)
const loginQueryObj: Record<string, string> = {
act: 'login',
appid: settings.aggregateOAuthAppId,
appkey: settings.aggregateOAuthAppKey,
type: loginType,
redirect_uri: redirectUri
}
const loginQuery = new URLSearchParams(loginQueryObj).toString()
const debugQueryNoKey = new URLSearchParams({ ...loginQueryObj, appkey: '***' }).toString()
console.log(
`[AggregateOAuth][auxx][getAuthorizeUrl] 请求 auxx Step1:GET ${endpoint}/connect.php?${debugQueryNoKey}`
)
try {
const resp: any = await $fetch(`${endpoint}/connect.php?${loginQuery}`, {
headers: { Accept: 'application/json' },
timeout: 15000
})
console.log(
'[AggregateOAuth][auxx][getAuthorizeUrl] auxx Step1 返回:' +
JSON.stringify({
code: resp?.code,
msg: resp?.msg,
has_url: !!resp?.url,
url_prefix: resp?.url ? String(resp.url).slice(0, 80) + '...' : null
})
)
if (resp.code !== 0 || !resp.url) {
throw new Error(resp.msg || `获取登录跳转地址失败(auxx code=${resp?.code ?? 'N/A'})`)
}
const sep = resp.url.includes('?') ? '&' : '?'
return `${resp.url}${sep}state=${encodeURIComponent(state)}`
} catch (e: any) {
const status = e?.response?.status || e?.status || 'N/A'
const body = e?.response?._data ? JSON.stringify(e.response._data).slice(0, 400) : e?.data ? JSON.stringify(e.data).slice(0, 400) : null
console.error(
'[AggregateOAuth][auxx][getAuthorizeUrl] fetch 异常:' +
` err=${e?.message || String(e)} status=${status} body=${body}`
)
throw new Error(e.message || '获取登录跳转地址失败(auxx 不可达或凭据错误)')
}
},
async exchangeToken(code: string, redirectUri: string) {
const settings = await loadAggregateSettings()
if (!settings?.aggregateOAuthEnabled || !settings.aggregateOAuthAppId || !settings.aggregateOAuthAppKey || !settings.aggregateOAuthEndpoint) {
throw createError({ statusCode: 500, message: '聚合登录未配置' })
}
const loginTypes = getAggregateOAuthLoginTypesOrDefault(settings.aggregateOAuthLoginType)
const loginType = loginTypes[0] || 'qq'
const endpoint = normalizeEndpoint(settings.aggregateOAuthEndpoint)
const cbQuery = new URLSearchParams({
act: 'callback',
appid: settings.aggregateOAuthAppId,
appkey: settings.aggregateOAuthAppKey,
type: loginType,
code
}).toString()
try {
const resp: any = await $fetch(`${endpoint}/connect.php?${cbQuery}`, {
headers: { Accept: 'application/json' }
})
if (resp.code !== 0 || !resp.access_token || !resp.social_uid) {
throw new Error(resp.msg || '回调换取用户信息失败')
}
const cacheKey = `${settings.aggregateOAuthAppId}:${resp.access_token}`
auxxUserInfoCache.set(cacheKey, resp)
setTimeout(() => auxxUserInfoCache.delete(cacheKey), 10 * 60 * 1000)
return String(resp.access_token)
} catch (e: any) {
console.error('Auxx OAuth token exchange failed', e)
throw new Error(e.message || '回调换取用户信息失败')
}
},
async getUserInfo(accessToken: string) {
const settings = await loadAggregateSettings()
const appId = settings?.aggregateOAuthAppId || ''
const cacheKey = `${appId}:${accessToken}`
let resp = auxxUserInfoCache.get(cacheKey)
if (!resp) {
resp = Array.from(auxxUserInfoCache.values()).find((r: any) => r.access_token === accessToken)
}
if (!resp || resp.code !== 0 || !resp.social_uid) {
throw new Error('获取用户信息失败')
}
return {
id: String(resp.social_uid),
username: resp.nickname || `wx_${String(resp.social_uid).slice(0, 8)}`,
name: resp.nickname || undefined,
email: undefined,
avatar: resp.faceimg || undefined
}
}
}
const standardAggregateStrategy: OAuthStrategy = {
async getAuthorizeUrl(redirectUri: string, state: string) {
const settings = await loadAggregateSettings()
if (!settings?.aggregateOAuthEnabled || !settings.aggregateOAuthAppId || !settings.aggregateOAuthAppKey || !settings.aggregateOAuthEndpoint) {
throw createError({ statusCode: 500, message: '聚合登录未配置' })
}
if (!isSafeAggregateOAuthUrl(settings.aggregateOAuthEndpoint)) {
throw createError({ statusCode: 500, message: '聚合登录端点不安全或格式错误' })
}
const loginTypes = getAggregateOAuthLoginTypesOrDefault(settings.aggregateOAuthLoginType)
const loginType = loginTypes[0] || 'qq'
const endpoint = normalizeEndpoint(settings.aggregateOAuthEndpoint)
const timestamp = String(Math.floor(Date.now() / 1000))
const nonce = randomUUID().replace(/-/g, '')
const baseParams: Record<string, string> = {
app_id: settings.aggregateOAuthAppId,
response_type: 'code',
redirect_uri: redirectUri,
state,
login_type: loginType,
timestamp,
nonce
}
const sign = aggregateSign(baseParams, settings.aggregateOAuthAppKey)
const query = new URLSearchParams({ ...baseParams, sign }).toString()
return `${endpoint}/oauth/authorize?${query}`
},
async exchangeToken(code: string, redirectUri: string) {
const settings = await loadAggregateSettings()
if (!settings?.aggregateOAuthEnabled || !settings.aggregateOAuthAppId || !settings.aggregateOAuthAppKey || !settings.aggregateOAuthEndpoint) {
throw createError({ statusCode: 500, message: '聚合登录未配置' })
}
const endpoint = normalizeEndpoint(settings.aggregateOAuthEndpoint)
const timestamp = String(Math.floor(Date.now() / 1000))
const nonce = randomUUID().replace(/-/g, '')
const baseParams: Record<string, string> = {
app_id: settings.aggregateOAuthAppId,
grant_type: 'authorization_code',
code,
redirect_uri: redirectUri,
timestamp,
nonce
}
const sign = aggregateSign(baseParams, settings.aggregateOAuthAppKey)
try {
const tokenResponse = await $fetch<any>(`${endpoint}/oauth/token`, {
method: 'POST',
body: { ...baseParams, sign },
headers: { Accept: 'application/json' }
})
if (tokenResponse.error) {
throw new Error(tokenResponse.error_description || tokenResponse.error || '令牌请求失败')
}
const accessToken = tokenResponse.access_token || tokenResponse.accessToken
if (!accessToken) {
throw new Error('未能获取访问令牌')
}
return accessToken
} catch (e: any) {
console.error('Aggregate OAuth token exchange failed', e)
throw new Error(e.message || '令牌请求失败')
}
},
async getUserInfo(accessToken: string) {
const settings = await loadAggregateSettings()
if (!settings?.aggregateOAuthAppId || !settings?.aggregateOAuthAppKey || !settings?.aggregateOAuthEndpoint) {
throw createError({ statusCode: 500, message: '聚合登录未配置' })
}
const endpoint = normalizeEndpoint(settings.aggregateOAuthEndpoint)
const timestamp = String(Math.floor(Date.now() / 1000))
const nonce = randomUUID().replace(/-/g, '')
const baseParams: Record<string, string> = {
app_id: settings.aggregateOAuthAppId,
access_token: accessToken,
timestamp,
nonce
}
const sign = aggregateSign(baseParams, settings.aggregateOAuthAppKey)
try {
const userInfo = await $fetch<any>(`${endpoint}/oauth/userinfo`, {
method: 'POST',
body: { ...baseParams, sign },
headers: { Accept: 'application/json' }
})
return {
id: String(userInfo.id || userInfo.openid || userInfo.sub || userInfo.userId || ''),
username: userInfo.username || userInfo.nickname || userInfo.name || String(userInfo.id || 'user'),
name: userInfo.name || userInfo.nickname || undefined,
email: userInfo.email || undefined,
avatar: userInfo.avatar || userInfo.avatar_url || userInfo.headimgurl || undefined
}
} catch (e: any) {
console.error('Aggregate OAuth user info failed', e)
throw new Error('获取用户信息失败')
}
}
}
const aggregateStrategy: OAuthStrategy = {
async getAuthorizeUrl(redirectUri: string, state: string) {
const settings = await loadAggregateSettings()
const endpoint = settings?.aggregateOAuthEndpoint || ''
return isAuxxEndpoint(endpoint)
? auxxStrategy.getAuthorizeUrl(redirectUri, state)
: standardAggregateStrategy.getAuthorizeUrl(redirectUri, state)
},
async exchangeToken(code: string, redirectUri: string) {
const settings = await loadAggregateSettings()
const endpoint = settings?.aggregateOAuthEndpoint || ''
return isAuxxEndpoint(endpoint)
? auxxStrategy.exchangeToken(code, redirectUri)
: standardAggregateStrategy.exchangeToken(code, redirectUri)
},
async getUserInfo(accessToken: string) {
const settings = await loadAggregateSettings()
const endpoint = settings?.aggregateOAuthEndpoint || ''
return isAuxxEndpoint(endpoint)
? auxxStrategy.getUserInfo(accessToken)
: standardAggregateStrategy.getUserInfo(accessToken)
}
}
strategies.aggregate = aggregateStrategy
export const getOAuthStrategy = (provider: string): OAuthStrategy => {
const strategy = strategies[provider]
if (!strategy) {
throw createError({ statusCode: 400, message: `Unknown provider: ${provider}` })
}
return strategy
}