mirror of
https://github.com/certd/certd.git
synced 2026-04-24 04:17:25 +08:00
perf: 第三方登录支持Microsoft
This commit is contained in:
@@ -147,7 +147,7 @@ export class AcmeService {
|
|||||||
externalAccountBinding: this.eab,
|
externalAccountBinding: this.eab,
|
||||||
backoffAttempts: this.options.maxCheckRetryCount || 20,
|
backoffAttempts: this.options.maxCheckRetryCount || 20,
|
||||||
backoffMin: 5000,
|
backoffMin: 5000,
|
||||||
backoffMax: 400000,
|
backoffMax: 1000*1000,
|
||||||
urlMapping,
|
urlMapping,
|
||||||
signal: this.options.signal,
|
signal: this.options.signal,
|
||||||
logger: this.logger,
|
logger: this.logger,
|
||||||
|
|||||||
@@ -4,4 +4,5 @@ export * from './wx/plugin-wx.js'
|
|||||||
export * from './oauth2/plugin-gitee.js'
|
export * from './oauth2/plugin-gitee.js'
|
||||||
export * from './oauth2/plugin-clogin.js'
|
export * from './oauth2/plugin-clogin.js'
|
||||||
export * from './oauth2/plugin-github.js'
|
export * from './oauth2/plugin-github.js'
|
||||||
export * from './oauth2/plugin-google.js'
|
export * from './oauth2/plugin-google.js'
|
||||||
|
export * from './oauth2/plugin-microsoft.js'
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
import { AddonInput, BaseAddon, IsAddon } from "@certd/lib-server";
|
||||||
|
import { BuildLoginUrlReq, BuildLogoutUrlReq, IOauthProvider, OnCallbackReq } from "../api.js";
|
||||||
|
|
||||||
|
@IsAddon({
|
||||||
|
addonType: "oauth",
|
||||||
|
name: 'microsoft',
|
||||||
|
title: 'Microsoft认证',
|
||||||
|
desc: 'Microsoft OAuth2登录',
|
||||||
|
icon:"simple-icons:microsoft",
|
||||||
|
showTest: false,
|
||||||
|
})
|
||||||
|
export class MicrosoftOauthProvider extends BaseAddon implements IOauthProvider {
|
||||||
|
|
||||||
|
@AddonInput({
|
||||||
|
title: "ClientId",
|
||||||
|
helper: "[Azure Portal](https://portal.azure.com/)创建应用后获取",
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
clientId = "";
|
||||||
|
|
||||||
|
@AddonInput({
|
||||||
|
title: "ClientSecretKey",
|
||||||
|
component: {
|
||||||
|
placeholder: "ClientSecretKey / appSecretKey",
|
||||||
|
},
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
clientSecretKey = "";
|
||||||
|
|
||||||
|
@AddonInput({
|
||||||
|
title: "TenantId",
|
||||||
|
helper: "租户ID,留空使用/common端点(需要应用配置为多租户)",
|
||||||
|
component: {
|
||||||
|
placeholder: "common 或 租户ID",
|
||||||
|
},
|
||||||
|
value: "common",
|
||||||
|
required: false,
|
||||||
|
})
|
||||||
|
tenantId = "common";
|
||||||
|
|
||||||
|
async buildLoginUrl(params: BuildLoginUrlReq) {
|
||||||
|
|
||||||
|
let scope = "openid profile email User.Read" // Scope of the access request
|
||||||
|
let state:any = {
|
||||||
|
forType: params.forType || 'login',
|
||||||
|
}
|
||||||
|
state = this.ctx.utils.hash.base64(JSON.stringify(state))
|
||||||
|
|
||||||
|
const authorizeEndpoint = `https://login.microsoftonline.com/${this.tenantId}/oauth2/v2.0/authorize`
|
||||||
|
const redirectUrl = encodeURIComponent(params.redirectUri)
|
||||||
|
const loginUrl = `${authorizeEndpoint}?client_id=${this.clientId}&redirect_uri=${redirectUrl}&response_type=code&scope=${scope}&state=${state}`
|
||||||
|
return {
|
||||||
|
loginUrl,
|
||||||
|
ticketValue: {
|
||||||
|
state,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async onCallback(req: OnCallbackReq) {
|
||||||
|
|
||||||
|
const code = req.code || ""
|
||||||
|
if (!code) {
|
||||||
|
throw new Error("Missing code parameter");
|
||||||
|
}
|
||||||
|
|
||||||
|
const tokenEndpoint = `https://login.microsoftonline.com/${this.tenantId}/oauth2/v2.0/token`
|
||||||
|
|
||||||
|
const uri = new URL(req.currentURL)
|
||||||
|
const redirectUri = `${uri.origin}${uri.pathname}`
|
||||||
|
|
||||||
|
// 构建 form-urlencoded 格式的数据
|
||||||
|
const formData = new URLSearchParams();
|
||||||
|
formData.append('client_id', this.clientId);
|
||||||
|
formData.append('client_secret', this.clientSecretKey);
|
||||||
|
formData.append('code', code);
|
||||||
|
formData.append('redirect_uri', redirectUri);
|
||||||
|
formData.append('grant_type', 'authorization_code');
|
||||||
|
|
||||||
|
const res = await this.ctx.utils.http.request( {
|
||||||
|
url: tokenEndpoint,
|
||||||
|
method: "post",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/x-www-form-urlencoded",
|
||||||
|
"Accept": "application/json"
|
||||||
|
},
|
||||||
|
data: formData.toString()
|
||||||
|
})
|
||||||
|
|
||||||
|
const tokens = res
|
||||||
|
|
||||||
|
const userInfoEndpoint = "https://graph.microsoft.com/v1.0/me"
|
||||||
|
|
||||||
|
// 获取用户信息
|
||||||
|
const userInfoRes = await this.ctx.utils.http.request( {
|
||||||
|
url: userInfoEndpoint,
|
||||||
|
method: "get",
|
||||||
|
headers: {
|
||||||
|
"Authorization": `Bearer ${tokens.access_token}`,
|
||||||
|
"Accept": "application/json"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const userInfo = userInfoRes
|
||||||
|
|
||||||
|
return {
|
||||||
|
token:{
|
||||||
|
accessToken: tokens.access_token,
|
||||||
|
refreshToken: tokens.refresh_token,
|
||||||
|
expiresIn: tokens.expires_in,
|
||||||
|
},
|
||||||
|
userInfo: {
|
||||||
|
openId: userInfo.id,
|
||||||
|
nickName: userInfo.displayName || userInfo.userPrincipalName || "",
|
||||||
|
avatar: userInfo.avatar || "",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
async buildLogoutUrl(params: BuildLogoutUrlReq) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user