perf: oauth支持github 和google, 修复头像显示问题

This commit is contained in:
xiaojunnuo
2026-02-05 01:10:01 +08:00
parent 82786c580a
commit 693a4a6633
5 changed files with 228 additions and 3 deletions

View File

@@ -2,4 +2,6 @@ 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-clogin.js'
export * from './oauth2/plugin-github.js'
export * from './oauth2/plugin-google.js'

View File

@@ -0,0 +1,103 @@
import { AddonInput, BaseAddon, IsAddon } from "@certd/lib-server";
import { BuildLoginUrlReq, BuildLogoutUrlReq, IOauthProvider, OnCallbackReq } from "../api.js";
@IsAddon({
addonType: "oauth",
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)创建应用后获取",
required: true,
})
clientId = "";
@AddonInput({
title: "ClientSecretKey",
component: {
placeholder: "ClientSecretKey / appSecretKey",
},
required: true,
})
clientSecretKey = "";
async buildLoginUrl(params: BuildLoginUrlReq) {
let scope = "user:email" // Scope of the access request
let state:any = {
forType: params.forType || 'login',
}
state = this.ctx.utils.hash.base64(JSON.stringify(state))
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=${state}`
return {
loginUrl,
ticketValue: {
state,
},
};
}
async onCallback(req: OnCallbackReq) {
const code = req.code || ""
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 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
return {
token:{
accessToken: tokens.access_token,
refreshToken: tokens.refresh_token,
expiresIn: tokens.expires_in,
},
userInfo: {
openId: userInfo.id,
nickName: userInfo.login || userInfo.name || "",
avatar: userInfo.avatar_url,
},
}
};
async buildLogoutUrl(params: BuildLogoutUrlReq) {
return {};
}
}

View File

@@ -0,0 +1,103 @@
import { AddonInput, BaseAddon, IsAddon } from "@certd/lib-server";
import { BuildLoginUrlReq, BuildLogoutUrlReq, IOauthProvider, OnCallbackReq } from "../api.js";
@IsAddon({
addonType: "oauth",
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)创建应用后获取",
required: true,
})
clientId = "";
@AddonInput({
title: "ClientSecretKey",
component: {
placeholder: "ClientSecretKey / appSecretKey",
},
required: true,
})
clientSecretKey = "";
async buildLoginUrl(params: BuildLoginUrlReq) {
let scope = "email profile" // Scope of the access request
let state:any = {
forType: params.forType || 'login',
}
state = this.ctx.utils.hash.base64(JSON.stringify(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=${state}`
return {
loginUrl,
ticketValue: {
state,
},
};
}
async onCallback(req: OnCallbackReq) {
const code = req.code || ""
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 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
return {
token:{
accessToken: tokens.access_token,
refreshToken: tokens.refresh_token,
expiresIn: tokens.expires_in,
},
userInfo: {
openId: userInfo.sub,
nickName: userInfo.name || userInfo.email || "",
avatar: userInfo.picture,
},
}
};
async buildLogoutUrl(params: BuildLogoutUrlReq) {
return {};
}
}