利用Spring HandlerInterceptor和RequestMapping注解进行权限访问控制
程序员文章站
2022-06-07 15:22:28
...
注意:本文仅适用于以@RequestMapping注解为基础的Spring MVC项目,并且权限控制粒度和RequestMapping标注的方法一一对应的情况
最近一直在思考权限拦截系统如何实现,在Restful的时代,我们认为一个url就是一个资源,而对于Spring来说,每个@RequestMapping标注的方法应该就对应了一个操作行为。如何配置用户权限信息让用户在到达每个操作行为前就判断用户是否有进行当前操作的权限就是需要解决的问题。
最开始是将url+method分别写入数据库作为一个operation,然后给角色分配这些operation,用户登陆的时候只需要加载自己所具有的operations,登陆的时候进行判断url是否matching就可以了。目前也是这样做的。
更多思考:
1.我们的url,method,甚至是parameter和header定义都可以写到@RequestMapping注解内,我们有必要到数据库重复一遍吗?
2.url包含通配符或者PathVariable的时候,哪怕使用AntPathMatcher也可能出现一条url映射出多个urlPattern的情况,选择最优匹配能不能和Spring的结果一致?而Spring MVC总是能为我们的请求找到对应的方法,我们能不能交给Spring去做好这件事?
我查看了Spring的源码,也进行了一些断点测试,最终发现,在HandlerInterceptorAdapter的preHandle方法的handler参数中(需要强制转换为HandlerMethod对象),已经包含了Spring为我们查找到的method对象。
就此我产生了一个灵感,method对象是可以获得所有注解的,我们可以自己实现一个注解类来标识每一个RequestMapping,也就是赋予ID,然后在数据库中将这些ID和角色进行关联,只需要在preHandle方法中取得这个id,然后验证当前用户是否具有这个id就能够判断用户是否具有权限,并依此决定是否放行!
现在的问题就转换为如何同步数据库和应用程序中的这些ID,Spring已经为我们提供了一个解决方案,就是BeanPostProcessor接口。
在Spring实例化每个controller的时候进行介入读取所有的ID并缓存,在系统完全启动后触发ApplicationListener中的ContextRefreshEvent事件,这时我们可以和数据库中的id进行比对,删除已经不存在的关联,并提醒管理员关联新增的operation id。
考虑到修改程序才可能会修改id配置,而这个id配置对系统访问的操作也没有影响,所以可以规定id一旦被设置就不能被修改,只能删除或新增。而这个频率也不会很高,因此依然在可以接受的范围内。
ps:这个思路还可以实现url白名单、黑名单哦,也欢迎提供别的应用思路。
最近一直在思考权限拦截系统如何实现,在Restful的时代,我们认为一个url就是一个资源,而对于Spring来说,每个@RequestMapping标注的方法应该就对应了一个操作行为。如何配置用户权限信息让用户在到达每个操作行为前就判断用户是否有进行当前操作的权限就是需要解决的问题。
最开始是将url+method分别写入数据库作为一个operation,然后给角色分配这些operation,用户登陆的时候只需要加载自己所具有的operations,登陆的时候进行判断url是否matching就可以了。目前也是这样做的。
更多思考:
1.我们的url,method,甚至是parameter和header定义都可以写到@RequestMapping注解内,我们有必要到数据库重复一遍吗?
2.url包含通配符或者PathVariable的时候,哪怕使用AntPathMatcher也可能出现一条url映射出多个urlPattern的情况,选择最优匹配能不能和Spring的结果一致?而Spring MVC总是能为我们的请求找到对应的方法,我们能不能交给Spring去做好这件事?
我查看了Spring的源码,也进行了一些断点测试,最终发现,在HandlerInterceptorAdapter的preHandle方法的handler参数中(需要强制转换为HandlerMethod对象),已经包含了Spring为我们查找到的method对象。
就此我产生了一个灵感,method对象是可以获得所有注解的,我们可以自己实现一个注解类来标识每一个RequestMapping,也就是赋予ID,然后在数据库中将这些ID和角色进行关联,只需要在preHandle方法中取得这个id,然后验证当前用户是否具有这个id就能够判断用户是否具有权限,并依此决定是否放行!
现在的问题就转换为如何同步数据库和应用程序中的这些ID,Spring已经为我们提供了一个解决方案,就是BeanPostProcessor接口。
在Spring实例化每个controller的时候进行介入读取所有的ID并缓存,在系统完全启动后触发ApplicationListener中的ContextRefreshEvent事件,这时我们可以和数据库中的id进行比对,删除已经不存在的关联,并提醒管理员关联新增的operation id。
考虑到修改程序才可能会修改id配置,而这个id配置对系统访问的操作也没有影响,所以可以规定id一旦被设置就不能被修改,只能删除或新增。而这个频率也不会很高,因此依然在可以接受的范围内。
ps:这个思路还可以实现url白名单、黑名单哦,也欢迎提供别的应用思路。