1. 项目概述
最近在帮一家中型企业开发招聘系统时,遇到了一个典型问题:HR部门反映系统权限混乱,普通招聘专员能看到薪资审批功能,而部门经理却无法查看应聘者完整简历。这促使我深入研究了招聘系统的权限管理方案,并针对性地做了一系列安全优化。
这个基于SpringBoot+MyBatisPlus+MySQL的招聘系统,包含用户端(Uniapp)、企业端和管理后台(Vue+ElementUI)三个模块。在开发过程中,我发现权限管理不仅是简单的功能控制,更关系到企业招聘数据的安全性和业务流程的规范性。
2. 权限管理设计方案
2.1 RBAC模型实现
我们采用经典的RBAC(Role-Based Access Control)模型,通过用户-角色-权限三级结构实现灵活控制:
java复制// 数据库表结构核心设计
CREATE TABLE `sys_user` (
`id` bigint NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL COMMENT '用户名',
`password` varchar(100) NOT NULL COMMENT '密码',
PRIMARY KEY (`id`)
);
CREATE TABLE `sys_role` (
`id` bigint NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL COMMENT '角色名',
`code` varchar(50) NOT NULL COMMENT '角色编码',
PRIMARY KEY (`id`)
);
CREATE TABLE `sys_permission` (
`id` bigint NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL COMMENT '权限名称',
`url` varchar(255) DEFAULT NULL COMMENT '接口URL',
`method` varchar(10) DEFAULT NULL COMMENT '请求方法',
PRIMARY KEY (`id`)
);
// 关联表
CREATE TABLE `sys_user_role` (
`user_id` bigint NOT NULL,
`role_id` bigint NOT NULL
);
CREATE TABLE `sys_role_permission` (
`role_id` bigint NOT NULL,
`permission_id` bigint NOT NULL
);
注意:角色编码建议采用前缀命名法,如HR_DEPT_MANAGER、HR_RECRUITER等,便于后期维护和权限判断。
2.2 权限粒度控制
根据招聘业务特点,我们将权限控制分为三个层级:
- 菜单级权限:控制导航菜单可见性
- 操作级权限:控制按钮/操作可用性
- 数据级权限:控制数据访问范围
前端实现方案(Vue示例):
javascript复制// 指令方式控制按钮权限
Vue.directive('permission', {
inserted(el, binding) {
const permissions = store.getters.permissions;
if (!permissions.includes(binding.value)) {
el.parentNode.removeChild(el);
}
}
});
// 使用方式
<button v-permission="'candidate:edit'">编辑</button>
后端实现方案(Spring Security):
java复制@PreAuthorize("hasAuthority('candidate:view')")
@GetMapping("/candidates")
public Result listCandidates() {
// 业务逻辑
}
2.3 数据权限设计
招聘系统特有的数据权限需求:
| 角色类型 | 可查看简历范围 | 可操作功能 |
|---|---|---|
| 超级管理员 | 全部 | 全部 |
| HR总监 | 全部 | 除系统设置外 |
| 部门经理 | 本部门 | 本部门招聘管理 |
| 招聘专员 | 分配的任务 | 简历筛选/面试安排 |
实现方案:
java复制// 使用MyBatisPlus数据权限拦截器
public class DataPermissionInterceptor implements InnerInterceptor {
@Override
public void beforeQuery(Executor executor, MappedStatement ms,
Object parameter, RowBounds rowBounds, ResultHandler resultHandler,
BoundSql boundSql) {
// 获取当前用户数据权限范围
DataScope dataScope = SecurityUtils.getDataScope();
if (dataScope != null) {
// 拼接SQL条件
String sql = dataScope.getSql();
// 修改原始SQL
// ...
}
}
}
3. 安全优化方案
3.1 接口安全防护
-
防SQL注入:
- 使用MyBatisPlus内置防护
- 所有查询参数必须经过校验
- 示例:
java复制@GetMapping("/list") public Result list(@Valid CandidateQuery query) { // 参数自动校验 } -
XSS防护:
- 前端使用vue-sanitize处理富文本
- 后端使用Jackson转义特殊字符
-
CSRF防护:
- 启用Spring Security的CSRF保护
- 关键操作使用POST/PUT/DELETE方法
3.2 简历数据安全
-
敏感信息脱敏:
java复制public String desensitizeIdCard(String idCard) { if (StringUtils.isBlank(idCard)) return ""; return idCard.replaceAll("(\\d{4})\\d{10}(\\w{4})", "$1****$2"); } -
文件加密存储:
- 使用AES加密上传的简历文件
- 密钥分级管理
-
下载权限控制:
- 记录下载日志
- 限制下载频率
- 添加水印
3.3 审计日志设计
java复制@Aspect
@Component
public class AuditLogAspect {
@Autowired
private AuditLogService logService;
@Around("@annotation(auditLog)")
public Object around(ProceedingJoinPoint joinPoint, AuditLog auditLog) throws Throwable {
// 记录操作前
String username = SecurityUtils.getUsername();
String operation = auditLog.value();
long beginTime = System.currentTimeMillis();
Object result = joinPoint.proceed();
long time = System.currentTimeMillis() - beginTime;
// 保存日志
logService.saveLog(username, operation, time);
return result;
}
}
4. 典型问题与解决方案
4.1 权限缓存一致性问题
问题现象:修改角色权限后,部分用户仍能访问已撤销的功能。
解决方案:
- 采用两级缓存策略:
- 本地缓存(30秒过期)
- Redis缓存(权限变更时主动清除)
- 权限变更事件机制:
java复制@EventListener
public void handleRoleChangeEvent(RolePermissionChangeEvent event) {
// 清除相关缓存
redisTemplate.delete("perm:" + event.getRoleId());
}
4.2 细粒度权限性能问题
问题现象:数据权限导致SQL复杂,查询性能下降。
优化方案:
- 建立合理的部门索引
- 使用冗余字段优化查询
- 复杂查询走Elasticsearch
4.3 移动端安全加固
-
API签名验证:
java复制public boolean verifySign(HttpServletRequest request) { String timestamp = request.getHeader("Timestamp"); String sign = request.getHeader("Sign"); // 时间有效性校验(5分钟内) if (System.currentTimeMillis() - Long.parseLong(timestamp) > 300000) { return false; } // 签名校验 String serverSign = generateSign(request); return serverSign.equals(sign); } -
敏感操作二次验证:
- 关键操作需短信/邮箱验证
- 使用TOTP动态口令
5. 部署与监控建议
5.1 安全部署方案
-
网络分层:
- Web层与应用层分离
- 数据库独立网络区域
- 简历存储单独服务器
-
最小权限原则:
- 应用使用专用账户
- 数据库账户按模块划分
5.2 监控指标
| 指标类别 | 监控项 | 报警阈值 |
|---|---|---|
| 安全 | 失败登录次数 | >5次/分钟 |
| 安全 | 敏感操作次数 | >10次/小时 |
| 性能 | 接口响应时间 | >2000ms |
| 业务 | 简历下载量 | >50次/小时 |
5.3 应急响应计划
-
数据泄露处理流程:
- 立即暂停相关账户
- 追溯泄露路径
- 通知受影响用户
- 加强监控
-
系统入侵响应:
- 断开网络
- 保留日志证据
- 安全评估后恢复
在实际项目中,权限管理和安全优化不是一次性的工作,而是需要持续迭代的过程。我们团队在每次迭代时都会进行安全评审,同时建议企业客户定期进行安全审计。这套方案已经稳定运行在3家客户的生产环境中,处理了超过10万份简历数据,期间成功拦截了200+次异常访问尝试。