202 lines
5.2 KiB
TypeScript
202 lines
5.2 KiB
TypeScript
import './routes/index.ts';
|
||
import './aura/index.ts';
|
||
import { app } from './app.ts';
|
||
import type { App } from '@kevisual/router';
|
||
import { User } from './models/user.ts';
|
||
import { createCookie, getSomeInfoFromReq } from './routes/user/me.ts';
|
||
|
||
/**
|
||
* 添加auth中间件, 用于验证token
|
||
* 添加 id: auth 必须需要user成功
|
||
* 添加 id: auth-can 可以不需要user成功,有则赋值
|
||
*
|
||
* @param app
|
||
*/
|
||
export const addAuth = (app: App) => {
|
||
app
|
||
.route({
|
||
path: 'auth',
|
||
id: 'auth',
|
||
description: '验证token,必须成功, 错误返回401,正确赋值到ctx.state.tokenUser',
|
||
})
|
||
.define(async (ctx) => {
|
||
const token = ctx.query.token;
|
||
// 已经有用户信息则直接返回,不需要重复验证
|
||
if (ctx.state.tokenUser) {
|
||
return;
|
||
}
|
||
if (!token) {
|
||
ctx.throw(401, 'Token is required');
|
||
}
|
||
const user = await User.getOauthUser(token);
|
||
if (!user) {
|
||
ctx.throw(401, 'Token is invalid');
|
||
return;
|
||
}
|
||
// console.log(`auth user: ${user.username} (${user.id})`);
|
||
const someInfo = getSomeInfoFromReq(ctx);
|
||
if (someInfo.isBrowser && !ctx.req?.cookies?.['token']) {
|
||
createCookie({ accessToken: token }, ctx);
|
||
}
|
||
ctx.state.tokenUser = user;
|
||
})
|
||
.addTo(app);
|
||
|
||
app
|
||
.route({
|
||
path: 'auth',
|
||
key: 'can',
|
||
id: 'auth-can',
|
||
description: '验证token,可以不成功,错误不返回401,正确赋值到ctx.state.tokenUser,失败赋值null',
|
||
})
|
||
.define(async (ctx) => {
|
||
// 已经有用户信息则直接返回,不需要重复验证
|
||
if (ctx.state.tokenUser) {
|
||
return;
|
||
}
|
||
if (ctx.query?.token) {
|
||
const token = ctx.query.token;
|
||
const user = await User.getOauthUser(token);
|
||
if (token) {
|
||
ctx.state.tokenUser = user;
|
||
const someInfo = getSomeInfoFromReq(ctx);
|
||
if (someInfo.isBrowser && !ctx.req?.cookies?.['token']) {
|
||
createCookie({ accessToken: token }, ctx);
|
||
}
|
||
} else {
|
||
ctx.state.tokenUser = null;
|
||
}
|
||
}
|
||
})
|
||
.addTo(app);
|
||
};
|
||
addAuth(app);
|
||
|
||
app
|
||
.route({
|
||
path: 'auth',
|
||
key: 'admin',
|
||
id: 'auth-admin',
|
||
isDebug: true,
|
||
middleware: ['auth'],
|
||
description: '验证token,必须是admin用户, 错误返回403,正确赋值到ctx.state.tokenAdmin',
|
||
})
|
||
.define(async (ctx) => {
|
||
const tokenUser = ctx.state.tokenUser;
|
||
if (!tokenUser) {
|
||
ctx.throw(401, 'No User For authorized');
|
||
}
|
||
console.log('auth-admin tokenUser', ctx.state);
|
||
if (typeof ctx.state.isAdmin !== 'undefined' && ctx.state.isAdmin === true) {
|
||
return;
|
||
}
|
||
try {
|
||
const user = await User.findOne({
|
||
id: tokenUser.id,
|
||
});
|
||
if (!user) {
|
||
ctx.throw(404, 'user not found');
|
||
}
|
||
user.setTokenUser(tokenUser);
|
||
const orgs = await user.getOrgs();
|
||
if (orgs.includes('admin')) {
|
||
ctx.body = 'admin';
|
||
} else {
|
||
ctx.throw(403, 'forbidden');
|
||
}
|
||
ctx.state.isAdmin = true;
|
||
} catch (e) {
|
||
console.error(`auth-admin error`, e);
|
||
console.error('tokenUser', tokenUser?.id, tokenUser?.username, tokenUser?.uid);
|
||
ctx.throw(500, e.message);
|
||
}
|
||
})
|
||
.addTo(app);
|
||
|
||
app
|
||
.route({
|
||
path: 'auth-check',
|
||
key: 'admin',
|
||
id: 'check-auth-admin',
|
||
middleware: ['auth'],
|
||
})
|
||
.define(async (ctx) => {
|
||
const tokenUser = ctx.state.tokenUser;
|
||
if (!tokenUser) {
|
||
ctx.throw(401, 'No User For authorized');
|
||
}
|
||
if (typeof ctx.state.isAdmin !== 'undefined') {
|
||
return;
|
||
}
|
||
|
||
try {
|
||
const user = await User.findOne({
|
||
id: tokenUser.id,
|
||
});
|
||
if (!user) {
|
||
ctx.throw(404, 'user not found');
|
||
}
|
||
user.setTokenUser(tokenUser);
|
||
const orgs = await user.getOrgs();
|
||
if (orgs.includes('admin')) {
|
||
ctx.body = 'admin';
|
||
ctx.state.isAdmin = true;
|
||
ctx.state.tokenAdmin = {
|
||
id: user.id,
|
||
username: user.username,
|
||
orgs,
|
||
};
|
||
return;
|
||
} else {
|
||
ctx.state.isAdmin = false;
|
||
}
|
||
ctx.body = 'not admin';
|
||
} catch (e) {
|
||
console.error(`auth-admin error`, e);
|
||
console.error('tokenUser', tokenUser?.id, tokenUser?.username, tokenUser?.uid);
|
||
ctx.throw(500, e.message);
|
||
}
|
||
})
|
||
.addTo(app);
|
||
|
||
app
|
||
.route({
|
||
path: 'router',
|
||
key: 'list',
|
||
description: '列出所有的当前的可请求的路由信息',
|
||
middleware: ['auth-can']
|
||
})
|
||
.define(async (ctx) => {
|
||
const tokenUser = ctx.state.tokenUser;
|
||
let isUser = !!tokenUser;
|
||
ctx.body = {
|
||
list: app.router.routes.filter(item => {
|
||
if (item.id === 'auth' || item.id === 'auth-can' || item.id === 'check-auth-admin' || item.id === 'auth-admin') {
|
||
return false;
|
||
}
|
||
return true;
|
||
}).map((item) => {
|
||
return {
|
||
id: item.id,
|
||
path: item.path,
|
||
key: item.key,
|
||
description: item.description,
|
||
middeleware: item.middleware,
|
||
metadata: item.metadata,
|
||
};
|
||
}),
|
||
isUser
|
||
}
|
||
})
|
||
.addTo(app);
|
||
|
||
|
||
app.route({
|
||
path: 'system',
|
||
key: 'version'
|
||
}).define(async (ctx) => {
|
||
ctx.body = {
|
||
version: '0.0.1',
|
||
name: 'KeVisual Backend System',
|
||
}
|
||
}).addTo(app); |