131 lines
3.0 KiB
JavaScript
131 lines
3.0 KiB
JavaScript
|
|
const Tenant = require('../models/Tenant');
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 租户上下文中间件
|
|||
|
|
* 从请求头或JWT令牌中提取租户信息,并设置到请求上下文中
|
|||
|
|
*/
|
|||
|
|
const tenantContextMiddleware = async (req, res, next) => {
|
|||
|
|
try {
|
|||
|
|
let tenantId = null;
|
|||
|
|
|
|||
|
|
// 1. 尝试从请求头获取租户ID
|
|||
|
|
const headerTenantId = req.headers['x-tenant-id'];
|
|||
|
|
if (headerTenantId) {
|
|||
|
|
tenantId = parseInt(headerTenantId, 10);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 2. 如果请求头中没有,尝试从JWT令牌中获取
|
|||
|
|
if (!tenantId && req.user && req.user.tenantId) {
|
|||
|
|
tenantId = req.user.tenantId;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 3. 系统管理员可以指定任意租户
|
|||
|
|
if (req.user && req.user.userType === 'super_admin' && headerTenantId) {
|
|||
|
|
tenantId = parseInt(headerTenantId, 10);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 4. 如果没有租户ID,返回错误
|
|||
|
|
if (!tenantId) {
|
|||
|
|
return res.status(400).json({
|
|||
|
|
code: 400,
|
|||
|
|
message: '缺少租户标识'
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 5. 验证租户是否存在且状态正常
|
|||
|
|
const tenant = await Tenant.findOne({
|
|||
|
|
where: {
|
|||
|
|
id: tenantId,
|
|||
|
|
status: 'active',
|
|||
|
|
isDeleted: 0
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
if (!tenant) {
|
|||
|
|
return res.status(403).json({
|
|||
|
|
code: 403,
|
|||
|
|
message: '租户不存在或已被禁用'
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 6. 检查租户是否过期(使用 currentPeriodEnd 判断)
|
|||
|
|
if (tenant.currentPeriodEnd && new Date(tenant.currentPeriodEnd) < new Date()) {
|
|||
|
|
return res.status(403).json({
|
|||
|
|
code: 403,
|
|||
|
|
message: '租户服务已过期'
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 7. 将租户信息附加到请求对象
|
|||
|
|
req.tenantId = tenantId;
|
|||
|
|
req.tenant = tenant;
|
|||
|
|
|
|||
|
|
next();
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('租户上下文中间件错误:', error);
|
|||
|
|
return res.status(500).json({
|
|||
|
|
code: 500,
|
|||
|
|
message: '租户验证失败',
|
|||
|
|
error: error.message
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 可选租户中间件
|
|||
|
|
* 用于一些不需要强制租户隔离的接口
|
|||
|
|
*/
|
|||
|
|
const optionalTenantMiddleware = async (req, res, next) => {
|
|||
|
|
try {
|
|||
|
|
let tenantId = null;
|
|||
|
|
|
|||
|
|
const headerTenantId = req.headers['x-tenant-id'];
|
|||
|
|
if (headerTenantId) {
|
|||
|
|
tenantId = parseInt(headerTenantId, 10);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (!tenantId && req.user && req.user.tenantId) {
|
|||
|
|
tenantId = req.user.tenantId;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (tenantId) {
|
|||
|
|
const tenant = await Tenant.findOne({
|
|||
|
|
where: {
|
|||
|
|
id: tenantId,
|
|||
|
|
status: 'active',
|
|||
|
|
isDeleted: 0
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
if (tenant) {
|
|||
|
|
req.tenantId = tenantId;
|
|||
|
|
req.tenant = tenant;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
next();
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('可选租户中间件错误:', error);
|
|||
|
|
next();
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 系统管理员权限检查中间件
|
|||
|
|
*/
|
|||
|
|
const superAdminMiddleware = (req, res, next) => {
|
|||
|
|
if (!req.user || req.user.userType !== 'super_admin') {
|
|||
|
|
return res.status(403).json({
|
|||
|
|
code: 403,
|
|||
|
|
message: '需要系统管理员权限'
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
next();
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
module.exports = {
|
|||
|
|
tenantContextMiddleware,
|
|||
|
|
optionalTenantMiddleware,
|
|||
|
|
superAdminMiddleware
|
|||
|
|
};
|