概述
在一个应用系统中有多个用户,用户通常分为多种角色,每种角色的用户能够访问的页面、能够查看的数据或者能够执行的操作等各有不同,因此需要设计与实现应用系统的权限体系。通过对应用系统进行需求分析,由用例图可知功能需求,由E-R图可知数据需求,应用系统的权限就包括功能权限和数据权限。功能权限描述了一个用户或者一种角色能够访问哪些页面、能够执行哪些操作(按钮、链接等),数据权限描述了一个用户或者一种角色能够查看什么范围内的数据(水平范围内的记录)、能够查看数据的哪些属性(垂直范围内的字段)。本文仅讨论功能权限的设计与实现,从数据库层面尽量实现一种通用的功能权限体系。
部门、用户与角色
在面向对象分析和设计中,通过用例图可以明确一个应该系统中有哪些用户、用户分哪些角色、用户属于哪个组织架构、各种用户或角色有哪些行为,通过E-R图来分析一个应用系统中的用户有哪些属性、用户与组织架构之间的关系、用户与角色之间的关系。1个用户属于1个部门,1个用户拥有1个或多个角色。用户属于哪个部门,则表示该用户只能查看与该部门关联的数据,这可以通过数据权限实现,也可以通过用户与部门之间的关联以及部门与其数据之间的关联推导出用户可查看哪些数据;用户拥有哪些角色,则表示该用户拥有这些角色赋予的权限。
图1:部门-用户-角色的E-R图
部门、用户和角色各自包含哪些基本属性,则用以下表说明:
字段名称 | 数据类型 | 属性 | 允许空 | 默认值 | 备注 |
u_id | int(4) | PK AI | 否 | 用户编号 | |
u_guid | char(36) | 否 | newid() | 用户GUID | |
d_guid | varchar(36) | 所在部门GUID | |||
u_account | varchar(50) | 否 | 用户账号 | ||
u_pwd | char(32) | 否 | 用户MD5密码 | ||
u_reg_time | datetime(8) | 否 | getdate() | 用户注册时间 | |
u_reg_ip | varchar(50) | 否 | 用户注册IP | ||
u_last_time | datetime(8) | 用户上次登录时间 | |||
u_last_ip | varchar(50) | 用户上次登录IP | |||
u_state | int(4) | 否 | 0 | 用户状态(-1已删除,0锁定,1正常),只有正常状态才允许登录 |
表1:base_user用户表
字段名称 | 数据类型 | 属性 | 允许空 | 默认值 | 备注 |
d_id | int(4) | PK AI | 否 | 部门编号 | |
d_guid | char(36) | 否 | newid() | 部门GUID | |
d_parent_guid | varchar(36) | 否 | 上级部门GUID | ||
d_name | varchar(50) | 否 | 部门名称 | ||
d_state | int(4) | 否 | 0 | 部门状态(-1已删除,0已禁用,1已启用) |
表2:base_department部门表
字段名称 | 数据类型 | 属性 | 允许空 | 默认值 | 备注 |
r_id | int(4) | PK AI | 否 | 角色编号 | |
r_guid | char(36) | 否 | newid() | 角色GUID | |
r_name | varchar(50) | 否 | 角色名称 | ||
r_state | int(4) | 否 | 0 | 角色状态(-1已删除,0已禁用,1已启用) |
表3:base_role角色表
字段名称 | 数据类型 | 属性 | 允许空 | 默认值 | 备注 |
ur_id | int(4) | PK AI | 否 | 关联编号 | |
u_guid | char(36) | 否 | 用户GUID | ||
r_guid | char(36) | 否 | 角色GUID | ||
ur_state | int(4) | 否 | 0 | 关联状态(-1已删除,0已禁用,1已启用) |
表4:map_user_role用户与角色关联表
模块、操作与权限
通过模块化设计一个应用系统,可以将系统划分为若干模块(Module:一个模块可以是一个页面、可以是一个控制器等等),每个模块包含各自的操作(Operation:一个操作可以是访问一个页面、可以是点击一个链接、可以是点击一个按钮、可以是点击一个菜单等等),一个模块的一个操作可以定义为最小粒度的权限(Power)。无论是通过点击链接或是按钮,都可以最终指向一个模块的一个操作。所有模块的通用操作我觉得基本上如下表所示:
操作编码 | 操作名称 | 操作说明 |
Add | 新增 | 添加数据 |
Delete | 删除 | 删除数据 |
Update | 修改 | 编辑数据 |
List | 列表 | 查询数据列表或访问列表页面 |
Get | 详情 | 查询数据详情或访问详情页面 |
Import | 导入 | 导入数据 |
Export | 导出 | 导出数据 |
Pass | 审核 | 审核或取消审核 |
Top | 推荐 | 推荐或取消推荐 |
表5:操作列表
图2:模块-操作-权限E-R图
字段名称 | 数据类型 | 属性 | 允许空 | 默认值 | 备注 |
m_id | int(4) | PK AI | 否 | 模块编号 | |
m_guid | char(36) | 否 | newid() | 模块GUID | |
m_parent_guid | varchar(36) | 否 | 上级模块GUID | ||
m_name | varchar(50) | 否 | 模块名称 | ||
m_state | int(4) | 否 | 0 | 模块状态(-1已删除,0已禁用,1已启用) |
表6:base_module模块表
字段名称 | 数据类型 | 属性 | 允许空 | 默认值 | 备注 |
op_id | int(4) | PK AI | 否 | 操作编号 | |
op_guid | char(36) | 否 | newid() | 操作GUID | |
op_name | varchar(50) | 否 | 操作名称 | ||
op_state | int(4) | 否 | 0 | 操作状态(-1已删除,0已禁用,1已启用) |
表7:base_operation操作表
字段名称 | 数据类型 | 属性 | 允许空 | 默认值 | 备注 |
p_id | int(4) | PK AI | 否 | 权限编号 | |
p_guid | char(36) | 否 | newid() | 权限GUID | |
m_guid | char(36) | 否 | 模块GUID | ||
op_guid | char(36) | 否 | 操作GUID | ||
p_name | varchar(50) | 否 | 权限名称 | ||
p_login | int(4) | 否 | 1 | 是否登录(1要求登录,0无需登录) | |
p_validate | int(4) | 否 | 1 | 是否验证(1验证权限,0开放权限) | |
p_state | int(4) | 否 | 0 | 权限状态(-1已删除,0已禁用,1已启用) |
表8:base_power权限表
用户、角色与权限
为各角色分配权限,则属于该角色的所有用户都将拥有这些权限。若一个用户还拥有所属角色之外的特殊权限,也可以单独为该用户分配权限,但为了统一规范权限体系,建议为这些特殊权限新建一个角色。一个用户的权限是其所属的所有角色的权限并集。
图3:角色-权限E-R图
字段名称 | 数据类型 | 属性 | 允许空 | 默认值 | 备注 |
rp_id | int(4) | PK AI | 否 | 关联编号 | |
r_guid | char(36) | 否 | 角色GUID | ||
p_guid | char(36) | 否 | 权限GUID | ||
rp_state | int(4) | 否 | 0 | 关联状态(-1已删除,0已禁用,1已启用) |
表9:map_role_power角色与权限关联表
综述
配置部门->配置角色->分配权限->添加用户并设置所在部门和所属角色。在前后端分离项目中,一个业务接口为一个操作,一类接口为一个模块,比如ASP.NET MVC WebApi中,使用控制器名作为模块编码,使用方法名为操作编码。
图4:综合E-R图
图5:程序流程图