From 0e05a3ad4ef425ef899c5063228a08c3dcbaaf0d Mon Sep 17 00:00:00 2001 From: qcqcqc <1220204124@zust.edu.cn> Date: Wed, 24 Dec 2025 12:26:47 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8Doauth-app=E5=92=8Cprov?= =?UTF-8?q?ider=E7=9A=84systemId=E5=A1=AB=E5=85=85=E9=97=AE=E9=A2=98?= =?UTF-8?q?=EF=BC=8C=E5=B0=86oauth=E8=AE=A4=E8=AF=81=E9=A1=B5=E6=9C=AA?= =?UTF-8?q?=E7=99=BB=E5=BD=95=E5=9B=9E=E8=B0=83=E4=BB=A5=E5=8F=8Aoauth?= =?UTF-8?q?=E7=BB=93=E6=9E=9C=E9=A1=B5=E9=9D=A2=E7=9A=84=E6=8C=89=E9=92=AE?= =?UTF-8?q?=E5=9B=9E=E8=B0=83=EF=BC=8C=E5=85=A8=E9=83=A8=E4=BA=A4=E7=BB=99?= =?UTF-8?q?=E4=B8=8A=E5=B1=82=E5=BA=94=E7=94=A8=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../login/oauth/authorize/index.d.ts | 18 ++++- es/components/login/oauth/authorize/index.js | 42 +++++++---- es/components/oauth/index.d.ts | 8 ++- es/components/oauth/index.js | 21 ++++-- es/features/token.d.ts | 3 + es/features/token.js | 3 + es/triggers/index.d.ts | 2 +- es/triggers/oauthApps.js | 3 +- es/triggers/oauthProvider.js | 3 +- es/triggers/toDo.d.ts | 2 +- lib/features/token.d.ts | 3 + lib/features/token.js | 3 + lib/triggers/index.d.ts | 2 +- lib/triggers/oauthApps.js | 3 +- lib/triggers/oauthProvider.js | 3 +- src/components/login/oauth/authorize/index.ts | 69 +++++++++++++++---- src/components/oauth/index.ts | 36 +++++++--- src/triggers/oauthApps.ts | 4 +- src/triggers/oauthProvider.ts | 4 +- 19 files changed, 173 insertions(+), 59 deletions(-) diff --git a/es/components/login/oauth/authorize/index.d.ts b/es/components/login/oauth/authorize/index.d.ts index 4afcc50ae..6d72bbeef 100644 --- a/es/components/login/oauth/authorize/index.d.ts +++ b/es/components/login/oauth/authorize/index.d.ts @@ -1,3 +1,19 @@ import { EntityDict } from '../../../../oak-app-domain'; -declare const _default: (props: import("oak-frontend-base").ReactComponentProps) => React.ReactElement; +import { ReactComponentProps } from 'oak-frontend-base'; +import { EntityDict as BaseEntityDict } from 'oak-domain/lib/base-app-domain'; +/** + * OAuth 授权页面组件 + */ +declare const _default: (props: ReactComponentProps void; +}>) => React.ReactElement; export default _default; diff --git a/es/components/login/oauth/authorize/index.js b/es/components/login/oauth/authorize/index.js index 72e84c2c8..de8d6374a 100644 --- a/es/components/login/oauth/authorize/index.js +++ b/es/components/login/oauth/authorize/index.js @@ -1,9 +1,14 @@ import assert from "assert"; +/** + * OAuth 授权页面组件 + */ export default OakComponent({ // Virtual Component isList: false, filters: [], - properties: {}, + properties: { + onUnLogin: null, + }, data: { clientInfo: null, loading: true, @@ -38,18 +43,29 @@ export default OakComponent({ // load userinfo const userId = this.features.token.getUserId(true); if (!userId) { - const params = new URLSearchParams(); - params.set('response_type', responseType || ""); - params.set('client_id', clientId || ""); - params.set('redirect_uri', redirectUri || ""); - params.set('scope', scope || ""); - params.set('state', state || ""); - const redirectUrl = `/login/oauth/authorize?${params.toString()}`; - console.log('Not logged in, redirecting to login page:', redirectUrl); - const encoded = btoa(encodeURIComponent(redirectUrl)); - this.features.navigator.navigateTo({ - url: `/login?redirect=${encoded}`, - }, undefined, true); + // const params = new URLSearchParams(); + // params.set('response_type', responseType || ""); + // params.set('client_id', clientId || ""); + // params.set('redirect_uri', redirectUri || ""); + // params.set('scope', scope || ""); + // params.set('state', state || ""); + // const redirectUrl = `/login/oauth/authorize?${params.toString()}`; + // console.log('Not logged in, redirecting to login page:', redirectUrl); + // const encoded = btoa(encodeURIComponent(redirectUrl)); + // this.features.navigator.navigateTo({ + // url: `/login?redirect=${encoded}`, + // }, undefined, true); + if (!this.props.onUnLogin) { + console.error('用户未登录,请在使用Oauth授权组件时配置onUnLogin回调函数'); + return; + } + this.props.onUnLogin({ + response_type: responseType, + client_id: clientId, + redirect_uri: redirectUri, + scope: scope, + state: state, + }); return; } const userInfo = this.features.token.getUserInfo(); diff --git a/es/components/oauth/index.d.ts b/es/components/oauth/index.d.ts index 73d6c0526..8d45d5e91 100644 --- a/es/components/oauth/index.d.ts +++ b/es/components/oauth/index.d.ts @@ -1,2 +1,8 @@ -declare const _default: (props: import("oak-frontend-base").ReactComponentProps) => React.ReactElement; +import { EntityDict } from "../../oak-app-domain"; +import { EntityDict as BaseEntityDict } from "oak-domain/lib/base-app-domain"; +import { ReactComponentProps } from "oak-frontend-base"; +declare const _default: (props: ReactComponentProps void; + onSuccess: () => void; +}>) => React.ReactElement; export default _default; diff --git a/es/components/oauth/index.js b/es/components/oauth/index.js index a2e0b5116..98c986732 100644 --- a/es/components/oauth/index.js +++ b/es/components/oauth/index.js @@ -3,7 +3,10 @@ export default OakComponent({ // Virtual Component isList: false, filters: [], - properties: {}, + properties: { + onRetry: null, + onSuccess: null, + }, data: { hasError: false, errorMessage: '', @@ -51,14 +54,18 @@ export default OakComponent({ this.setState({ hasError: true, errorMessage: message }); }, retry() { - this.features.navigator.redirectTo({ - url: '/login', - }); + if (!this.props.onRetry) { + console.error('未设置失败重试回调函数,请在使用Oauth组件时配置onRetry属性'); + return; + } + this.props.onRetry(); }, returnToIndex() { - this.features.navigator.redirectTo({ - url: '/', - }); + if (!this.props.onSuccess) { + console.error('未设置成功回调函数,请在使用Oauth组件时配置onSuccess属性'); + return; + } + this.props.onSuccess(); } } }); diff --git a/es/features/token.d.ts b/es/features/token.d.ts index b8f684af5..36fb04366 100644 --- a/es/features/token.d.ts +++ b/es/features/token.d.ts @@ -50,6 +50,9 @@ export declare class Token extends Feature { wakeupParasite(id: string): Promise; needVerifyPassword(): boolean | null | undefined; verifyPassword(password: string): Promise; + /** + * 添加一个异常到忽略列表,如果refreshToken时出现这个异常,不会强制用户登出 + */ addIgnoreException(clazz: typeof OakException): void; removeIgnoreException(clazz: typeof OakException): void; } diff --git a/es/features/token.js b/es/features/token.js index 2f7fd7d9c..eab7c5302 100644 --- a/es/features/token.js +++ b/es/features/token.js @@ -370,6 +370,9 @@ export class Token extends Feature { env, }); } + /** + * 添加一个异常到忽略列表,如果refreshToken时出现这个异常,不会强制用户登出 + */ addIgnoreException(clazz) { if (!this.ignoreExceptionList.includes(clazz)) { this.ignoreExceptionList.push(clazz); diff --git a/es/triggers/index.d.ts b/es/triggers/index.d.ts index 5e0cf60ac..e5cf26df7 100644 --- a/es/triggers/index.d.ts +++ b/es/triggers/index.d.ts @@ -1,2 +1,2 @@ -declare const _default: (import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger>)[]; +declare const _default: (import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger>)[]; export default _default; diff --git a/es/triggers/oauthApps.js b/es/triggers/oauthApps.js index 20675a31b..4d04542cd 100644 --- a/es/triggers/oauthApps.js +++ b/es/triggers/oauthApps.js @@ -10,8 +10,7 @@ const triggers = [ fn: async ({ operation }, context) => { assert(operation.data && !Array.isArray(operation.data), "oauthApplication create data 必须存在且为单条记录"); const { data } = operation; - const systemId = context.getSystemId(); - data.systemId = systemId; + assert(data.systemId, "oauthApplication 创建时必须指定 systemId"); data.clientSecret = randomUUID(); // 默认不强制 PKCE data.requirePKCE = data.requirePKCE ?? false; diff --git a/es/triggers/oauthProvider.js b/es/triggers/oauthProvider.js index 4bf4b19fe..0ed0bb9ce 100644 --- a/es/triggers/oauthProvider.js +++ b/es/triggers/oauthProvider.js @@ -8,8 +8,7 @@ const triggers = [ fn: async ({ operation }, context) => { assert(operation.data && !Array.isArray(operation.data), "oauthProvider create data 必须存在且为单条记录"); const { data } = operation; - const systemId = context.getSystemId(); - data.systemId = systemId; + assert(data.systemId, "oauthProvider 创建时必须指定 systemId"); return 0; } }, diff --git a/es/triggers/toDo.d.ts b/es/triggers/toDo.d.ts index e5be399e1..1d9bc2ce2 100644 --- a/es/triggers/toDo.d.ts +++ b/es/triggers/toDo.d.ts @@ -14,7 +14,7 @@ export declare function createToDo; +}, userIds?: string[]): Promise<0 | 1>; /** * 完成todo例程,当在entity对象上进行action操作时(操作条件是filter),将对应的todo完成 * 必须在entity的action的后trigger中调用 diff --git a/lib/features/token.d.ts b/lib/features/token.d.ts index b8f684af5..36fb04366 100644 --- a/lib/features/token.d.ts +++ b/lib/features/token.d.ts @@ -50,6 +50,9 @@ export declare class Token extends Feature { wakeupParasite(id: string): Promise; needVerifyPassword(): boolean | null | undefined; verifyPassword(password: string): Promise; + /** + * 添加一个异常到忽略列表,如果refreshToken时出现这个异常,不会强制用户登出 + */ addIgnoreException(clazz: typeof OakException): void; removeIgnoreException(clazz: typeof OakException): void; } diff --git a/lib/features/token.js b/lib/features/token.js index f78b2ca57..89fc8c6e4 100644 --- a/lib/features/token.js +++ b/lib/features/token.js @@ -373,6 +373,9 @@ class Token extends Feature_1.Feature { env, }); } + /** + * 添加一个异常到忽略列表,如果refreshToken时出现这个异常,不会强制用户登出 + */ addIgnoreException(clazz) { if (!this.ignoreExceptionList.includes(clazz)) { this.ignoreExceptionList.push(clazz); diff --git a/lib/triggers/index.d.ts b/lib/triggers/index.d.ts index 5e0cf60ac..e5cf26df7 100644 --- a/lib/triggers/index.d.ts +++ b/lib/triggers/index.d.ts @@ -1,2 +1,2 @@ -declare const _default: (import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger>)[]; +declare const _default: (import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger>)[]; export default _default; diff --git a/lib/triggers/oauthApps.js b/lib/triggers/oauthApps.js index c22a5e2b4..87da68973 100644 --- a/lib/triggers/oauthApps.js +++ b/lib/triggers/oauthApps.js @@ -13,8 +13,7 @@ const triggers = [ fn: async ({ operation }, context) => { (0, assert_1.default)(operation.data && !Array.isArray(operation.data), "oauthApplication create data 必须存在且为单条记录"); const { data } = operation; - const systemId = context.getSystemId(); - data.systemId = systemId; + (0, assert_1.default)(data.systemId, "oauthApplication 创建时必须指定 systemId"); data.clientSecret = (0, crypto_1.randomUUID)(); // 默认不强制 PKCE data.requirePKCE = data.requirePKCE ?? false; diff --git a/lib/triggers/oauthProvider.js b/lib/triggers/oauthProvider.js index d14478156..7287f7040 100644 --- a/lib/triggers/oauthProvider.js +++ b/lib/triggers/oauthProvider.js @@ -11,8 +11,7 @@ const triggers = [ fn: async ({ operation }, context) => { (0, assert_1.default)(operation.data && !Array.isArray(operation.data), "oauthProvider create data 必须存在且为单条记录"); const { data } = operation; - const systemId = context.getSystemId(); - data.systemId = systemId; + (0, assert_1.default)(data.systemId, "oauthProvider 创建时必须指定 systemId"); return 0; } }, diff --git a/src/components/login/oauth/authorize/index.ts b/src/components/login/oauth/authorize/index.ts index d380d3097..62b068c8f 100644 --- a/src/components/login/oauth/authorize/index.ts +++ b/src/components/login/oauth/authorize/index.ts @@ -1,11 +1,23 @@ import { EntityDict } from '../../../../oak-app-domain'; import assert from "assert"; +import { ReactComponentProps } from 'oak-frontend-base'; +import { EntityDict as BaseEntityDict } from 'oak-domain/lib/base-app-domain'; +/** + * OAuth 授权页面组件 + */ export default OakComponent({ // Virtual Component isList: false, filters: [], properties: { + onUnLogin: null as ((params: { + response_type: string; + client_id: string; + redirect_uri: string; + scope: string; + state: string; + }) => void) | null, }, data: { clientInfo: null as EntityDict['oauthApplication']['Schema'] | null, @@ -44,21 +56,34 @@ export default OakComponent({ const userId = this.features.token.getUserId(true); if (!userId) { - const params = new URLSearchParams(); - params.set('response_type', responseType || ""); - params.set('client_id', clientId || ""); - params.set('redirect_uri', redirectUri || ""); - params.set('scope', scope || ""); - params.set('state', state || ""); + // const params = new URLSearchParams(); + // params.set('response_type', responseType || ""); + // params.set('client_id', clientId || ""); + // params.set('redirect_uri', redirectUri || ""); + // params.set('scope', scope || ""); + // params.set('state', state || ""); - const redirectUrl = `/login/oauth/authorize?${params.toString()}`; + // const redirectUrl = `/login/oauth/authorize?${params.toString()}`; - console.log('Not logged in, redirecting to login page:', redirectUrl); - const encoded = btoa(encodeURIComponent(redirectUrl)); + // console.log('Not logged in, redirecting to login page:', redirectUrl); + // const encoded = btoa(encodeURIComponent(redirectUrl)); - this.features.navigator.navigateTo({ - url: `/login?redirect=${encoded}`, - }, undefined, true); + // this.features.navigator.navigateTo({ + // url: `/login?redirect=${encoded}`, + // }, undefined, true); + + if (!this.props.onUnLogin) { + console.error('用户未登录,请在使用Oauth授权组件时配置onUnLogin回调函数'); + return; + } + + this.props.onUnLogin({ + response_type: responseType, + client_id: clientId, + redirect_uri: redirectUri, + scope: scope, + state: state, + }); return; } @@ -166,4 +191,22 @@ export default OakComponent({ }); } }, -}); +}) as ( + props: ReactComponentProps< + ED2, + T2, + true, + { + /** + * 如果用户未登录,调用此回调函数,期望下一次重新进入该页面时,用户已经登录,并且携带相应的 OAuth 参数 + */ + onUnLogin: (params: { + response_type: string; + client_id: string; + redirect_uri: string; + scope: string; + state: string; + }) => void; + } + > +) => React.ReactElement; diff --git a/src/components/oauth/index.ts b/src/components/oauth/index.ts index 24d3dfc86..92039ca47 100644 --- a/src/components/oauth/index.ts +++ b/src/components/oauth/index.ts @@ -1,10 +1,16 @@ import assert from "assert"; +import { EntityDict } from "../../oak-app-domain"; +import { EntityDict as BaseEntityDict } from "oak-domain/lib/base-app-domain"; +import { ReactComponentProps } from "oak-frontend-base"; export default OakComponent({ // Virtual Component isList: false, filters: [], - properties: {}, + properties: { + onRetry: null as (() => void) | null, + onSuccess: null as (() => void) | null, + }, data: { hasError: false, errorMessage: '', @@ -58,14 +64,28 @@ export default OakComponent({ this.setState({ hasError: true, errorMessage: message }); }, retry() { - this.features.navigator.redirectTo({ - url: '/login', - }); + if (!this.props.onRetry) { + console.error('未设置失败重试回调函数,请在使用Oauth组件时配置onRetry属性'); + return; + } + this.props.onRetry(); }, returnToIndex() { - this.features.navigator.redirectTo({ - url: '/', - }); + if (!this.props.onSuccess) { + console.error('未设置成功回调函数,请在使用Oauth组件时配置onSuccess属性'); + return; + } + this.props.onSuccess(); } } -}); +}) as ( + props: ReactComponentProps< + ED2, + T2, + true, + { + onRetry: () => void; + onSuccess: () => void; + } + > +) => React.ReactElement; diff --git a/src/triggers/oauthApps.ts b/src/triggers/oauthApps.ts index ea75d8328..52b913ebf 100644 --- a/src/triggers/oauthApps.ts +++ b/src/triggers/oauthApps.ts @@ -15,9 +15,9 @@ const triggers: Trigger>[] = [ fn: async ({ operation }, context) => { assert(operation.data && !Array.isArray(operation.data), "oauthApplication create data 必须存在且为单条记录") const { data } = operation; - const systemId = context.getSystemId(); - data.systemId = systemId; + assert(data.systemId, "oauthApplication 创建时必须指定 systemId"); + data.clientSecret = randomUUID(); // 默认不强制 PKCE diff --git a/src/triggers/oauthProvider.ts b/src/triggers/oauthProvider.ts index e92e7d0eb..a44ea64be 100644 --- a/src/triggers/oauthProvider.ts +++ b/src/triggers/oauthProvider.ts @@ -13,9 +13,7 @@ const triggers: Trigger>[] = [ fn: async ({ operation }, context) => { assert(operation.data && !Array.isArray(operation.data), "oauthProvider create data 必须存在且为单条记录") const { data } = operation; - const systemId = context.getSystemId(); - - data.systemId = systemId; + assert(data.systemId, "oauthProvider 创建时必须指定 systemId"); return 0; }