From 53c88ad5afe66a3f7c38b9b759747918913a4edc Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Sat, 29 Nov 2025 03:25:21 +0800 Subject: [PATCH] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E5=A4=A9=E7=BF=BC?= =?UTF-8?q?=E4=BA=91cdn=20=E7=AD=89=E5=BE=855=E7=A7=92=E9=83=A8=E7=BD=B2?= =?UTF-8?q?=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/core/basic/src/utils/util.lock.ts | 2 +- .../plugin-lib/src/tencent/lib/ssl-client.ts | 34 ++++------ .../src/locales/langs/zh-CN/certd.ts | 14 ++-- .../certd-client/src/views/certd/mine/api.ts | 33 ++++++++++ .../src/views/certd/mine/user-profile.vue | 64 ++++++++++++++++-- .../src/views/framework/login/index.vue | 4 +- .../src/views/framework/oauth/api.ts | 3 +- .../views/framework/oauth/oauth-callback.vue | 34 +++++++--- .../basic/login/oauth-controller.ts | 65 ++++++++++++------- .../login/service/oauth-bound-service.ts | 7 +- .../src/plugins/plugin-oauth/api.ts | 2 +- .../plugins/plugin-oauth/oidc/plugin-oidc.ts | 14 ++-- .../plugin/refresh-cert/index.ts | 19 ++++-- 13 files changed, 211 insertions(+), 84 deletions(-) diff --git a/packages/core/basic/src/utils/util.lock.ts b/packages/core/basic/src/utils/util.lock.ts index b63bf0427..42783c474 100644 --- a/packages/core/basic/src/utils/util.lock.ts +++ b/packages/core/basic/src/utils/util.lock.ts @@ -9,7 +9,7 @@ export class Locker { } async execute(lockStr: string, callback: any, options?: { timeout?: number }) { - const timeout = options?.timeout ?? 20000; + const timeout = options?.timeout ?? 120000; return this.asyncLocker.acquire(lockStr, callback, { timeout }); } } diff --git a/packages/plugins/plugin-lib/src/tencent/lib/ssl-client.ts b/packages/plugins/plugin-lib/src/tencent/lib/ssl-client.ts index 2075d4705..dada84408 100644 --- a/packages/plugins/plugin-lib/src/tencent/lib/ssl-client.ts +++ b/packages/plugins/plugin-lib/src/tencent/lib/ssl-client.ts @@ -36,7 +36,7 @@ export class TencentSslClient { checkRet(ret: any) { if (!ret || ret.Error) { - throw new Error("请求失败:" + ret.Error.Code + "," + ret.Error.Message); + throw new Error("请求失败:" + ret.Error.Code + "," + ret.Error.Message + ",requestId" + ret.RequestId); } } @@ -70,43 +70,33 @@ export class TencentSslClient { } async deployCertificateInstance(params: any) { - const client = await this.getSslClient(); - const res = await client.DeployCertificateInstance(params); - this.checkRet(res); - return res; + return await this.doRequest("DeployCertificateInstance", params); } async DescribeHostUploadUpdateRecordDetail(params: any) { - const client = await this.getSslClient(); - const res = await client.request("DescribeHostUploadUpdateRecordDetail", params); - this.checkRet(res); - return res; + return await this.doRequest("DescribeHostUploadUpdateRecordDetail", params); } async UploadUpdateCertificateInstance(params: any) { - const client = await this.getSslClient(); - const res = await client.request("UploadUpdateCertificateInstance", params); - this.checkRet(res); - return res; + return await this.doRequest("UploadUpdateCertificateInstance", params); } async DescribeCertificates(params: { Limit?: number; Offset?: number; SearchKey?: string }) { - const client = await this.getSslClient(); - const res = await client.DescribeCertificates({ + return await this.doRequest("DescribeCertificates", { ExpirationSort: "ASC", ...params, }); - this.checkRet(res); - return res; } async doRequest(action: string, params: any) { const client = await this.getSslClient(); - if (!client[action]) { - throw new Error(`action ${action} not found`); + try { + const res = await client.request(action, params); + this.checkRet(res); + return res; + } catch (e) { + this.logger.error(`action ${action} error: ${e.message},requestId=${e.RequestId}`); + throw e; } - const res = await client[action](params); - this.checkRet(res); - return res; } } diff --git a/packages/ui/certd-client/src/locales/langs/zh-CN/certd.ts b/packages/ui/certd-client/src/locales/langs/zh-CN/certd.ts index 220fbb7cb..ae7a70a76 100644 --- a/packages/ui/certd-client/src/locales/langs/zh-CN/certd.ts +++ b/packages/ui/certd-client/src/locales/langs/zh-CN/certd.ts @@ -604,7 +604,7 @@ export default { limitUserPipelineCountHelper: "0为不限制", enableSelfRegistration: "开启自助注册", enableUserValidityPeriod: "开启用户有效期", - userValidityPeriodHelper: "有效期内用户可正常使用,失效后流水线将被停用", + userValidityPeriodHelper: "有效期内用户可正常使用,失效后用户的流水线将被停用", enableUsernameRegistration: "开启用户名注册", enableEmailRegistration: "开启邮箱注册", proFeature: "专业版功能", @@ -762,12 +762,12 @@ export default { fixedCertExpireDaysHelper: "固定证书有效期天数,有助于列表进度条整齐显示", fixedCertExpireDaysRecommend: "推荐90", - enableOauth: "启用OAuth2登录", - oauthEnabledHelper: "是否启用OAuth2登录", - oauthProviders: "OAuth2登录提供商", - oauthType: "OAuth2登录类型", - oauthConfig: "OAuth2登录配置", - oauthProviderSelectorPlaceholder: "请选择OAuth2登录提供商", + enableOauth: "启用第三方登录", + oauthEnabledHelper: "是否启用第三方登录", + oauthProviders: "第三方登录提供商", + oauthType: "第三方登录类型", + oauthConfig: "第三方登录配置", + oauthProviderSelectorPlaceholder: "请选择第三方登录提供商", }, }, modal: { diff --git a/packages/ui/certd-client/src/views/certd/mine/api.ts b/packages/ui/certd-client/src/views/certd/mine/api.ts index aa996cf53..641638a28 100644 --- a/packages/ui/certd-client/src/views/certd/mine/api.ts +++ b/packages/ui/certd-client/src/views/certd/mine/api.ts @@ -22,3 +22,36 @@ export async function UpdateProfile(form: any) { data: form, }); } + +export async function GetOauthBounds() { + return await request({ + url: "/oauth/bounds", + method: "POST", + }); +} + +export async function GetOauthProviders() { + return await request({ + url: "/oauth/providers", + method: "POST", + }); +} + +export async function UnbindOauth(type: string) { + return await request({ + url: "/oauth/unbind", + method: "POST", + data: { type }, + }); +} + +export async function OauthBoundUrl(type: string) { + return await request({ + url: "/oauth/login", + method: "POST", + data: { + type, + forType: "bind", + }, + }); +} diff --git a/packages/ui/certd-client/src/views/certd/mine/user-profile.vue b/packages/ui/certd-client/src/views/certd/mine/user-profile.vue index 48b331971..5f00852c7 100644 --- a/packages/ui/certd-client/src/views/certd/mine/user-profile.vue +++ b/packages/ui/certd-client/src/views/certd/mine/user-profile.vue @@ -15,7 +15,14 @@ {{ userInfo.email }} {{ userInfo.phoneCode }}{{ userInfo.mobile }} - + +
+ + {{ item.title }} + 解绑 + 绑定 +
+
{{ t("authentication.updateProfile") }} @@ -27,10 +34,12 @@ diff --git a/packages/ui/certd-client/src/views/framework/login/index.vue b/packages/ui/certd-client/src/views/framework/login/index.vue index 999ba2e1d..c513ea5b8 100644 --- a/packages/ui/certd-client/src/views/framework/login/index.vue +++ b/packages/ui/certd-client/src/views/framework/login/index.vue @@ -65,7 +65,7 @@ -
+
@@ -82,7 +82,7 @@ -
-
-
第三方登录成功,还未绑定账号,请选择
+
+
第三方({{ oauthType }})登录成功,您还未绑定账号,请选择
-
- 绑定已有账号 - 创建新账号 +
+ 绑定已有账号 + 创建新账号
-
- 返回登录页 +
+ 返回登录页
@@ -26,11 +26,13 @@ import { ref, onMounted } from "vue"; import * as api from "./api"; import { useRoute, useRouter } from "vue-router"; import { useUserStore } from "/@/store/user"; +import { notification } from "ant-design-vue"; const route = useRoute(); const router = useRouter(); const oauthType = route.params.type as string; const validationCode = route.query.validationCode as string; +const forType = route.query.forType as string; const error = ref(route.query.error as string); const userStore = useUserStore(); @@ -58,6 +60,18 @@ onMounted(async () => { if (error.value) { return; } + + if (forType === "bind") { + //绑定第三方账号 + await api.BindUser(validationCode); + notification.success({ + message: "绑定成功", + }); + //跳转到首页 + router.replace("/certd/mine/user-profile"); + return; + } + await handleOauthToken(); }); @@ -86,7 +100,7 @@ async function autoRegister() { justify-content: center; align-items: center; gap: 16px; - + width: 100%; .oauth-callback-content { display: flex; justify-content: center; @@ -96,12 +110,14 @@ async function autoRegister() { border-radius: 16px; box-shadow: 0 0 16px rgba(0, 0, 0, 0.1); width: 500px; + max-width: 90%; margin: 0 auto; margin-top: 50px; margin-bottom: 100px; + min-height: 200px; .oauth-callback-title { - font-size: 24px; + font-size: 16px; font-weight: 500; } } diff --git a/packages/ui/certd-server/src/controller/basic/login/oauth-controller.ts b/packages/ui/certd-server/src/controller/basic/login/oauth-controller.ts index 708c732a7..ca938d8ed 100644 --- a/packages/ui/certd-server/src/controller/basic/login/oauth-controller.ts +++ b/packages/ui/certd-server/src/controller/basic/login/oauth-controller.ts @@ -6,9 +6,10 @@ import { LoginService } from "../../../modules/login/service/login-service.js"; import { CodeService } from "../../../modules/basic/service/code-service.js"; import { UserService } from "../../../modules/sys/authority/service/user-service.js"; import { UserEntity } from "../../../modules/sys/authority/entity/user.js"; -import { logger, simpleNanoId } from "@certd/basic"; +import { logger, simpleNanoId, utils } from "@certd/basic"; import { OauthBoundService } from "../../../modules/login/service/oauth-bound-service.js"; import { OauthBoundEntity } from "../../../modules/login/entity/oauth-bound.js"; +import { checkPlus } from "@certd/plus-core"; /** */ @@ -50,14 +51,14 @@ export class ConnectController extends BaseController { } @Post('/login', { summary: Constants.per.guest }) - public async login(@Body(ALL) body: { type: string }) { + public async login(@Body(ALL) body: { type: string, forType?:string }) { const addon = await this.getOauthProvider(body.type); const installInfo = await this.sysSettingsService.getSetting(SysInstallInfo); const bindUrl = installInfo?.bindUrl || ""; //构造登录url const redirectUrl = `${bindUrl}api/oauth/callback/${body.type}`; - const { loginUrl, ticketValue } = await addon.buildLoginUrl({ redirectUri: redirectUrl }); + const { loginUrl, ticketValue } = await addon.buildLoginUrl({ redirectUri: redirectUrl, forType: body.forType }); const ticket = this.codeService.setValidationValue(ticketValue) this.ctx.cookies.set("oauth_ticket", ticket, { httpOnly: true, @@ -68,6 +69,9 @@ export class ConnectController extends BaseController { } @Get('/callback/:type', { summary: Constants.per.guest }) public async callback(@Param('type') type: string, @Query() query: Record) { + + checkPlus() + //处理登录回调 const addon = await this.getOauthProvider(type); const request = this.ctx.request; @@ -103,7 +107,9 @@ export class ConnectController extends BaseController { userInfo, }); - const redirectUrl = `${bindUrl}#/oauth/callback/${type}?validationCode=${validationCode}`; + const state = JSON.parse(utils.hash.base64Decode(query.state)); + + const redirectUrl = `${bindUrl}#/oauth/callback/${type}?validationCode=${validationCode}&forType=${state.forType}`; this.ctx.redirect(redirectUrl); } catch (err) { logger.error(err); @@ -115,6 +121,7 @@ export class ConnectController extends BaseController { @Post('/token', { summary: Constants.per.guest }) public async token(@Body(ALL) body: { validationCode: string, type: string }) { + checkPlus() const validationValue = await this.codeService.getValidationValue(body.validationCode); if (!validationValue) { throw new Error("校验码错误"); @@ -140,24 +147,6 @@ export class ConnectController extends BaseController { return this.ok(loginRes); } - @Post('/bind', { summary: Constants.per.loginOnly }) - public async bind(@Body(ALL) body: any) { - //需要已登录 - const userId = this.getUserId(); - const validationValue = this.codeService.getValidationValue(body.validationCode); - if (!validationValue) { - throw new Error("校验码错误"); - } - const type = validationValue.type; - const userInfo = validationValue.userInfo; - const openId = userInfo.openId; - await this.oauthBoundService.bind({ - userId, - type, - openId, - }); - return this.ok(1); - } @Post('/autoRegister', { summary: Constants.per.guest }) public async autoRegister(@Body(ALL) body: { validationCode: string, type: string }) { @@ -185,6 +174,26 @@ export class ConnectController extends BaseController { return this.ok(loginRes); } + + @Post('/bind', { summary: Constants.per.loginOnly }) + public async bind(@Body(ALL) body: any) { + //需要已登录 + const userId = this.getUserId(); + const validationValue = this.codeService.getValidationValue(body.validationCode); + if (!validationValue) { + throw new Error("校验码错误"); + } + const type = validationValue.type; + const userInfo = validationValue.userInfo; + const openId = userInfo.openId; + await this.oauthBoundService.bind({ + userId, + type, + openId, + }); + return this.ok(1); + } + @Post('/unbind', { summary: Constants.per.loginOnly }) public async unbind(@Body(ALL) body: any) { //需要已登录 @@ -196,6 +205,18 @@ export class ConnectController extends BaseController { return this.ok(1); } + @Post('/bounds', { summary: Constants.per.loginOnly }) + public async bounds(@Body(ALL) body: any) { + //需要已登录 + const userId = this.getUserId(); + const bounds = await this.oauthBoundService.find({ + where :{ + userId, + } + }); + return this.ok(bounds); + } + @Post('/providers', { summary: Constants.per.guest }) public async providers() { const list = addonRegistry.getDefineList("oauth"); diff --git a/packages/ui/certd-server/src/modules/login/service/oauth-bound-service.ts b/packages/ui/certd-server/src/modules/login/service/oauth-bound-service.ts index aa32cac3d..e7c29be9d 100644 --- a/packages/ui/certd-server/src/modules/login/service/oauth-bound-service.ts +++ b/packages/ui/certd-server/src/modules/login/service/oauth-bound-service.ts @@ -44,8 +44,11 @@ export class OauthBoundService extends BaseService { type, }, }); - if (exist) { - throw new Error('该第三方账号已绑定用户'); + if (exist ) { + if(exist.userId === userId){ + return; + } + throw new Error('该第三方账号已绑定其他用户'); } const exist2 = await this.repository.findOne({ diff --git a/packages/ui/certd-server/src/plugins/plugin-oauth/api.ts b/packages/ui/certd-server/src/plugins/plugin-oauth/api.ts index 93609b39e..4c1d16f29 100644 --- a/packages/ui/certd-server/src/plugins/plugin-oauth/api.ts +++ b/packages/ui/certd-server/src/plugins/plugin-oauth/api.ts @@ -38,6 +38,6 @@ export type LoginUrlReply = { } export interface IOauthProvider { - buildLoginUrl: (params: { redirectUri: string }) => Promise; + buildLoginUrl: (params: { redirectUri: string, forType?: string }) => Promise; onCallback: (params: OnCallbackReq) => Promise; } \ No newline at end of file diff --git a/packages/ui/certd-server/src/plugins/plugin-oauth/oidc/plugin-oidc.ts b/packages/ui/certd-server/src/plugins/plugin-oauth/oidc/plugin-oidc.ts index d4849b075..749861491 100644 --- a/packages/ui/certd-server/src/plugins/plugin-oauth/oidc/plugin-oidc.ts +++ b/packages/ui/certd-server/src/plugins/plugin-oauth/oidc/plugin-oidc.ts @@ -29,7 +29,7 @@ export class OidcOauthProvider extends BaseAddon implements IOauthProvider { @AddonInput({ title: "服务地址", - helper: "Issuer地址", + helper: "Issuer地址,去掉/.well-known/openid-configuration的服务发现地址", component: { placeholder: "https://oidc.example.com/oidc", }, @@ -56,7 +56,7 @@ export class OidcOauthProvider extends BaseAddon implements IOauthProvider { } } - async buildLoginUrl(params: { redirectUri: string }) { + async buildLoginUrl(params: { redirectUri: string, forType?: string }) { const { config, client } = await this.getClient() let redirect_uri = new URL(params.redirectUri) @@ -69,7 +69,10 @@ export class OidcOauthProvider extends BaseAddon implements IOauthProvider { */ let code_verifier = client.randomPKCECodeVerifier() let code_challenge = await client.calculatePKCECodeChallenge(code_verifier) - let state = client.randomState() + let state:any = { + forType: params.forType || 'login', + } + state = this.ctx.utils.hash.base64(JSON.stringify(state)) let parameters: any = { redirect_uri, @@ -90,13 +93,11 @@ export class OidcOauthProvider extends BaseAddon implements IOauthProvider { // } let redirectTo = client.buildAuthorizationUrl(config, parameters) - - // now redirect the user to redirectTo.href - console.log('redirecting to', redirectTo.href) return { loginUrl: redirectTo.href, ticketValue: { codeVerifier: code_verifier, + state, }, }; } @@ -114,7 +115,6 @@ export class OidcOauthProvider extends BaseAddon implements IOauthProvider { } ) - console.log('Token Endpoint Response', tokens) const claims = tokens.claims() return { token:{ diff --git a/packages/ui/certd-server/src/plugins/plugin-tencent/plugin/refresh-cert/index.ts b/packages/ui/certd-server/src/plugins/plugin-tencent/plugin/refresh-cert/index.ts index 445fd4488..eee016781 100644 --- a/packages/ui/certd-server/src/plugins/plugin-tencent/plugin/refresh-cert/index.ts +++ b/packages/ui/certd-server/src/plugins/plugin-tencent/plugin/refresh-cert/index.ts @@ -124,6 +124,9 @@ export class TencentRefreshCert extends AbstractTaskPlugin { let resourceTypes = [] const resourceTypesRegions = [] + if(!this.resourceTypesRegions){ + this.resourceTypesRegions = [] + } for (const item of this.resourceTypesRegions) { const [type,region] = item.split("_") if (!resourceTypes.includes( type)){ @@ -156,13 +159,17 @@ export class TencentRefreshCert extends AbstractTaskPlugin { break; } retryCount++ - deployRes = await sslClient.UploadUpdateCertificateInstance({ - OldCertificateId: certId, + const params = { + "OldCertificateId": certId, "ResourceTypes": resourceTypes, - "CertificatePublicKey": this.cert.crt, - "CertificatePrivateKey": this.cert.key, + "CertificatePublicKey": "xxx", + "CertificatePrivateKey": "xxx", "ResourceTypesRegions":resourceTypesRegions - }); + } + this.logger.info(`请求参数:${JSON.stringify(params)}`); + params.CertificatePublicKey = this.cert.crt + params.CertificatePrivateKey = this.cert.key + deployRes = await sslClient.UploadUpdateCertificateInstance(params); if (deployRes && deployRes.DeployRecordId>0){ this.logger.info(`任务创建成功,开始检查结果:${JSON.stringify(deployRes)}`); break; @@ -325,7 +332,7 @@ export class TencentRefreshCert extends AbstractTaskPlugin { */ const options = list.map((item: any) => { return { - label: `${item.Alias}<${item.Domain}_${item.CertificateId}>`, + label: `${item.CertificateId}<${item.Domain}_${item.Alias}_${item.BoundResource.length}>`, value: item.CertificateId, domain: item.SubjectAltName, };