数据库设计
- 用户表:包含用户基本信息,如
id
、username
、password
等,同时有一个字段role_id
用于关联用户角色表。
- 角色表:
id
作为主键,role_name
描述角色名称,例如admin
、user
等。
- 权限表:
id
为主键,permission_name
描述具体权限,如create_post
、edit_post
等。
- 角色 - 权限关联表:通过
role_id
和permission_id
两个字段,建立角色与权限之间的多对多关系,表明某个角色拥有哪些权限。
代码逻辑
- 初始化:在应用启动时,从数据库加载所有角色与权限的关联关系,存储在内存中(如使用
Map
数据结构),方便快速查询。
const rolePermissionMap = new Map();
// 假设从数据库获取角色权限关联数据
const rolePermissions = await RolePermission.findAll();
rolePermissions.forEach(({ role_id, permission_id }) => {
if (!rolePermissionMap.has(role_id)) {
rolePermissionMap.set(role_id, []);
}
rolePermissionMap.get(role_id).push(permission_id);
});
- 用户角色权限获取:当用户登录时,根据用户表中的
role_id
,从上述内存中的映射关系获取该用户角色所拥有的权限列表。
const user = await User.findByPk(userId);
const userPermissions = rolePermissionMap.get(user.role_id) || [];
中间件验证
- 定义中间件:在Express等框架中定义一个中间件函数,用于验证用户是否有权限访问特定资源。
const checkPermission = (requiredPermission) => {
return (req, res, next) => {
const user = req.user; // 假设通过身份验证中间件已将用户信息挂载到req.user
const userPermissions = rolePermissionMap.get(user.role_id) || [];
if (userPermissions.includes(requiredPermission)) {
next();
} else {
res.status(403).send('Forbidden');
}
};
};
- 使用中间件:在路由定义中使用该中间件,指定访问该路由所需的权限。
app.get('/posts/create', checkPermission('create_post'), (req, res) => {
// 创建文章逻辑
});