chore: format

This commit is contained in:
xiaojunnuo
2026-05-31 01:41:33 +08:00
parent acd440106b
commit 4b57a0d729
557 changed files with 12530 additions and 14039 deletions
@@ -1,60 +1,60 @@
export type OnCallbackReq = {
code: string;
state: string;
currentURL: URL;
ticketValue: any;
}
code: string;
state: string;
currentURL: URL;
ticketValue: any;
};
export type OauthToken = {
userInfo: {
openId: string;
nickName: string;
avatar: string;
},
token: {
accessToken: string;
refreshToken: string;
expiresIn: number;
}
}
export type OnBindReq = {
userInfo: {
openId: string;
nickName: string;
avatar: string;
};
token: {
accessToken: string;
refreshToken: string;
expiresIn: number;
idToken: string;
scope: string;
tokenType: string;
bindInfo: any;
}
};
};
export type OnBindReq = {
accessToken: string;
refreshToken: string;
expiresIn: number;
idToken: string;
scope: string;
tokenType: string;
bindInfo: any;
};
export type OnBindReply = {
success: boolean;
message: string;
}
success: boolean;
message: string;
};
export type LoginUrlReply = {
loginUrl: string;
ticketValue: any;
}
loginUrl: string;
ticketValue: any;
};
export type BuildLoginUrlReq = {
redirectUri: string;
forType?: string;
from?:string;
subtype?: string;
state?: string;
}
redirectUri: string;
forType?: string;
from?: string;
subtype?: string;
state?: string;
};
export type BuildLogoutUrlReq = {
subtype?: string;
}
subtype?: string;
};
export type LogoutUrlReply = {
logoutUrl?: string;
}
logoutUrl?: string;
};
export interface IOauthProvider {
buildLoginUrl: (params: BuildLoginUrlReq) => Promise<LoginUrlReply>;
onCallback: (params: OnCallbackReq) => Promise<OauthToken>;
buildLogoutUrl: (params: BuildLogoutUrlReq) => Promise<LogoutUrlReply>;
buildLoginUrl: (params: BuildLoginUrlReq) => Promise<LoginUrlReply>;
onCallback: (params: OnCallbackReq) => Promise<OauthToken>;
buildLogoutUrl: (params: BuildLogoutUrlReq) => Promise<LogoutUrlReply>;
}
@@ -1,13 +1 @@
export const IconSets = [
"streamline-logos",
"logos",
"fa-brands",
"fa-solid",
"fa-regular",
"carbon",
"ion",
"ant-design",
"mdi",
"twemoji",
"svg-spinners"
]
export const IconSets = ["streamline-logos", "logos", "fa-brands", "fa-solid", "fa-regular", "carbon", "ion", "ant-design", "mdi", "twemoji", "svg-spinners"];
@@ -1,8 +1,8 @@
export * from './api.js'
export * from './oidc/plugin-oidc.js'
export * from './wx/plugin-wx.js'
export * from './oauth2/plugin-gitee.js'
export * from './oauth2/plugin-clogin.js'
export * from './oauth2/plugin-github.js'
export * from './oauth2/plugin-google.js'
export * from './oauth2/plugin-microsoft.js'
export * from "./api.js";
export * from "./oidc/plugin-oidc.js";
export * from "./wx/plugin-wx.js";
export * from "./oauth2/plugin-gitee.js";
export * from "./oauth2/plugin-clogin.js";
export * from "./oauth2/plugin-github.js";
export * from "./oauth2/plugin-google.js";
export * from "./oauth2/plugin-microsoft.js";
@@ -29,9 +29,9 @@ function getCloginType(subtype?: string, loginType?: string | string[]) {
@IsAddon({
addonType: "oauth",
name: 'clogin',
title: '彩虹聚合登录',
desc: '彩虹聚合登录',
name: "clogin",
title: "彩虹聚合登录",
desc: "彩虹聚合登录",
icon: "emojione:rainbow",
showTest: false,
})
@@ -40,7 +40,7 @@ export class CloginOauthProvider extends BaseAddon implements IOauthProvider {
title: "系统地址",
helper: "http://clogin.xxxx.com/",
required: true,
col:{span:24},
col: { span: 24 },
})
endpoint = "";
@@ -85,19 +85,17 @@ export class CloginOauthProvider extends BaseAddon implements IOauthProvider {
})
appKey = "";
async buildLoginUrl(params: BuildLoginUrlReq) {
let redirectUri = params.redirectUri || ""
const redirectUri = params.redirectUri || "";
const loginType = getCloginType(params.subtype, this.loginType);
// if(redirectUri.indexOf("localhost:3008")>=0){
// redirectUri = redirectUri.replace("localhost:3008", "certd.handfree.work")
// }
const res = await this.ctx.http.request({
url: `${this.endpoint}/connect.php?act=login&appid=${this.appId}&appkey=${this.appKey}&type=${loginType}&redirect_uri=${redirectUri}&state=${params.state}`
})
url: `${this.endpoint}/connect.php?act=login&appid=${this.appId}&appkey=${this.appKey}&type=${loginType}&redirect_uri=${redirectUri}&state=${params.state}`,
});
this.checkRes(res)
this.checkRes(res);
return {
loginUrl: res.url,
@@ -107,23 +105,22 @@ export class CloginOauthProvider extends BaseAddon implements IOauthProvider {
checkRes(res: any) {
if (res.code !== 0) {
throw new Error(res.msg || "请求接口失败")
throw new Error(res.msg || "请求接口失败");
}
}
async onCallback(req: OnCallbackReq) {
//校验state
const code = req.code || ""
const code = req.code || "";
const loginType = getCloginType(req.ticketValue?.subtype, this.loginType);
const tokenEndpoint = `${this.endpoint}/connect.php?act=callback&appid=${this.appId}&appkey=${this.appKey}&type=${loginType}&code=${code}`
const tokenEndpoint = `${this.endpoint}/connect.php?act=callback&appid=${this.appId}&appkey=${this.appKey}&type=${loginType}&code=${code}`;
const res = await this.ctx.utils.http.request({
url: tokenEndpoint,
method: "post",
})
this.checkRes(res)
});
this.checkRes(res);
/**
* "access_token": "89DC9691E274D6B596FFCB8D43368234",
@@ -135,8 +132,7 @@ export class CloginOauthProvider extends BaseAddon implements IOauthProvider {
"ip": "1.12.3.40"
*/
const { access_token, faceimg, nickname, social_uid } = res
const { access_token, faceimg, nickname, social_uid } = res;
return {
token: {
@@ -149,8 +145,8 @@ export class CloginOauthProvider extends BaseAddon implements IOauthProvider {
nickName: nickname || "",
avatar: faceimg || "",
},
}
};
};
}
async buildLogoutUrl(params: BuildLogoutUrlReq) {
return {};
@@ -3,14 +3,13 @@ import { BuildLoginUrlReq, BuildLogoutUrlReq, IOauthProvider, OnCallbackReq } fr
@IsAddon({
addonType: "oauth",
name: 'gitee',
title: 'Gitee认证',
desc: 'Gitee OAuth2登录',
icon:"simple-icons:gitee:red",
name: "gitee",
title: "Gitee认证",
desc: "Gitee OAuth2登录",
icon: "simple-icons:gitee:red",
showTest: false,
})
export class GiteeOauthProvider extends BaseAddon implements IOauthProvider {
@AddonInput({
title: "ClientId",
helper: "[gitee 第三方应用管理](https://gitee.com/oauth/applications)创建应用后获取",
@@ -74,63 +73,57 @@ gitee.userInfo = https://gitee.com/api/v5/user
// })
// scope: string;
async buildLoginUrl(params: BuildLoginUrlReq) {
let scope = "user_info" // Scope of the access request
const authorizeEndpoint = "https://gitee.com/oauth/authorize"
const redirectUrl = encodeURIComponent(params.redirectUri)
const scope = "user_info"; // Scope of the access request
const authorizeEndpoint = "https://gitee.com/oauth/authorize";
const redirectUrl = encodeURIComponent(params.redirectUri);
// https://gitee.com/oauth/authorize?client_id=5bb5f4158af41c50c7a17b5d9068244e97d3ee572def6a57ed32fd8c9d760ad1&redirect_uri=http%3A%2F%2Fcasdoor.docmirror.cn%3A8000%2Fcallback&response_type=code
const loginUrl = `${authorizeEndpoint}?client_id=${this.clientId}&redirect_uri=${redirectUrl}&response_type=code&scope=${scope}&state=${params.state}`
const loginUrl = `${authorizeEndpoint}?client_id=${this.clientId}&redirect_uri=${redirectUrl}&response_type=code&scope=${scope}&state=${params.state}`;
return {
loginUrl,
ticketValue: {
},
ticketValue: {},
};
}
async onCallback(req: OnCallbackReq) {
//校验state
const code = req.code || ""
const code = req.code || "";
const tokenEndpoint = "https://gitee.com/oauth/token"
const tokenEndpoint = "https://gitee.com/oauth/token";
const uri = new URL(req.currentURL)
const redirectUri = `${uri.origin}${uri.pathname}`
const res = await this.ctx.utils.http.request( {
url: tokenEndpoint,
method: "post",
data:{
const uri = new URL(req.currentURL);
const redirectUri = `${uri.origin}${uri.pathname}`;
const res = await this.ctx.utils.http.request({
url: tokenEndpoint,
method: "post",
data: {
// https://gitee.com/oauth/token?
// grant_type=authorization_code&code={code}&client_id={client_id}&redirect_uri={redirect_uri}&client_secret={client_secret}
grant_type: "authorization_code",
code,
client_id: this.clientId,
redirect_uri: redirectUri,
client_secret: this.clientSecretKey,
}
})
const tokens = res
grant_type: "authorization_code",
code,
client_id: this.clientId,
redirect_uri: redirectUri,
client_secret: this.clientSecretKey,
},
});
const tokens = res;
const userInfoEndpoint = "https://gitee.com/api/v5/user"
const userInfoEndpoint = "https://gitee.com/api/v5/user";
// 获取用户信息
const userInfoRes = await this.ctx.utils.http.request( {
url: userInfoEndpoint,
method: "get",
params:{
access_token: tokens.access_token,
}
})
const userInfo = userInfoRes
const userInfoRes = await this.ctx.utils.http.request({
url: userInfoEndpoint,
method: "get",
params: {
access_token: tokens.access_token,
},
});
const userInfo = userInfoRes;
return {
token:{
token: {
accessToken: tokens.access_token,
refreshToken: tokens.refresh_token,
expiresIn: tokens.expires_in,
@@ -140,8 +133,8 @@ gitee.userInfo = https://gitee.com/api/v5/user
nickName: userInfo.name || userInfo.nick_name || "",
avatar: userInfo.avatar_url,
},
}
};
};
}
async buildLogoutUrl(params: BuildLogoutUrlReq) {
return {};
@@ -3,14 +3,13 @@ import { BuildLoginUrlReq, BuildLogoutUrlReq, IOauthProvider, OnCallbackReq } fr
@IsAddon({
addonType: "oauth",
name: 'github',
title: 'GitHub认证',
desc: 'GitHub OAuth2登录',
icon:"simple-icons:github",
name: "github",
title: "GitHub认证",
desc: "GitHub OAuth2登录",
icon: "simple-icons:github",
showTest: false,
})
export class GithubOauthProvider extends BaseAddon implements IOauthProvider {
@AddonInput({
title: "ClientId",
helper: "[GitHub Developer Settings](https://github.com/settings/developers)创建应用后获取",
@@ -28,56 +27,54 @@ export class GithubOauthProvider extends BaseAddon implements IOauthProvider {
clientSecretKey = "";
async buildLoginUrl(params: BuildLoginUrlReq) {
let scope = "user:email" // Scope of the access request
const authorizeEndpoint = "https://github.com/login/oauth/authorize"
const redirectUrl = encodeURIComponent(params.redirectUri)
const loginUrl = `${authorizeEndpoint}?client_id=${this.clientId}&redirect_uri=${redirectUrl}&response_type=code&scope=${scope}&state=${params.state}`
const scope = "user:email"; // Scope of the access request
const authorizeEndpoint = "https://github.com/login/oauth/authorize";
const redirectUrl = encodeURIComponent(params.redirectUri);
const loginUrl = `${authorizeEndpoint}?client_id=${this.clientId}&redirect_uri=${redirectUrl}&response_type=code&scope=${scope}&state=${params.state}`;
return {
loginUrl,
ticketValue: { },
ticketValue: {},
};
}
async onCallback(req: OnCallbackReq) {
const code = req.code || ""
const code = req.code || "";
const tokenEndpoint = "https://github.com/login/oauth/access_token"
const tokenEndpoint = "https://github.com/login/oauth/access_token";
const uri = new URL(req.currentURL)
const redirectUri = `${uri.origin}${uri.pathname}`
const res = await this.ctx.utils.http.request( {
url: tokenEndpoint,
method: "post",
headers: {
"Accept": "application/json"
},
data:{
client_id: this.clientId,
client_secret: this.clientSecretKey,
code,
redirect_uri: redirectUri
}
})
const tokens = res
const uri = new URL(req.currentURL);
const redirectUri = `${uri.origin}${uri.pathname}`;
const res = await this.ctx.utils.http.request({
url: tokenEndpoint,
method: "post",
headers: {
Accept: "application/json",
},
data: {
client_id: this.clientId,
client_secret: this.clientSecretKey,
code,
redirect_uri: redirectUri,
},
});
const userInfoEndpoint = "https://api.github.com/user"
const tokens = res;
const userInfoEndpoint = "https://api.github.com/user";
// 获取用户信息
const userInfoRes = await this.ctx.utils.http.request( {
url: userInfoEndpoint,
method: "get",
headers: {
"Authorization": `Bearer ${tokens.access_token}`,
"Accept": "application/json"
}
})
const userInfo = userInfoRes
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:{
token: {
accessToken: tokens.access_token,
refreshToken: tokens.refresh_token,
expiresIn: tokens.expires_in,
@@ -87,10 +84,10 @@ export class GithubOauthProvider extends BaseAddon implements IOauthProvider {
nickName: userInfo.login || userInfo.name || "",
avatar: userInfo.avatar_url,
},
}
};
};
}
async buildLogoutUrl(params: BuildLogoutUrlReq) {
return {};
}
}
}
@@ -3,14 +3,13 @@ import { BuildLoginUrlReq, BuildLogoutUrlReq, IOauthProvider, OnCallbackReq } fr
@IsAddon({
addonType: "oauth",
name: 'google',
title: 'Google认证',
desc: 'Google OAuth2登录',
icon:"simple-icons:google",
name: "google",
title: "Google认证",
desc: "Google OAuth2登录",
icon: "simple-icons:google",
showTest: false,
})
export class GoogleOauthProvider extends BaseAddon implements IOauthProvider {
@AddonInput({
title: "ClientId",
helper: "[Google Cloud Console](https://console.cloud.google.com/apis/credentials)创建应用后获取",
@@ -28,58 +27,55 @@ export class GoogleOauthProvider extends BaseAddon implements IOauthProvider {
clientSecretKey = "";
async buildLoginUrl(params: BuildLoginUrlReq) {
const scope = "email profile"; // Scope of the access request
let scope = "email profile" // Scope of the access request
const authorizeEndpoint = "https://accounts.google.com/o/oauth2/auth"
const redirectUrl = encodeURIComponent(params.redirectUri)
const loginUrl = `${authorizeEndpoint}?client_id=${this.clientId}&redirect_uri=${redirectUrl}&response_type=code&scope=${scope}&state=${params.state}`
const authorizeEndpoint = "https://accounts.google.com/o/oauth2/auth";
const redirectUrl = encodeURIComponent(params.redirectUri);
const loginUrl = `${authorizeEndpoint}?client_id=${this.clientId}&redirect_uri=${redirectUrl}&response_type=code&scope=${scope}&state=${params.state}`;
return {
loginUrl,
ticketValue: {
},
ticketValue: {},
};
}
async onCallback(req: OnCallbackReq) {
const code = req.code || ""
const code = req.code || "";
const tokenEndpoint = "https://oauth2.googleapis.com/token"
const tokenEndpoint = "https://oauth2.googleapis.com/token";
const uri = new URL(req.currentURL)
const redirectUri = `${uri.origin}${uri.pathname}`
const res = await this.ctx.utils.http.request( {
url: tokenEndpoint,
method: "post",
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
data:{
client_id: this.clientId,
client_secret: this.clientSecretKey,
code,
redirect_uri: redirectUri,
grant_type: "authorization_code"
}
})
const tokens = res
const uri = new URL(req.currentURL);
const redirectUri = `${uri.origin}${uri.pathname}`;
const res = await this.ctx.utils.http.request({
url: tokenEndpoint,
method: "post",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
data: {
client_id: this.clientId,
client_secret: this.clientSecretKey,
code,
redirect_uri: redirectUri,
grant_type: "authorization_code",
},
});
const userInfoEndpoint = "https://www.googleapis.com/oauth2/v3/userinfo"
const tokens = res;
const userInfoEndpoint = "https://www.googleapis.com/oauth2/v3/userinfo";
// 获取用户信息
const userInfoRes = await this.ctx.utils.http.request( {
url: userInfoEndpoint,
method: "get",
headers: {
"Authorization": `Bearer ${tokens.access_token}`
}
})
const userInfo = userInfoRes
const userInfoRes = await this.ctx.utils.http.request({
url: userInfoEndpoint,
method: "get",
headers: {
Authorization: `Bearer ${tokens.access_token}`,
},
});
const userInfo = userInfoRes;
return {
token:{
token: {
accessToken: tokens.access_token,
refreshToken: tokens.refresh_token,
expiresIn: tokens.expires_in,
@@ -89,10 +85,10 @@ export class GoogleOauthProvider extends BaseAddon implements IOauthProvider {
nickName: userInfo.name || userInfo.email || "",
avatar: userInfo.picture,
},
}
};
};
}
async buildLogoutUrl(params: BuildLogoutUrlReq) {
return {};
}
}
}
@@ -3,14 +3,13 @@ import { BuildLoginUrlReq, BuildLogoutUrlReq, IOauthProvider, OnCallbackReq } fr
@IsAddon({
addonType: "oauth",
name: 'microsoft',
title: 'Microsoft认证',
desc: 'Microsoft OAuth2登录',
icon:"simple-icons:microsoft",
name: "microsoft",
title: "Microsoft认证",
desc: "Microsoft OAuth2登录",
icon: "simple-icons:microsoft",
showTest: false,
})
export class MicrosoftOauthProvider extends BaseAddon implements IOauthProvider {
@AddonInput({
title: "ClientId",
helper: "[Microsoft Entra ID](https://portal.azure.com/#view/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/~/RegisteredApps)创建应用后获取",
@@ -23,7 +22,7 @@ export class MicrosoftOauthProvider extends BaseAddon implements IOauthProvider
component: {
placeholder: "ClientSecretKey / appSecretKey",
},
helper:"客户端凭据->证书与机密->客户端密码->新客户端密码",
helper: "客户端凭据->证书与机密->客户端密码->新客户端密码",
required: true,
})
clientSecretKey = "";
@@ -33,72 +32,69 @@ export class MicrosoftOauthProvider extends BaseAddon implements IOauthProvider
component: {
placeholder: "common 或 租户ID",
},
helper:"根据受支持的账户类型填写 common 或 租户ID,默认为common(Microsoft个人账户)。 \n租户ID获取: 概述 -> 目录(租户) ID ",
helper: "根据受支持的账户类型填写 common 或 租户ID,默认为common(Microsoft个人账户)。 \n租户ID获取: 概述 -> 目录(租户) ID ",
value: "common",
required: false,
})
tenantId = "common";
async buildLoginUrl(params: BuildLoginUrlReq) {
let scope = "openid profile email User.Read" // Scope of the access request
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=${params.state}`
const scope = "openid profile email User.Read"; // Scope of the access request
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=${params.state}`;
return {
loginUrl,
ticketValue: {
},
ticketValue: {},
};
}
async onCallback(req: OnCallbackReq) {
const code = req.code || ""
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 tokenEndpoint = `https://login.microsoftonline.com/${this.tenantId}/oauth2/v2.0/token`;
const uri = new URL(req.currentURL);
const redirectUri = `${uri.origin}${uri.pathname}`;
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');
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 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 userInfoEndpoint = "https://graph.microsoft.com/v1.0/me"
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
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:{
token: {
accessToken: tokens.access_token,
refreshToken: tokens.refresh_token,
expiresIn: tokens.expires_in,
@@ -108,10 +104,10 @@ export class MicrosoftOauthProvider extends BaseAddon implements IOauthProvider
nickName: userInfo.displayName || userInfo.userPrincipalName || "",
avatar: userInfo.avatar || "",
},
}
};
};
}
async buildLogoutUrl(params: BuildLogoutUrlReq) {
return {};
}
}
}
@@ -4,19 +4,18 @@ import { IconSets } from "../iconsets.js";
@IsAddon({
addonType: "oauth",
name: 'oidc',
title: 'OIDC认证',
desc: 'OpenID Connect 认证,统一认证服务',
icon:"simple-icons:fusionauth:#006be6",
name: "oidc",
title: "OIDC认证",
desc: "OpenID Connect 认证,统一认证服务",
icon: "simple-icons:fusionauth:#006be6",
showTest: false,
})
export class OidcOauthProvider extends BaseAddon implements IOauthProvider {
@AddonInput({
title: "自定义图标",
component: {
name:"fs-icon-selector",
vModel:"modelValue",
name: "fs-icon-selector",
vModel: "modelValue",
iconSets: IconSets,
},
required: false,
@@ -49,53 +48,48 @@ export class OidcOauthProvider extends BaseAddon implements IOauthProvider {
})
issuerUrl = "";
async getClient() {
const client = await import('openid-client')
let server = new URL(this.issuerUrl)// Authorization Server's Issuer Identifier
const client = await import("openid-client");
const server = new URL(this.issuerUrl); // Authorization Server's Issuer Identifier
let config = await client.discovery(
server,
this.clientId,
this.clientSecretKey,
)
const config = await client.discovery(server, this.clientId, this.clientSecretKey);
// console.log(config.serverMetadata())
return {
config,
client
}
client,
};
}
async buildLoginUrl(params: BuildLoginUrlReq) {
const { config, client } = await this.getClient()
let redirect_uri = new URL(params.redirectUri)
let scope = 'openid profile' // Scope of the access request
async buildLoginUrl(params: BuildLoginUrlReq) {
const { config, client } = await this.getClient();
const redirect_uri = new URL(params.redirectUri);
const scope = "openid profile"; // Scope of the access request
/**
* PKCE: The following MUST be generated for every redirect to the
* authorization_endpoint. You must store the code_verifier and state in the
* end-user session such that it can be recovered as the user gets redirected
* from the authorization server back to your application.
*/
let code_verifier = client.randomPKCECodeVerifier()
let code_challenge = await client.calculatePKCECodeChallenge(code_verifier)
let state:any = {
forType: params.forType || 'login',
}
state = this.ctx.utils.hash.base64(JSON.stringify(state))
const code_verifier = client.randomPKCECodeVerifier();
const code_challenge = await client.calculatePKCECodeChallenge(code_verifier);
let state: any = {
forType: params.forType || "login",
};
state = this.ctx.utils.hash.base64(JSON.stringify(state));
let parameters: any = {
const parameters: any = {
redirect_uri,
scope,
code_challenge,
code_challenge_method: 'S256',
code_challenge_method: "S256",
state,
nonce: client.randomNonce(),
}
};
let redirectTo = client.buildAuthorizationUrl(config, parameters)
const redirectTo = client.buildAuthorizationUrl(config, parameters);
return {
loginUrl: redirectTo.href,
ticketValue: {
@@ -107,22 +101,17 @@ export class OidcOauthProvider extends BaseAddon implements IOauthProvider {
}
async onCallback(req: OnCallbackReq) {
const { config, client } = await this.getClient()
const { config, client } = await this.getClient();
let tokens: any = await client.authorizationCodeGrant(
config,
req.currentURL,
{
expectedState: req.ticketValue.state,
pkceCodeVerifier: req.ticketValue.codeVerifier,
expectedNonce: req.ticketValue.nonce,
}
)
const tokens: any = await client.authorizationCodeGrant(config, req.currentURL, {
expectedState: req.ticketValue.state,
pkceCodeVerifier: req.ticketValue.codeVerifier,
expectedNonce: req.ticketValue.nonce,
});
const claims = tokens.claims()
const claims = tokens.claims();
return {
token:{
token: {
accessToken: tokens.access_token,
refreshToken: tokens.refresh_token,
expiresIn: tokens.expires_in,
@@ -133,18 +122,18 @@ export class OidcOauthProvider extends BaseAddon implements IOauthProvider {
avatar: claims.picture,
email: claims.email || "",
},
}
};
};
}
async buildLogoutUrl(params: BuildLogoutUrlReq) {
try{
const { config } = await this.getClient()
let logoutUrl = config.serverMetadata().end_session_endpoint
try {
const { config } = await this.getClient();
const logoutUrl = config.serverMetadata().end_session_endpoint;
return {
logoutUrl: logoutUrl,
};
}catch(err){
this.logger.error(`获取注销地址失败: ${err}`)
} catch (err) {
this.logger.error(`获取注销地址失败: ${err}`);
return {
logoutUrl: "",
};
@@ -3,14 +3,13 @@ import { BuildLoginUrlReq, BuildLogoutUrlReq, IOauthProvider, OnCallbackReq } fr
@IsAddon({
addonType: "oauth",
name: 'wx',
title: '微信登录',
desc: '微信网站应用登录',
name: "wx",
title: "微信登录",
desc: "微信网站应用登录",
icon: "ion:logo-wechat:green",
showTest: false,
})
export class WxOauthProvider extends BaseAddon implements IOauthProvider {
@AddonInput({
title: "AppId",
required: true,
@@ -27,24 +26,22 @@ export class WxOauthProvider extends BaseAddon implements IOauthProvider {
})
appSecretKey = "";
wxAccessToken?: { access_token: string, expires_at: number }
wxAccessToken?: { access_token: string; expires_at: number };
async buildLoginUrl(params: BuildLoginUrlReq) {
const from = params.from || "web";
const appId = this.appId;
const redirect_uri = encodeURIComponent(params.redirectUri);
let state: any = {
forType: params.forType,
from
}
state = this.ctx.utils.hash.base64(JSON.stringify(state))
from,
};
state = this.ctx.utils.hash.base64(JSON.stringify(state));
let scope = "snsapi_userinfo";
let loginUrl = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appId}&redirect_uri=${redirect_uri}&response_type=code&scope=${scope}&state=${state}#wechat_redirect`
let loginUrl = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appId}&redirect_uri=${redirect_uri}&response_type=code&scope=${scope}&state=${state}#wechat_redirect`;
if (from === "web") {
scope = "snsapi_login";
loginUrl = `https://open.weixin.qq.com/connect/qrconnect?appid=${appId}&redirect_uri=${redirect_uri}&response_type=code&scope=${scope}&state=${state}#wechat_redirect`
loginUrl = `https://open.weixin.qq.com/connect/qrconnect?appid=${appId}&redirect_uri=${redirect_uri}&response_type=code&scope=${scope}&state=${state}#wechat_redirect`;
}
return {
@@ -78,13 +75,11 @@ export class WxOauthProvider extends BaseAddon implements IOauthProvider {
checkRet(res: any) {
if (res.errcode) {
throw new Error(res.errmsg)
throw new Error(res.errmsg);
}
}
async onCallback(req: OnCallbackReq) {
// GET https://api.weixin.qq.com/sns/oauth2/access_token?appid=wx520c15f417810387&secret=SECRET&code=CODE&grant_type=authorization_code
const res = await this.http.request({
url: "https://api.weixin.qq.com/sns/oauth2/access_token",
@@ -95,22 +90,21 @@ export class WxOauthProvider extends BaseAddon implements IOauthProvider {
code: req.code,
grant_type: "authorization_code",
},
})
this.checkRet(res)
const accessToken = res.access_token
});
this.checkRet(res);
const accessToken = res.access_token;
// GET https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN
const userInfoRes = await this.http.request({
url: "https://api.weixin.qq.com/sns/userinfo",
method: "GET",
params: {
access_token:accessToken,
access_token: accessToken,
openid: res.openid,
lang: "zh_CN",
},
})
this.checkRet(userInfoRes)
});
this.checkRet(userInfoRes);
return {
token: {
@@ -123,9 +117,8 @@ export class WxOauthProvider extends BaseAddon implements IOauthProvider {
nickName: userInfoRes.nickname || "",
avatar: userInfoRes.headimgurl,
},
}
};
};
}
async buildLogoutUrl(params: BuildLogoutUrlReq) {
return {};