SpringBoot uri统一权限管理
业务需求:为了增加系统的安全性,系统的任意一个接口均要做权限拦截验证。
1. 表结构定义
CREATE TABLE `sys_uri` (
`id` bigint(11) NOT NULL AUTO_INCREMENT COMMENT 'id',
`bean_name` varchar(128) DEFAULT NULL COMMENT 'controller类名',
`uri` varchar(256) DEFAULT NULL COMMENT '访问地址',
`clazz_name` varchar(256) DEFAULT NULL COMMENT '类名',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=44 DEFAULT CHARSET=utf8 COMMENT='系统uri记录表';
CREATE TABLE `role_uri_authority` (
`id` bigint(11) NOT NULL AUTO_INCREMENT COMMENT 'id 自增',
`role_id` bigint(11) NOT NULL COMMENT '角色id,对应角色表roles主键',
`sys_uri_id` bigint(11) NOT NULL COMMENT 'sys_uri表中的主键id',
PRIMARY KEY (`id`),
KEY `role_id` (`role_id`),
KEY `sys_uri_id` (`sys_uri_id`)
) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=utf8 COMMENT='角色uri权限访问表';
2. 自动统计URI,并自动删除脏数据
直接上service,
@Service
public class UriInitServiceImpl implements UriInitService {
// 排除swagger与其他内置的uri;排序用户登录模块,以及内部测试模块controller
private static final List<String> excludesControllerList =
Stream.of("apiResourceController", "knife4jController", "basicErrorController", "loginController", "thymeleafTest", "testController").collect(Collectors.toList());
// SpringBoot 内置对象,可获取controller所有的uri信息
@Autowired
private RequestMappingHandlerMapping requestMappingHandlerMapping;
// 逆向工程自动生成dao
@Autowired
private RoleUriAuthMapperExt roleUriAuthMapperExt;
// 逆向工程自动生成dao
@Autowired
private SysUriMapperExt sysUriMapperExt;
private Date sysDate;
@Transactional
@Override
public void initSysUri() {
// 全量uri
List<SysUri> sysUriList = new ArrayList<>();
sysDate = new Date();
// 获取系统所有的uri信息
Map<RequestMappingInfo, HandlerMethod> handlerMethodsMap = requestMappingHandlerMapping.getHandlerMethods();
for (Map.Entry<RequestMappingInfo, HandlerMethod> item : handlerMethodsMap.entrySet()) {
saveUriMap(sysUriList, item);
}
// 原有的存量数据
List<SysUri> oldSysUriList = sysUriMapperExt.selectByExample(new SysUriExample());
// sysUriList - oldSysUriList 新增差集
List<SysUri> addSysUriList = sysUriList.stream()
.filter(s -> !oldSysUriList.stream()
.map(os -> os.getUri()).collect(Collectors.toList()).contains(s.getUri()))
.collect(Collectors.toList());
// oldSysUriList - sysUriList 移除差集
List<Long> reduceSysUriIdList = oldSysUriList.stream()
.filter(os -> !sysUriList.stream()
.map(s -> s.getUri()).collect(Collectors.toList()).contains(os.getUri())).map(item -> item.getId())
.collect(Collectors.toList());
// sysUri 新增
if (!CollectionUtils.isEmpty(addSysUriList)) {
sysUriMapperExt.batchInsert(addSysUriList);
}
// sysUri,roleUriAuth删除已清除的uri
if (!CollectionUtils.isEmpty(reduceSysUriIdList)) {
SysUriExample example = new SysUriExample();
example.createCriteria().andIdIn(reduceSysUriIdList);
sysUriMapperExt.deleteByExample(example);
RoleUriAuthExample roleUriAuthExample = new RoleUriAuthExample();
roleUriAuthExample.createCriteria().andSysUriIdIn(reduceSysUriIdList);
roleUriAuthMapperExt.deleteByExample(roleUriAuthExample);
}
}
// 过滤映射转换
private void saveUriMap(List<SysUri> sysUriList, Map.Entry<RequestMappingInfo, HandlerMethod> item) {
RequestMappingInfo uriMappingInfo = item.getKey();
HandlerMethod value = item.getValue();
String uri = uriMappingInfo.getPatternsCondition().toString();
// 类名:xxxController
String beanName = value.getBean().toString();
// clazz全路径名称
String clazzName = value.getBeanType().getName();
if (!excludesControllerList.contains(beanName)) {
SysUri sysUri = new SysUri();
sysUri.setBeanName(beanName);
sysUri.setUri(uri);
sysUri.setClazzName(clazzName);
sysUri.setCreateTime(sysDate);
sysUriList.add(sysUri);
}
}
}
3. 程序启动加载
@Service
public class StartupListener implements ApplicationListener<ContextRefreshedEvent> {
private Logger logger = LoggerFactory.getLogger(StartupListener.class);
@Autowired
private UriInitService uriInitService;
/**
* 触发机制
* 容器中所有的bean初始化完成之后执行
*
* @param evt
*/
@Override
public void onApplicationEvent(ContextRefreshedEvent evt) {
try {
// 保证只执行一次
if (evt.getApplicationContext().getParent() == null) {
// 程序启动初始化uri
uriInitService.initSysUri();
}
} catch (Exception e) {
logger.error("onApplicationEvent error {}", e.getMessage());
// 异常 强制关闭启动
throw new RuntimeException(e.getMessage());
}
}
}
4. 结果
5. 其他
以上为各个系统通用模块。
其他拦截器验证业务,缓存等代码根据自身系统开发。