在Shiro权限管理中,数据库设计是核心环节,合理的表结构能高效支撑用户认证与授权流程,通常需要设计用户表(user)、角色表(role)、权限表(permission)及关联表(如用户-角色、角色-权限),通过多对多关系实现灵活的权限分配,以下从表结构设计、字段说明、数据关联及实际应用场景展开详细说明。
核心表结构设计
用户表(user)
存储用户基础信息,作为认证主体,核心字段包括:
| 字段名 | 类型 | 描述 | 约束条件 |
|—————-|————–|——————————-|—————————|
| id | BIGINT | 用户ID,主键 | 自增,非空 |
| username | VARCHAR(50) | 用户名(登录账号) | 唯一,非空 |
| password | VARCHAR(100) | 密文密码(建议加盐哈希存储) | 非空 |
| salt | VARCHAR(32) | 密码盐值 | 非空 |
| status | TINYINT | 用户状态(0-禁用,1-正常) | 默认1,非空 |
| create_time | DATETIME | 创建时间 | 默认当前时间 |
| update_time | DATETIME | 更新时间 | 默认当前时间 |
说明:密码字段需存储加密后的值(如MD5+盐),避免明文存储;status字段用于控制用户是否可登录,实现逻辑删除。
角色表(role)
定义系统角色,如管理员、普通用户等,字段如下:
| 字段名 | 类型 | 描述 | 约束条件 |
|—————-|————–|——————————-|—————————|
| id | BIGINT | 角色ID,主键 | 自增,非空 |
| role_name | VARCHAR(50) | 角色名称(如“超级管理员”) | 唯一,非空 |
| role_key | VARCHAR(50) | 角色标识(如“admin”) | 唯一,用于代码判断 |
| description | VARCHAR(200) | 角色描述 | 可空 |
| create_time | DATETIME | 创建时间 | 默认当前时间 |
说明:role_key需与代码中的角色标识一致,方便Shiro授权时通过字符串匹配。
权限表(permission)
定义具体权限资源,如菜单、按钮、API接口等:
| 字段名 | 类型 | 描述 | 约束条件 |
|—————-|————–|——————————-|—————————|
| id | BIGINT | 权限ID,主键 | 自增,非空 |
| permission_name| VARCHAR(50) | 权限名称(如“用户查询”) | 非空 |
| permission_key | VARCHAR(100) | 权限标识(如“user:list”) | 唯一,对应资源路径 |
| resource_type | TINYINT | 资源类型(0-菜单,1-按钮) | 默认0,非空 |
| parent_id | BIGINT | 父级权限ID(用于构建树形结构)| 可空,默认0 |
| path | VARCHAR(200) | 资源路径(如“/system/user”) | 可空 |
| create_time | DATETIME | 创建时间 | 默认当前时间 |
说明:resource_type区分菜单和按钮权限,parent_id实现权限层级管理,如“用户管理”菜单下包含“新增”“删除”按钮。
关联表设计
(1)用户-角色关联表(user_role)
字段名 | 类型 | 描述 | 约束条件 |
---|---|---|---|
id | BIGINT | 主键 | 自增,非空 |
user_id | BIGINT | 用户ID(外键) | 关联user.id,非空 |
role_id | BIGINT | 角色ID(外键) | 关联role.id,非空 |
索引:需建立(user_id, role_id)联合索引,提升查询效率。
(2)角色-权限关联表(role_permission)
字段名 | 类型 | 描述 | 约束条件 |
---|---|---|---|
id | BIGINT | 主键 | 自增,非空 |
role_id | BIGINT | 角色ID(外键) | 关联role.id,非空 |
permission_id | BIGINT | 权限ID(外键) | 关联permission.id,非空 |
索引:需建立(role_id, permission_id)联合索引。
数据关联与Shiro集成逻辑
认证流程
用户登录时,Shiro通过Realm
的doGetAuthenticationInfo
方法从user表查询用户信息,验证密码(比对加密后的密码与salt)。授权流程
用户访问资源时,Shiro通过doGetAuthorizationInfo
方法:- 先根据user_id从user_role表查询角色列表;
- 再根据role_id从role_permission表查询权限标识(permission_key);
- 最终将权限标识封装到
AuthorizationInfo
中,与当前请求的资源路径比对,判断是否有权限。
权限数据初始化
系统初始化时,可通过SQL脚本插入基础数据,-- 插入超级管理员角色 INSERT INTO role (role_name, role_key) VALUES ('超级管理员', 'admin'); -- 插入“用户查询”权限 INSERT INTO permission (permission_name, permission_key, resource_type) VALUES ('用户查询', 'user:list', 1); -- 关联角色与权限 INSERT INTO role_permission (role_id, permission_id) VALUES (1, 1);
扩展设计建议
- 缓存优化:频繁查询的权限数据(如用户角色)可通过Redis缓存,减少数据库压力。
- 动态权限:若需支持动态权限(如按部门分配),可扩展表结构,增加部门字段或设计独立的权限分配策略表。
- 数据隔离:多租户场景下,user表需增加tenant_id字段,实现数据隔离。
相关问答FAQs
Q1:Shiro权限数据库中,用户密码为什么要加盐存储?
A1:加盐存储是为了增强密码安全性,通过为每个用户生成唯一的随机盐值(salt),与密码组合后再进行哈希(如MD5、SHA256),即使两个用户密码相同,存储的哈希值也不同,可有效防止彩虹表攻击,密码“123456”对应用户A的盐值“salt1”和用户B的盐值“salt2”,最终存储的密文完全不同,破解难度大幅提升。
Q2:如何通过数据库实现Shiro的动态权限控制(如根据用户状态实时禁用权限)?
A2:可通过以下方式实现:
- 实时状态校验:在Shiro的Realm中,每次授权时查询user表的status字段,若为0(禁用),则直接返回空权限集合,拒绝访问。
- 缓存失效机制:若使用缓存(如Redis),当用户状态变更时,主动清除该用户的缓存权限数据(如通过CacheManager.remove(user)),确保下次请求时重新从数据库加载最新状态。
- SQL动态过滤:在查询用户权限时,关联user表并添加status=1的条件,避免禁用用户的权限被加载到缓存中。
SELECT p.permission_key FROM permission p JOIN role_permission rp ON p.id = rp.permission_id JOIN role r ON rp.role_id = r.id JOIN user_role ur ON r.id = ur.role_id JOIN user u ON ur.user_id = u.id WHERE u.id = #{userId} AND u.status = 1;
【版权声明】:本站所有内容均来自网络,若无意侵犯到您的权利,请及时与我们联系将尽快删除相关内容!
发表回复