目前开源的用户认证与鉴权方案已经比较成熟
1 单体架构
2 微服务
1 设计目标
1.1 轻量化:利用 Shiro 简化认证流程。
1.2 RBAC 模型:采用市场主流的用户-角色-资源的层级控制。
注意,RBAC 指的是 Resource-Based Access Control(基于资源)而不是 Role-Based Access Control(基于角色),它是对基于角色的权限控制模型的升级,因为在复杂系统中可能有非常多的角色,仅通过判断角色难以满足复杂的权限控制,且代码难以扩展和维护。因此,虽然角色这个概念沿用了下来,但在实现时并不是通过角色判断,角色在基于资源的权限模型中起的是分配资源的作用,通过角色找到资源,最终通过资源/路由判断用户是否能访问。
1.3 平滑演进:通过模块化设计支持未来微服务拆分。
2 技术选型
认证框架:Shiro
权限模型:RBAC + 数据权限(支持角色继承、数据行级过滤)
会话管理:Redis + JWT
密码加密:SHA-256 + Salt
3 实现细节
3.1 认证流程
- ① 用户登录(先根据用户名查询用户是否存在,再对加密后的密码进行比较验证,同时检查用户的状态,可通过 Realm 访问 DB/Redis);
- ② 登录成功后生成 JWT(包含如 userId、username、发行人、过期时间等),再放到 HttpServletResponse 的 Header 中返回给前端;
- ③ 添加自定义的 AuthInterceptor(implements HandlerInterceptor),实现 JWT 的解析和权限拦截,并放行特定的路由。
3.2 权限控制
动态权限:重写 doGetAuthorizationInfo() 方法,实时查询数据库权限。数据库设计如下:
基础表:
① tb_user:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23DROP TABLE IF EXISTS `tb_user`;
CREATE TABLE `tb_user` (
`user_id` bigint(0) NOT NULL AUTO_INCREMENT,
`username` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户名',
`password` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '密码',
`salt` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '盐',
`sex` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '性别',
`email` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '邮箱',
`phone` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '手机号',
`nickname` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '昵称',
`img_url` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '头像',
`org_id` bigint(0) NULL DEFAULT NULL COMMENT '所属机构',
`create_by` varchar(128) NULL DEFAULT NULL COMMENT '创建者',
`update_by` varchar(128) NULL DEFAULT NULL COMMENT '更新者',
`create_time` timestamp(0) NULL DEFAULT NULL COMMENT '创建时间',
`update_time` timestamp(0) NULL DEFAULT NULL COMMENT '最后更新时间',
`status` tinyint(0) NOT NULL DEFAULT 0 COMMENT '状态 0:正常 1:禁用',
`address` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '地址',
`remark` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注',
`del_flag` tinyint(0) NOT NULL DEFAULT 0 COMMENT '0:未删除 1:已删除',
PRIMARY KEY (`user_id`) USING BTREE,
UNIQUE INDEX `idx_username`(`username`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用户表' ROW_FORMAT = Dynamic;② tb_role:
1
2
3
4
5
6
7
8
9
10
11
12DROP TABLE IF EXISTS `tb_role`;
CREATE TABLE `tb_role` (
`role_id` bigint(0) NOT NULL AUTO_INCREMENT,
`role_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '角色名',
`remark` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注',
`create_by` varchar(128) NULL DEFAULT NULL COMMENT '创建者',
`update_by` varchar(128) NULL DEFAULT NULL COMMENT '更新者',
`create_time` timestamp(0) NULL DEFAULT NULL COMMENT '创建时间',
`update_time` timestamp(0) NULL DEFAULT NULL COMMENT '最后更新时间',
`del_flag` tinyint(0) NOT NULL DEFAULT 0 COMMENT '0:未删除 1:已删除',
PRIMARY KEY (`role_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '角色表' ROW_FORMAT = Dynamic;③ tb_user_role:
1
2
3
4
5
6
7DROP TABLE IF EXISTS `tb_user_role`;
CREATE TABLE `tb_user_role` (
`id` bigint(0) NOT NULL AUTO_INCREMENT,
`user_id` bigint(0) NULL DEFAULT NULL COMMENT '用户ID',
`role_id` bigint(0) NULL DEFAULT NULL COMMENT '角色ID',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用户与角色对应关系表' ROW_FORMAT = Dynamic;④ tb_menu:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18DROP TABLE IF EXISTS `tb_menu`;
CREATE TABLE `tb_menu` (
`menu_id` bigint(0) NOT NULL AUTO_INCREMENT,
`parent_id` bigint(0) NULL DEFAULT NULL COMMENT '父菜单ID,一级菜单为0',
`menu_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '菜单名',
`menu_url` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '路由',
`permissions_code` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '拥有的权限(多个用逗号分隔,如:user:list,user:info)',
`type` int(0) NULL DEFAULT NULL COMMENT '类型 0:目录 1:菜单 2:按钮',
`icon` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '菜单图标',
`menu_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '标识',
`order_num` int(0) NULL DEFAULT 0 COMMENT '排序',
`create_by` varchar(128) NULL DEFAULT NULL COMMENT '创建者',
`update_by` varchar(128) NULL DEFAULT NULL COMMENT '更新者',
`create_time` timestamp(0) NULL DEFAULT NULL COMMENT '创建时间',
`update_time` timestamp(0) NULL DEFAULT NULL COMMENT '最后更新时间',
`del_flag` tinyint(0) NOT NULL DEFAULT 0 COMMENT '0:未删除 1:已删除',
PRIMARY KEY (`menu_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '菜单表' ROW_FORMAT = Dynamic;⑤ tb_role_menu:
1
2
3
4
5
6
7DROP TABLE IF EXISTS `tb_role_menu`;
CREATE TABLE `tb_role_menu` (
`id` bigint(0) NOT NULL AUTO_INCREMENT,
`role_id` bigint(0) NULL DEFAULT NULL COMMENT '角色ID',
`menu_id` bigint(0) NULL DEFAULT NULL COMMENT '菜单ID',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '角色与菜单对应关系表' ROW_FORMAT = Dynamic;扩展表(待研究):
① tb_data_scope:
1
2
3
4
5
6DROP TABLE IF EXISTS `tb_data_scope`;
CREATE TABLE `tb_data_scope` (
`user_id` bigint(0) NOT NULL AUTO_INCREMENT,
`username` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户名',
PRIMARY KEY (`user_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '扩展表' ROW_FORMAT = Dynamic;
在代码中通过 Shiro 注解控制权限(如 @RequiresPermissions(“user:delete”))。
3.3 优化措施
- Redis 记录登录失败次数,超过限制锁定账户(防暴力破解)。
- 集成 Shiro 的 HttpServletRequestWrapper(防 XSS/CSRF)。
- Redis 缓存角色-权限关系,设置 TTL(如 10 分钟)。
- 监控登录接口响应时间和权限缓存命中率。