完善discord登录流程

This commit is contained in:
zhl 2023-06-12 19:00:07 +08:00
parent 3621d8cc44
commit a2313ff701
3 changed files with 164 additions and 90 deletions

View File

@ -1,74 +1,89 @@
import fastify, { FastifyError, FastifyInstance, FastifyReply, FastifyRequest } from 'fastify'
import helmet from '@fastify/helmet'
import { IncomingMessage, Server, ServerResponse } from 'http'
import { RouterMap } from 'decorators/router'
import { mongoose } from '@typegoose/typegoose'
import logger from 'logger/logger'
import config from 'config/config'
import { ConnectOptions } from 'mongoose'
import fastify, {
FastifyError,
FastifyInstance,
FastifyReply,
FastifyRequest,
} from "fastify";
import helmet from "@fastify/helmet";
import { IncomingMessage, Server, ServerResponse } from "http";
import { RouterMap } from "decorators/router";
import { mongoose } from "@typegoose/typegoose";
import logger from "logger/logger";
import config from "config/config";
import { ConnectOptions } from "mongoose";
import { DiscordSvr } from "services/discord.svr";
const zReqParserPlugin = require('plugins/zReqParser')
const zReqParserPlugin = require("plugins/zReqParser");
const zTokenParserPlugin = require('plugins/zTokenParser')
const zTokenParserPlugin = require("plugins/zTokenParser");
const apiAuthPlugin = require('plugins/apiauth')
const apiAuthPlugin = require("plugins/apiauth");
const fs = require('fs')
const join = require('path').join
const fs = require("fs");
const join = require("path").join;
require('./common/Extend')
require("./common/Extend");
export class ApiServer {
server: FastifyInstance<Server, IncomingMessage, ServerResponse>
server: FastifyInstance<Server, IncomingMessage, ServerResponse>;
public constructor() {
this.server = fastify({ logger: true, trustProxy: true })
this.registerPlugins()
console.log('version::' + process.version)
this.server = fastify({ logger: true, trustProxy: true });
this.registerPlugins();
console.log("version::" + process.version);
}
private registerPlugins() {
this.server.register(require('@fastify/formbody'))
this.server.register(zReqParserPlugin)
this.server.register(helmet, { hidePoweredBy: false, contentSecurityPolicy: false })
this.server.register(zTokenParserPlugin)
this.server.register(require("@fastify/formbody"));
this.server.register(zReqParserPlugin);
this.server.register(helmet, {
hidePoweredBy: false,
contentSecurityPolicy: false,
});
this.server.register(zTokenParserPlugin);
this.server.register(apiAuthPlugin, {
secret: { private: config.api.token_secret_private, public: config.api.token_secret_public },
secret: {
private: config.api.token_secret_private,
public: config.api.token_secret_public,
},
expiresIn: config.api.token_expiresIn,
})
if (process.env.NODE_ENV !== 'production') {
this.server.register(require('@fastify/cors'), {})
});
if (process.env.NODE_ENV !== "production") {
this.server.register(require("@fastify/cors"), {});
}
this.server.register(require('@fastify/view'), {
this.server.register(require("@fastify/view"), {
engine: {
ejs: require('ejs'),
ejs: require("ejs"),
},
})
});
}
private registerRouter() {
logger.log('register api routers')
let self = this
logger.log("register api routers");
let self = this;
for (let [controller, config] of RouterMap.decoratedRouters) {
for (let data of config.data) {
logger.info(
'add router',
data.method || 'all',
"add router",
data.method || "all",
data.path,
`${data.target.constructor.name}.${controller.name}()`,
)
`${data.target.constructor.name}.${controller.name}()`
);
// @ts-ignore
self.server[data.method || 'all'](
self.server[data.method || "all"](
data.path,
{
preValidation: async function (request: FastifyRequest, reply: FastifyReply) {
request.roles = config.roles
await this.apiAuth(request, reply)
preValidation: async function (
request: FastifyRequest,
reply: FastifyReply
) {
request.roles = config.roles;
await this.apiAuth(request, reply);
},
},
controller,
)
controller
);
}
}
}
@ -76,56 +91,64 @@ export class ApiServer {
* controller
*/
initControllers() {
logger.info('Bootstrap controllers...')
const controllers = join(__dirname, './controllers')
logger.info("Bootstrap controllers...");
const controllers = join(__dirname, "./controllers");
fs.readdirSync(controllers)
.filter((file: string) => ~file.search(/^[^.].*\.(ts|js)$/))
.forEach((file: any) => {
// logger.log(file);
return require(join(controllers, file))
})
return require(join(controllers, file));
});
}
initSchedules() {}
initServcers() {
new DiscordSvr().init();
}
async connectDB() {
const options: ConnectOptions = {
minPoolSize: 5,
maxPoolSize: 10,
keepAlive: true,
keepAliveInitialDelay: 300000,
}
const uri = config.db_main
logger.info(`connect to ${uri} ...`)
};
const uri = config.db_main;
logger.info(`connect to ${uri} ...`);
try {
// await mongoose.createConnection(uri, options)
await mongoose.connect(uri, options)
logger.log('DB Connected')
await mongoose.connect(uri, options);
logger.log("DB Connected");
} catch (err) {
logger.log(`DB Connection Error: ${err.message}`)
logger.log(`DB Connection Error: ${err.message}`);
}
}
private setErrHandler() {
this.server.setNotFoundHandler(function (
request: any,
reply: { send: (arg0: { errcode: number; errmsg: string }) => void },
reply: { send: (arg0: { errcode: number; errmsg: string }) => void }
) {
reply.send({ errcode: 404, errmsg: 'page not found' })
})
this.server.setErrorHandler(function (error: FastifyError, request: FastifyRequest, reply: FastifyReply) {
let statusCode = (error && error.statusCode) || 100
reply.send({ errcode: 404, errmsg: "page not found" });
});
this.server.setErrorHandler(function (
error: FastifyError,
request: FastifyRequest,
reply: FastifyReply
) {
let statusCode = (error && error.statusCode) || 100;
if (statusCode >= 500) {
logger.error(error)
logger.error(error);
} else if (statusCode >= 400) {
logger.info(error)
logger.info(error);
} else {
logger.error(error)
logger.error(error);
}
reply.code(200).send({
errcode: statusCode,
errmsg: error ? error.message : 'unknown error',
})
})
errmsg: error ? error.message : "unknown error",
});
});
}
/**
* ,
@ -137,40 +160,47 @@ export class ApiServer {
* @private
*/
private setFormatSend() {
this.server.addHook('preSerialization', async (request: FastifyRequest, reply: FastifyReply, payload) => {
reply.header('X-Powered-By', 'PHP/5.4.16')
// @ts-ignore
if (!payload.errcode) {
this.server.addHook(
"preSerialization",
async (request: FastifyRequest, reply: FastifyReply, payload) => {
reply.header("X-Powered-By", "PHP/5.4.16");
// @ts-ignore
if (payload.direct) {
if (!payload.errcode) {
// @ts-ignore
delete payload.direct
return payload
}
payload = {
errcode: 0,
data: payload,
if (payload.direct) {
// @ts-ignore
delete payload.direct;
return payload;
}
payload = {
errcode: 0,
data: payload,
};
}
return payload;
}
return payload
})
);
}
public async start() {
let self = this
let self = this;
return new Promise(async (resolve, reject) => {
await self.connectDB()
self.initControllers()
self.registerRouter()
self.setErrHandler()
self.setFormatSend()
self.initSchedules()
this.server.listen({ port: config.api.port, host: config.api.host }, (err: any, address: any) => {
if (err) {
logger.log(err)
process.exit(0)
await self.connectDB();
self.initControllers();
self.registerRouter();
self.setErrHandler();
self.setFormatSend();
self.initSchedules();
self.initServcers();
this.server.listen(
{ port: config.api.port, host: config.api.host },
(err: any, address: any) => {
if (err) {
logger.log(err);
process.exit(0);
}
resolve && resolve(address);
}
resolve && resolve(address)
})
})
);
});
}
}

