feat: 在accessToken的endpoint和oauth的aspect中支持了PKCE相关支持
This commit is contained in:
parent
b6aea50539
commit
44c969635f
|
|
@ -21,7 +21,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
},
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<string>;
|
||||
|
||||
|
||||
/**
|
||||
* 合并用户账号,将一个用户的数据迁移到另一个用户
|
||||
* @param from 源用户 ID
|
||||
|
|
@ -31,7 +31,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
params: { from: string; to: string },
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<void>;
|
||||
|
||||
|
||||
/**
|
||||
* 刷新微信公众号用户信息(昵称、头像、性别等)
|
||||
*/
|
||||
|
|
@ -39,7 +39,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
params: {},
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<void>;
|
||||
|
||||
|
||||
/**
|
||||
* 获取微信小程序用户的手机号
|
||||
* @param code 微信小程序获取手机号的 code
|
||||
|
|
@ -50,7 +50,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
params: { code: string; env: WechatMpEnv },
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<string>;
|
||||
|
||||
|
||||
/**
|
||||
* 通过手机号绑定当前登录用户
|
||||
* @param mobile 手机号
|
||||
|
|
@ -65,7 +65,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
},
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<void>;
|
||||
|
||||
|
||||
/**
|
||||
* 通过邮箱绑定当前登录用户
|
||||
* @param email 邮箱地址
|
||||
|
|
@ -80,7 +80,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
},
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<void>;
|
||||
|
||||
|
||||
/**
|
||||
* 通过手机号和验证码登录
|
||||
* @param mobile 手机号
|
||||
|
|
@ -98,7 +98,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
},
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<string>;
|
||||
|
||||
|
||||
/**
|
||||
* 验证用户密码是否正确
|
||||
* @param password 密码(明文或 SHA1 密文,根据系统配置)
|
||||
|
|
@ -111,7 +111,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
},
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<void>;
|
||||
|
||||
|
||||
/**
|
||||
* 通过账号(手机号/邮箱/登录名)和密码登录
|
||||
* @param account 账号(可以是手机号、邮箱或登录名)
|
||||
|
|
@ -127,7 +127,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
},
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<string>;
|
||||
|
||||
|
||||
/**
|
||||
* 通过邮箱和验证码登录
|
||||
* @param email 邮箱地址
|
||||
|
|
@ -145,7 +145,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
},
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<string>;
|
||||
|
||||
|
||||
/**
|
||||
* 微信公众号登录
|
||||
* @param code 微信授权 code
|
||||
|
|
@ -165,7 +165,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
},
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<string>;
|
||||
|
||||
|
||||
/**
|
||||
* 用户登出,使指定 token 失效
|
||||
* @param tokenValue 要失效的 token
|
||||
|
|
@ -174,7 +174,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
params: { tokenValue: string },
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<void>;
|
||||
|
||||
|
||||
/**
|
||||
* 微信小程序登录
|
||||
* @param code 微信授权 code
|
||||
|
|
@ -191,7 +191,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
},
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<string>;
|
||||
|
||||
|
||||
/**
|
||||
* 微信原生 APP 登录
|
||||
* @param code 微信授权 code
|
||||
|
|
@ -208,7 +208,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
},
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<string>;
|
||||
|
||||
|
||||
/**
|
||||
* 同步微信小程序用户信息(昵称、头像等)
|
||||
* @param nickname 昵称
|
||||
|
|
@ -233,7 +233,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
},
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<void>;
|
||||
|
||||
|
||||
/**
|
||||
* 唤醒寄生用户(将 shadow 状态的用户激活)
|
||||
* @param id 用户 ID
|
||||
|
|
@ -247,7 +247,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
},
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<string>;
|
||||
|
||||
|
||||
/**
|
||||
* 刷新 token,延长有效期
|
||||
* @param tokenValue 当前 token
|
||||
|
|
@ -263,7 +263,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
},
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<string>;
|
||||
|
||||
|
||||
/**
|
||||
* 通过手机号发送验证码
|
||||
* @param mobile 手机号
|
||||
|
|
@ -279,7 +279,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
},
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<string>;
|
||||
|
||||
|
||||
/**
|
||||
* 通过邮箱发送验证码
|
||||
* @param email 邮箱地址
|
||||
|
|
@ -295,7 +295,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
},
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<string>;
|
||||
|
||||
|
||||
/**
|
||||
* 根据域名和应用类型获取应用信息,并检查版本兼容性
|
||||
* @param version 客户端版本号
|
||||
|
|
@ -315,7 +315,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
},
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<string>;
|
||||
|
||||
|
||||
/**
|
||||
* 生成微信 JS-SDK 签名,用于调用微信 JS 接口
|
||||
* @param url 当前页面 URL
|
||||
|
|
@ -334,7 +334,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
timestamp: number;
|
||||
appId: string;
|
||||
}>;
|
||||
|
||||
|
||||
/**
|
||||
* 更新平台或系统的配置信息
|
||||
* @param entity 实体类型(platform 或 system)
|
||||
|
|
@ -349,7 +349,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
},
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<void>;
|
||||
|
||||
|
||||
/**
|
||||
* 更新平台、系统或应用的样式配置
|
||||
* @param entity 实体类型(platform/system/application)
|
||||
|
|
@ -364,7 +364,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
},
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<void>;
|
||||
|
||||
|
||||
/**
|
||||
* 更新应用的配置信息
|
||||
* @param entity 实体类型(application)
|
||||
|
|
@ -379,7 +379,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
},
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<void>;
|
||||
|
||||
|
||||
/**
|
||||
* 切换到指定用户(管理员扮演用户功能)
|
||||
* @param userId 目标用户 ID
|
||||
|
|
@ -390,7 +390,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
},
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<void>;
|
||||
|
||||
|
||||
/**
|
||||
* 获取小程序无限制二维码
|
||||
* @param wechatQrCodeId 微信二维码 ID
|
||||
|
|
@ -400,7 +400,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
wechatQrCodeId: string,
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<string>;
|
||||
|
||||
|
||||
/**
|
||||
* 创建微信登录会话(用于扫码登录场景)
|
||||
* @param type 登录类型(login-登录,bind-绑定)
|
||||
|
|
@ -414,7 +414,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
},
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<string>;
|
||||
|
||||
|
||||
/**
|
||||
* 解绑微信用户
|
||||
* @param wechatUserId 微信用户 ID
|
||||
|
|
@ -429,7 +429,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
},
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<void>;
|
||||
|
||||
|
||||
/**
|
||||
* 通过微信登录会话 ID 完成登录(Web 端扫码登录确认)
|
||||
* @param wechatLoginId 微信登录会话 ID
|
||||
|
|
@ -443,7 +443,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
},
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<string>;
|
||||
|
||||
|
||||
/**
|
||||
* 从 URL 中提取网页信息(标题、发布时间、图片列表)
|
||||
* @param url 网页 URL
|
||||
|
|
@ -454,7 +454,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
publishDate: number | undefined;
|
||||
imageList: string[];
|
||||
}>;
|
||||
|
||||
|
||||
/**
|
||||
* 获取用户可用的修改密码方式
|
||||
* @param userId 用户 ID
|
||||
|
|
@ -464,7 +464,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
params: { userId: string },
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<string[]>;
|
||||
|
||||
|
||||
/**
|
||||
* 修改用户密码
|
||||
* @param userId 用户 ID
|
||||
|
|
@ -484,7 +484,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
},
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<{ result: string; times?: number }>;
|
||||
|
||||
|
||||
/**
|
||||
* 创建或获取会话(用于客服系统等场景)
|
||||
* @param data 微信事件数据(可选)
|
||||
|
|
@ -502,7 +502,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
},
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<string>;
|
||||
|
||||
|
||||
/**
|
||||
* 上传素材到微信服务器
|
||||
* @param params 包含文件信息、应用 ID、素材类型等
|
||||
|
|
@ -512,7 +512,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
params: any,
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<{ mediaId: string }>;
|
||||
|
||||
|
||||
/**
|
||||
* 获取微信公众号当前使用的自定义菜单配置
|
||||
* @param applicationId 应用 ID
|
||||
|
|
@ -524,7 +524,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
},
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<any>;
|
||||
|
||||
|
||||
/**
|
||||
* 获取微信公众号自定义菜单配置(包括默认和个性化菜单)
|
||||
* @param applicationId 应用 ID
|
||||
|
|
@ -536,7 +536,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
},
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<any>;
|
||||
|
||||
|
||||
/**
|
||||
* 创建微信公众号自定义菜单
|
||||
* @param applicationId 应用 ID
|
||||
|
|
@ -551,7 +551,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
},
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<any>;
|
||||
|
||||
|
||||
/**
|
||||
* 创建微信公众号个性化菜单(针对特定用户群体)
|
||||
* @param applicationId 应用 ID
|
||||
|
|
@ -566,7 +566,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
},
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<any>;
|
||||
|
||||
|
||||
/**
|
||||
* 删除微信公众号个性化菜单
|
||||
* @param applicationId 应用 ID
|
||||
|
|
@ -579,7 +579,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
},
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<any>;
|
||||
|
||||
|
||||
/**
|
||||
* 删除微信公众号自定义菜单
|
||||
* @param applicationId 应用 ID
|
||||
|
|
@ -590,7 +590,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
},
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<any>;
|
||||
|
||||
|
||||
/**
|
||||
* 批量获取微信公众号图文消息素材
|
||||
* @param applicationId 应用 ID
|
||||
|
|
@ -608,7 +608,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
},
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<any>;
|
||||
|
||||
|
||||
/**
|
||||
* 获取微信公众号单个图文消息素材
|
||||
* @param applicationId 应用 ID
|
||||
|
|
@ -622,7 +622,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
},
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<any>;
|
||||
|
||||
|
||||
/**
|
||||
* 批量获取微信素材列表
|
||||
* @param applicationId 应用 ID
|
||||
|
|
@ -640,7 +640,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
},
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<any>;
|
||||
|
||||
|
||||
/**
|
||||
* 获取微信素材
|
||||
* @param applicationId 应用 ID
|
||||
|
|
@ -656,7 +656,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
},
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<any>;
|
||||
|
||||
|
||||
/**
|
||||
* 删除微信永久素材
|
||||
* @param applicationId 应用 ID
|
||||
|
|
@ -669,7 +669,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
},
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<any>;
|
||||
|
||||
|
||||
/**
|
||||
* 创建微信公众号用户标签
|
||||
* @param applicationId 应用 ID
|
||||
|
|
@ -683,7 +683,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
},
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<any>;
|
||||
|
||||
|
||||
/**
|
||||
* 获取微信公众号所有用户标签
|
||||
* @param applicationId 应用 ID
|
||||
|
|
@ -695,7 +695,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
},
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<any>;
|
||||
|
||||
|
||||
/**
|
||||
* 编辑微信公众号用户标签
|
||||
* @param applicationId 应用 ID
|
||||
|
|
@ -710,7 +710,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
},
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<any>;
|
||||
|
||||
|
||||
/**
|
||||
* 删除微信公众号用户标签
|
||||
* @param applicationId 应用 ID
|
||||
|
|
@ -725,7 +725,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
},
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<any>;
|
||||
|
||||
|
||||
/**
|
||||
* 同步微信公众号消息模板到本地
|
||||
* @param applicationId 应用 ID
|
||||
|
|
@ -737,7 +737,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
},
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<any>;
|
||||
|
||||
|
||||
/**
|
||||
* 获取已注册的消息类型列表
|
||||
* @returns 返回消息类型数组
|
||||
|
|
@ -746,7 +746,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
params: {},
|
||||
content: BackendRuntimeContext<ED>
|
||||
) => Promise<string[]>;
|
||||
|
||||
|
||||
/**
|
||||
* 同步单个微信公众号用户标签到微信服务器
|
||||
* @param applicationId 应用 ID
|
||||
|
|
@ -759,7 +759,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
},
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<any>;
|
||||
|
||||
|
||||
/**
|
||||
* 一键同步微信公众号用户标签(从微信服务器同步到本地)
|
||||
* @param applicationId 应用 ID
|
||||
|
|
@ -770,7 +770,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
},
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<any>;
|
||||
|
||||
|
||||
/**
|
||||
* 获取指定标签下的微信用户列表
|
||||
* @param applicationId 应用 ID
|
||||
|
|
@ -784,7 +784,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
},
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<any>;
|
||||
|
||||
|
||||
/**
|
||||
* 批量为用户打标签
|
||||
* @param applicationId 应用 ID
|
||||
|
|
@ -799,7 +799,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
},
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<any>;
|
||||
|
||||
|
||||
/**
|
||||
* 批量为用户取消标签
|
||||
* @param applicationId 应用 ID
|
||||
|
|
@ -814,7 +814,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
},
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<any>;
|
||||
|
||||
|
||||
/**
|
||||
* 获取用户身上的标签列表
|
||||
* @param applicationId 应用 ID
|
||||
|
|
@ -828,7 +828,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
},
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<any>;
|
||||
|
||||
|
||||
/**
|
||||
* 获取微信公众号用户列表
|
||||
* @param applicationId 应用 ID
|
||||
|
|
@ -842,7 +842,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
},
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<any>;
|
||||
|
||||
|
||||
/**
|
||||
* 为单个用户设置标签列表
|
||||
* @param applicationId 应用 ID
|
||||
|
|
@ -857,7 +857,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
},
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<any>;
|
||||
|
||||
|
||||
/**
|
||||
* 从微信服务器同步用户标签到本地
|
||||
* @param applicationId 应用 ID
|
||||
|
|
@ -870,7 +870,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
},
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<any>;
|
||||
|
||||
|
||||
/**
|
||||
* 将本地用户标签同步到微信服务器
|
||||
* @param applicationId 应用 ID
|
||||
|
|
@ -885,7 +885,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
},
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<any>;
|
||||
|
||||
|
||||
/**
|
||||
* 同步短信模板(从服务商同步到本地)
|
||||
* @param systemId 系统 ID
|
||||
|
|
@ -898,7 +898,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
},
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<void>;
|
||||
|
||||
|
||||
/**
|
||||
* 获取应用的登录方式配置列表
|
||||
* @param applicationId 应用 ID
|
||||
|
|
@ -910,7 +910,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
},
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<EntityDict['applicationPassport']['Schema'][]>;
|
||||
|
||||
|
||||
/**
|
||||
* 根据登录方式 ID 列表删除应用的登录方式配置
|
||||
* @param passportIds 登录方式 ID 列表
|
||||
|
|
@ -921,7 +921,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
},
|
||||
content: BackendRuntimeContext<ED>
|
||||
) => Promise<void>;
|
||||
|
||||
|
||||
/**
|
||||
* 通过 OAuth 2.0 第三方登录
|
||||
* @param code OAuth 授权码
|
||||
|
|
@ -937,7 +937,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
},
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<string>;
|
||||
|
||||
|
||||
/**
|
||||
* 创建 OAuth 登录/绑定状态码
|
||||
* @param providerId OAuth 提供商 ID
|
||||
|
|
@ -953,7 +953,7 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
},
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<string>;
|
||||
|
||||
|
||||
/**
|
||||
* OAuth 2.0 授权确认(用户同意或拒绝授权)
|
||||
* @param response_type 响应类型(固定为 "code")
|
||||
|
|
@ -972,12 +972,16 @@ export type AspectDict<ED extends EntityDict> = {
|
|||
scope: string;
|
||||
state: string;
|
||||
action: "grant" | "deny";
|
||||
|
||||
// PKCE 支持
|
||||
code_challenge?: string;
|
||||
code_challenge_method?: 'plain' | 'S256';
|
||||
},
|
||||
context: BackendRuntimeContext<ED>
|
||||
) => Promise<{
|
||||
redirectUri: string;
|
||||
}>
|
||||
|
||||
|
||||
/**
|
||||
* 获取 OAuth 客户端应用信息
|
||||
* @param client_id 客户端应用 ID
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ export async function loginByOauth<ED extends EntityDict>(params: {
|
|||
filter: {
|
||||
state: stateCode,
|
||||
},
|
||||
}, {})
|
||||
}, { dontCollect: true })
|
||||
|
||||
assert(state, '无效的 state 参数');
|
||||
assert(state.provider?.ableState && state.provider?.ableState === 'enabled', '该 OAuth 提供商已被禁用');
|
||||
|
|
@ -60,7 +60,7 @@ export async function loginByOauth<ED extends EntityDict>(params: {
|
|||
filter: {
|
||||
id: state.id,
|
||||
}
|
||||
}, {});
|
||||
}, { dontCollect: true });
|
||||
|
||||
// 使用 code 换取 access_token 并获取用户信息
|
||||
const { oauthUserInfo, accessToken, refreshToken, accessTokenExp, refreshTokenExp } = await fetchOAuthUserInfo(
|
||||
|
|
@ -87,7 +87,7 @@ export async function loginByOauth<ED extends EntityDict>(params: {
|
|||
providerUserId: oauthUserInfo.providerUserId,
|
||||
providerConfigId: state.providerId!,
|
||||
}
|
||||
}, {})
|
||||
}, { dontCollect: true })
|
||||
|
||||
// 已登录的情况
|
||||
if (islogginedIn) {
|
||||
|
|
@ -130,7 +130,7 @@ export async function loginByOauth<ED extends EntityDict>(params: {
|
|||
applicationId,
|
||||
stateId: state.id,
|
||||
}
|
||||
}, {});
|
||||
}, { dontCollect: true });
|
||||
|
||||
// 返回当前 token
|
||||
const tokenValue = context.getTokenValue()!;
|
||||
|
|
@ -171,7 +171,7 @@ export async function loginByOauth<ED extends EntityDict>(params: {
|
|||
filter: {
|
||||
id: existingOAuthUser.id,
|
||||
}
|
||||
}, {});
|
||||
}, { dontCollect: true });
|
||||
|
||||
await loadTokenInfo(tokenValue, context);
|
||||
closeRootMode();
|
||||
|
|
@ -219,7 +219,7 @@ export async function loginByOauth<ED extends EntityDict>(params: {
|
|||
filter: {
|
||||
id: newUserId,
|
||||
}
|
||||
}, {});
|
||||
}, { dontCollect: true });
|
||||
|
||||
await loadTokenInfo(tokenValue, context);
|
||||
closeRootMode();
|
||||
|
|
@ -248,7 +248,7 @@ export async function getOAuthClientInfo<ED extends EntityDict>(params: {
|
|||
systemId: systemId,
|
||||
ableState: "enabled",
|
||||
}
|
||||
}, {})
|
||||
}, { dontCollect: true })
|
||||
|
||||
// 如果还有正在生效的授权,说明已经授权过了
|
||||
const [hasAuth] = await context.select("oauthUserAuthorization", {
|
||||
|
|
@ -279,7 +279,7 @@ export async function getOAuthClientInfo<ED extends EntityDict>(params: {
|
|||
userId: currentUserId,
|
||||
}
|
||||
}
|
||||
}, {})
|
||||
}, { dontCollect: true })
|
||||
|
||||
if (hasAuth) {
|
||||
console.log("用户已有授权记录:", currentUserId, hasAuth.id, hasAuth.userId, hasAuth.applicationId, hasAuth.usageState);
|
||||
|
|
@ -318,7 +318,7 @@ export async function createOAuthState<ED extends EntityDict>(params: {
|
|||
type,
|
||||
state
|
||||
}
|
||||
}, {})
|
||||
}, { dontCollect: true })
|
||||
|
||||
closeRootMode();
|
||||
return state;
|
||||
|
|
@ -330,8 +330,12 @@ export async function authorize<ED extends EntityDict>(params: {
|
|||
scope?: string;
|
||||
state?: string;
|
||||
action: 'grant' | 'deny';
|
||||
|
||||
// PKCE 支持
|
||||
code_challenge?: string;
|
||||
code_challenge_method?: 'plain' | 'S256';
|
||||
}, context: BRC<ED>) {
|
||||
const { response_type, client_id, redirect_uri, scope, state, action } = params;
|
||||
const { response_type, client_id, redirect_uri, scope, state, action, code_challenge, code_challenge_method } = params;
|
||||
|
||||
if (response_type !== 'code') {
|
||||
throw new OakUserException('不支持的 response_type 类型');
|
||||
|
|
@ -350,7 +354,7 @@ export async function authorize<ED extends EntityDict>(params: {
|
|||
id: client_id,
|
||||
systemId: systemId,
|
||||
}
|
||||
}, {})
|
||||
}, { dontCollect: true })
|
||||
|
||||
if (!oauthApp) {
|
||||
throw new OakUserException('未经授权的客户端应用');
|
||||
|
|
@ -368,7 +372,7 @@ export async function authorize<ED extends EntityDict>(params: {
|
|||
usageState: action === 'grant' ? 'unused' : 'denied',
|
||||
authorizedAt: Date.now(),
|
||||
}
|
||||
}, {})
|
||||
}, { dontCollect: true })
|
||||
|
||||
if (action === 'deny') {
|
||||
const params = new URLSearchParams();
|
||||
|
|
@ -407,8 +411,12 @@ export async function authorize<ED extends EntityDict>(params: {
|
|||
userId: context.getCurrentUserId()!,
|
||||
scope: scope === undefined ? [] : [scope],
|
||||
expiresAt: Date.now() + 10 * 60 * 1000, // 10分钟后过期
|
||||
|
||||
// PKCE 支持
|
||||
codeChallenge: code_challenge,
|
||||
codeChallengeMethod: code_challenge_method || 'plain',
|
||||
}
|
||||
}, {})
|
||||
}, { dontCollect: true })
|
||||
|
||||
// 更新记录
|
||||
await context.operate("oauthUserAuthorization", {
|
||||
|
|
|
|||
|
|
@ -8,6 +8,27 @@ import { applicationProjection, extraFileProjection } from "../types/Projection"
|
|||
import { composeFileUrl } from "../utils/cos/index.backend";
|
||||
import assert from "assert";
|
||||
import { checkOauthTokenAvaliable } from "../utils/oauth";
|
||||
import { createHash } from "crypto";
|
||||
|
||||
// PKCE 验证函数
|
||||
async function verifyPKCE(
|
||||
verifier: string,
|
||||
challenge: string,
|
||||
method: 'plain' | 'S256'
|
||||
): Promise<boolean> {
|
||||
if (method === 'plain') {
|
||||
return verifier === challenge;
|
||||
} else if (method === 'S256') {
|
||||
const hash = createHash('sha256').update(verifier).digest();
|
||||
const computed = hash.toString('base64')
|
||||
.replace(/\+/g, '-')
|
||||
.replace(/\//g, '_')
|
||||
.replace(/=/g, '');
|
||||
return computed === challenge;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
const oauthTokenEndpoint: Endpoint<EntityDict, BackendRuntimeContext<EntityDict>> = {
|
||||
name: "获取OAuth Token",
|
||||
|
|
@ -16,7 +37,21 @@ const oauthTokenEndpoint: Endpoint<EntityDict, BackendRuntimeContext<EntityDict>
|
|||
type: "free",
|
||||
fn: async (contextBuilder, params, header, req, body) => {
|
||||
const context = await contextBuilder()
|
||||
const { client_id, client_secret, grant_type, code, redirect_uri } = body as { client_id: string, client_secret: string, grant_type: string, code?: string, redirect_uri?: string };
|
||||
const {
|
||||
client_id,
|
||||
client_secret,
|
||||
grant_type,
|
||||
code,
|
||||
redirect_uri,
|
||||
code_verifier // PKCE支持
|
||||
} = body as {
|
||||
client_id: string,
|
||||
client_secret: string,
|
||||
grant_type: string,
|
||||
code?: string,
|
||||
redirect_uri?: string
|
||||
code_verifier?: string
|
||||
};
|
||||
const [app] = await context.select("oauthApplication", {
|
||||
data: {
|
||||
id: 1,
|
||||
|
|
@ -61,6 +96,8 @@ const oauthTokenEndpoint: Endpoint<EntityDict, BackendRuntimeContext<EntityDict>
|
|||
userId: 1,
|
||||
expiresAt: 1,
|
||||
usedAt: 1,
|
||||
codeChallenge: 1,
|
||||
codeChallengeMethod: 1,
|
||||
},
|
||||
filter: {
|
||||
code,
|
||||
|
|
@ -76,6 +113,40 @@ const oauthTokenEndpoint: Endpoint<EntityDict, BackendRuntimeContext<EntityDict>
|
|||
};
|
||||
}
|
||||
|
||||
// PKCE 验证
|
||||
if (authCodeRecord.codeChallenge) {
|
||||
if (!code_verifier) {
|
||||
await context.commit();
|
||||
return {
|
||||
statusCode: 400,
|
||||
data: {
|
||||
error: "invalid_request",
|
||||
error_description: "code_verifier is required",
|
||||
success: false
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// 验证 code_verifier
|
||||
const isValid = await verifyPKCE(
|
||||
code_verifier,
|
||||
authCodeRecord.codeChallenge as string,
|
||||
authCodeRecord.codeChallengeMethod as 'plain' | 'S256'
|
||||
);
|
||||
|
||||
if (!isValid) {
|
||||
await context.commit();
|
||||
return {
|
||||
statusCode: 400,
|
||||
data: {
|
||||
error: "invalid_grant",
|
||||
error_description: "Invalid code_verifier",
|
||||
success: false
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// 验证redirect_uri
|
||||
if (authCodeRecord.redirectUri !== redirect_uri) {
|
||||
await context.commit();
|
||||
|
|
|
|||
Loading…
Reference in New Issue