mirror of
https://github.com/certd/certd.git
synced 2026-07-15 18:27:33 +08:00
chore: format
This commit is contained in:
@@ -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 {};
|
||||
|
||||
Reference in New Issue
Block a user