View File

@ -2,7 +2,11 @@ import BaseController, { ROLE_ANON } from "common/base.controller";
import { ZError } from "common/ZError";
import { role, router } from "decorators/router";
import logger from "logger/logger";
import { exchangeDiscrodCodeForToken, userInfo } from "services/discord.svr";
import {
DiscordSvr,
exchangeDiscrodCodeForToken,
userInfo,
} from "services/discord.svr";
class DiscordController extends BaseController {
@role(ROLE_ANON)
@ -14,9 +18,19 @@ class DiscordController extends BaseController {
if (code) {
access_token = await exchangeDiscrodCodeForToken(code);
let uinfo = await userInfo(access_token);
console.log(uinfo);
return res.view("/templates/discord_redirect.ejs");
} else {
return res.view("/templates/discord_redirect.ejs");
}
}
@role(ROLE_ANON)
@router("get /discord/check_user_role")
async checkUserRole(req, res) {
// let { uid } = req.params;
let uid = "1034482894690861116";
let role = await new DiscordSvr().checkUserRole(uid);
return { role };
}
}

View File

@ -1,3 +1,7 @@
import { ZError } from "common/ZError";
import { singleton } from "decorators/singleton";
const { Client, Events, GatewayIntentBits } = require("discord.js");
export async function exchangeDiscrodCodeForToken(code: string) {
const clientId = process.env.DISCORD_CLIENT_ID;
const clientSecret = process.env.DISCORD_CLIENT_SECRET;
@ -34,3 +38,29 @@ export async function userInfo(token: string) {
console.log(data);
return data;
}
@singleton
export class DiscordSvr {
private client: any;
private guild: any;
public async init() {
console.log("DiscordSvr init");
this.client = new Client({ intents: [GatewayIntentBits.Guilds] });
this.client.once(Events.ClientReady, async (c) => {
console.log(`Ready! Logged in as ${c.user.tag}`);
this.guild = await this.client.guilds.fetch(process.env.DISCROD_GUILD_ID);
});
this.client.login(process.env.DISCORD_BOT_TOKEN);
}
public async checkUserRole(uid: string) {
if (!this.guild) {
throw new ZError(10, "DiscordSvr not init");
}
const member = await this.guild.members.fetch(uid);
if (!member) {
return false;
}
return member.roles.cache.has(process.env.DISCORD_ROLE_ID);
}
}