Files
certd/packages/ui/certd-server/src/middleware/authority.ts
T

166 lines
4.8 KiB
TypeScript
Raw Normal View History

2026-05-31 01:41:33 +08:00
import { Init, Inject, MidwayWebRouterService, Provide, Scope, ScopeEnum } from "@midwayjs/core";
import { IMidwayKoaContext, IWebMiddleware, NextFunction } from "@midwayjs/koa";
import jwt from "jsonwebtoken";
import { Constants, SysPrivateSettings, SysSettingsService } from "@certd/lib-server";
import { logger } from "@certd/basic";
import { AuthService } from "../modules/sys/authority/service/auth-service.js";
import { OpenKeyService } from "../modules/open/service/open-key-service.js";
import { RoleService } from "../modules/sys/authority/service/role-service.js";
/**
* 权限校验
*/
@Provide()
2024-08-27 13:46:19 +08:00
@Scope(ScopeEnum.Singleton)
export class AuthorityMiddleware implements IWebMiddleware {
2023-06-27 09:29:43 +08:00
@Inject()
webRouterService: MidwayWebRouterService;
@Inject()
authService: AuthService;
2024-08-27 13:46:19 +08:00
@Inject()
2025-01-19 00:33:34 +08:00
roleService: RoleService;
@Inject()
openKeyService: OpenKeyService;
@Inject()
2024-08-27 13:46:19 +08:00
sysSettingsService: SysSettingsService;
secret: string;
@Init()
async init() {
const setting: SysPrivateSettings = await this.sysSettingsService.getSetting(SysPrivateSettings);
this.secret = setting.jwtKey;
}
resolve() {
return async (ctx: IMidwayKoaContext, next: NextFunction) => {
2023-06-27 09:29:43 +08:00
// 查询当前路由是否在路由表中注册
2024-07-15 00:30:33 +08:00
const routeInfo = await this.webRouterService.getMatchedRouterInfo(ctx.path, ctx.method);
2023-06-27 22:45:27 +08:00
if (routeInfo == null) {
// 404
await next();
return;
}
2026-07-12 02:29:54 +08:00
ctx.auditRouteInfo = routeInfo;
this.extractProjectId(ctx);
2026-05-31 01:41:33 +08:00
let permission = routeInfo.description || "";
permission = permission.trim().split(" ")[0];
if (permission == null || permission === "") {
2023-06-27 09:29:43 +08:00
ctx.status = 500;
2026-05-31 01:41:33 +08:00
ctx.body = Constants.res.serverError("该路由未配置权限控制:" + ctx.path);
2023-06-27 09:29:43 +08:00
return;
}
2023-06-27 09:29:43 +08:00
if (permission === Constants.per.guest) {
await next();
return;
}
const token = this.getTokenFromRequest(ctx);
2023-06-27 09:29:43 +08:00
2025-01-19 00:33:34 +08:00
if (token) {
try {
ctx.user = jwt.verify(token, this.secret);
} catch (err) {
2026-05-31 01:41:33 +08:00
logger.error("token verify error: ", err);
2025-01-19 00:33:34 +08:00
return this.notAuth(ctx);
}
} else {
if (permission === Constants.per.guestOptionalAuth) {
await next();
return;
}
2025-01-19 00:33:34 +08:00
//找找openKey
const openKey = await this.doOpenHandler(ctx);
if (!openKey) {
return this.notAuth(ctx);
}
if (permission === Constants.per.open) {
await next();
2023-06-27 09:29:43 +08:00
return;
2026-05-31 01:41:33 +08:00
} else if (openKey.scope === "open") {
return this.notAuth(ctx, "open key scope errorneed user scope");
2023-06-27 09:29:43 +08:00
}
}
2025-01-19 00:33:34 +08:00
if (permission === Constants.per.authOnly) {
await next();
return;
}
if (permission === Constants.per.guestOptionalAuth) {
await next();
return;
}
2025-01-19 00:33:34 +08:00
const pass = await this.authService.checkPermission(ctx, permission);
if (!pass) {
2026-05-31 01:41:33 +08:00
logger.info("not permission: ", ctx.req.url);
2025-03-09 16:22:22 +08:00
ctx.status = 200;
2025-01-19 00:33:34 +08:00
ctx.body = Constants.res.permission;
return;
}
2025-01-19 01:07:20 +08:00
await next();
};
}
2026-03-15 18:26:49 +08:00
private notAuth(ctx: IMidwayKoaContext, message?: string) {
2025-01-19 00:33:34 +08:00
ctx.status = 401;
ctx.body = Constants.res.auth;
2026-03-15 18:26:49 +08:00
if (message) {
// @ts-ignore
2026-05-31 01:41:33 +08:00
ctx.body.message = message;
2026-03-15 18:26:49 +08:00
}
2025-01-19 00:33:34 +08:00
return;
}
2026-07-12 02:29:54 +08:00
private extractProjectId(ctx: IMidwayKoaContext) {
const headerVal = ctx.headers["project-id"] as string;
const queryVal = (ctx.request as any)?.query?.projectId;
const bodyVal = (ctx.request as any)?.body?.projectId;
const raw = headerVal || queryVal || bodyVal;
if (raw != null && raw !== "") {
ctx.projectId = parseInt(String(raw), 10) || 0;
}
}
private getTokenFromRequest(ctx: IMidwayKoaContext) {
2026-05-31 01:41:33 +08:00
let token = ctx.get("Authorization") || "";
token = token.replace("Bearer ", "").trim();
if (token) {
return token;
}
const cookie = ctx.headers.cookie;
if (cookie) {
2026-05-31 01:41:33 +08:00
const items = cookie.split(";");
for (const item of items) {
2026-05-31 01:41:33 +08:00
if (!item || !item.trim()) {
continue;
}
2026-05-31 01:41:33 +08:00
const [key, value] = item.split("=");
if (key.trim() === "certd_token") {
return value.trim();
}
}
}
2026-05-31 01:41:33 +08:00
return (ctx.query.token as string) || "";
}
2025-01-19 00:33:34 +08:00
async doOpenHandler(ctx: IMidwayKoaContext) {
//开放接口
2026-05-31 01:41:33 +08:00
const openKey = ctx.get("x-certd-token") || "";
if (!openKey) {
2025-01-19 00:33:34 +08:00
return null;
}
//校验 openKey
const openKeyRes = await this.openKeyService.verifyOpenKey(openKey);
2026-05-31 01:41:33 +08:00
let roles = [1];
2026-03-15 14:01:34 +08:00
if (!openKeyRes.projectId || openKeyRes.projectId <= 0) {
roles = await this.roleService.getRoleIdsByUserId(openKeyRes.userId);
}
2026-05-31 01:41:33 +08:00
ctx.user = { id: openKeyRes.userId, roles, projectId: openKeyRes.projectId };
ctx.openKey = openKeyRes;
2025-01-19 00:33:34 +08:00
return openKeyRes;
}
}