add login with discord

This commit is contained in:
CounterFire2023 2024-01-24 16:11:12 +08:00
parent 4810544cd1
commit 9bcd9168ab
7 changed files with 106 additions and 16 deletions

View File

@ -54,3 +54,8 @@ OKX_API_KEY='5cda794d-b2af-479c-bd75-af1eb877d4ef'
OKX_PROJECT_ID='17c69bdda138a6342f9bece529030cbb' OKX_PROJECT_ID='17c69bdda138a6342f9bece529030cbb'
OKX_PASS='7654321Cf_' OKX_PASS='7654321Cf_'
OKX_SECRET_KEY='AF7F4CEE2A10715F9709D38452CE0BFD' OKX_SECRET_KEY='AF7F4CEE2A10715F9709D38452CE0BFD'
DISCORD_CLIENT_ID='1199289311850409984'
DISCORD_CLIENT_SECRET='2ttcY7FgDXSo_izCD1BSZrORh864aR6r'
DISCORD_REDIRECT_URI='https://oauth-svr.cebggame.com/test/discord/oauth_redirect'

@ -1 +1 @@
Subproject commit b5f10e3d21e4cad0496ba0659232b3260946189e Subproject commit c1946bbe7d53e21cf0c85ca13a82577751a04b7c

View File

@ -0,0 +1,21 @@
import logger from 'logger/logger'
import { IPlat } from 'plats/IPlat'
import { BaseController, ROLE_ANON, role, router } from 'zutils'
import { PlatDiscord } from 'plats/PlatDiscord'
const plat: IPlat = new PlatDiscord()
class DiscordController extends BaseController {
@role(ROLE_ANON)
@router('get /discord/oauth_redirect')
async appleWebLoginCb(req, res) {
const { code, state, error } = req.params
console.log(`code: ${code}, state: ${state}, error: ${error}`)
if (error) {
res.redirect(`cebgdiscordcb://discord_login_result?state=${state}&error=${JSON.stringify(error)}`)
} else {
res.redirect(`cebgdiscordcb://discord_login_result?token=${code}&state=${state}`)
}
}
}

View File

@ -6,6 +6,7 @@ import { Wallet } from 'modules/Wallet'
import { IPlat } from 'plats/IPlat' import { IPlat } from 'plats/IPlat'
import { PlatApple } from 'plats/PlatApple' import { PlatApple } from 'plats/PlatApple'
import { PlatClient } from 'plats/PlatClient' import { PlatClient } from 'plats/PlatClient'
import { PlatDiscord } from 'plats/PlatDiscord'
import { PlatExternalWallet } from 'plats/PlatExternalWallet' import { PlatExternalWallet } from 'plats/PlatExternalWallet'
import { PlatFacebook } from 'plats/PlatFacebook' import { PlatFacebook } from 'plats/PlatFacebook'
import { PlatGoogle } from 'plats/PlatGoogle' import { PlatGoogle } from 'plats/PlatGoogle'
@ -22,6 +23,7 @@ const plats: Map<PlatEnum, IPlat> = new Map([
[PlatEnum.WC, new PlatExternalWallet()], [PlatEnum.WC, new PlatExternalWallet()],
[PlatEnum.EXTERNAL_WALLET, new PlatExternalWallet()], [PlatEnum.EXTERNAL_WALLET, new PlatExternalWallet()],
[PlatEnum.RELAY_WALLET, new PlatExternalWallet()], [PlatEnum.RELAY_WALLET, new PlatExternalWallet()],
[PlatEnum.DISCORD, new PlatDiscord()],
]) ])
// 如果客户端有传入account, 则说明该次登录是绑定账号 // 如果客户端有传入account, 则说明该次登录是绑定账号
@ -101,7 +103,7 @@ class LoginController extends BaseController {
} }
const plat = plats.get(channel) const plat = plats.get(channel)
if (!plat) { if (!plat) {
throw new ZError(11, 'plat not support') throw new ZError(11, 'plat not support: ' + channel)
} }
const { openId, data } = await plat.verifyToken(req) const { openId, data } = await plat.verifyToken(req)
const { api_platform } = req.headers const { api_platform } = req.headers

View File

@ -38,11 +38,12 @@ class WalletController extends BaseController {
record.nweRecord = false record.nweRecord = false
await record.save() await record.save()
} }
if (!record.toOkx && record.address) { // TODO:: 临时处理
setImmediate(async () => { // if (!record.toOkx && record.address) {
await bindOkx(record) // setImmediate(async () => {
}) // await bindOkx(record)
} // })
// }
Object.assign(data, record.toJson()) Object.assign(data, record.toJson())
return data return data
} }
@ -85,13 +86,14 @@ class WalletController extends BaseController {
} }
record.address = address record.address = address
await record.save() await record.save()
if (!record.toOkx) { // TODO:: 临时处理
if (!record.toOkx && record.address) { // if (!record.toOkx) {
setImmediate(async () => { // if (!record.toOkx && record.address) {
await bindOkx(record) // setImmediate(async () => {
}) // await bindOkx(record)
} // })
} // }
// }
return {} return {}
} }

60
src/plats/PlatDiscord.ts Normal file
View File

@ -0,0 +1,60 @@
import { ZError } from 'zutils'
import { IPlat } from './IPlat'
import { handleFetch } from 'zutils/utils/net.util'
export async function exchangeDiscrodCodeForToken(code: string) {
const clientId = process.env.DISCORD_CLIENT_ID
const clientSecret = process.env.DISCORD_CLIENT_SECRET
const redirectUri = process.env.DISCORD_REDIRECT_URI
const data = await handleFetch('https://discord.com/api/oauth2/token', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({
grant_type: 'authorization_code',
client_id: clientId,
client_secret: clientSecret,
redirect_uri: redirectUri,
code,
scope: 'identify email',
}),
})
return data
}
export async function userInfo(token: string) {
const data = await handleFetch('https://discord.com/api/users/@me', {
headers: {
authorization: `Bearer ${token}`,
},
})
return data
}
export class PlatDiscord implements IPlat {
async verifyToken(req: any): Promise<any> {
let { code, token } = req.params
code = code || token
let tokenResponse = await exchangeDiscrodCodeForToken(code)
if (!tokenResponse || tokenResponse.error) {
throw new ZError(60, tokenResponse.error_description)
}
let payload = await userInfo(tokenResponse.access_token)
const openId = payload.id
let data: any = {}
if (payload.username) data.nickname = payload.username
if (payload.avatar) data.avatar = payload.avatar
if (payload.email) data.email = payload.email
if (payload.verified) data.emailVerified = payload.verified
const { api_platform } = req.headers
if (api_platform) {
data.platform = api_platform
}
return { openId, data }
}
}

View File

@ -4,7 +4,7 @@
"name": "wallet-svr", "name": "wallet-svr",
"script": "npm", "script": "npm",
"args": "run prod:api", "args": "run prod:api",
"cwd": "/data/apps/wallet-svr", "cwd": "/home/kingsome/code/wallet-svr",
"max_memory_restart": "1024M", "max_memory_restart": "1024M",
"log_date_format" : "YYYY-MM-DD HH:mm Z", "log_date_format" : "YYYY-MM-DD HH:mm Z",
"watch": true, "watch": true,
@ -15,7 +15,7 @@
"tasks" "tasks"
], ],
"instances": 1, "instances": 1,
"exec_mode": "cluster", "exec_mode": "fork",
"env": { "env": {
"NODE_ENV": "production" "NODE_ENV": "production"
}, },