统一认证系统实现要点-资源认证

时间:2022-09-02 14:27:05
权限系统有一个普遍的需求,即:用户登录系统后,在浏览器地址栏直接输入未经授权的URL,应该拒绝其访问。
目前有很多线程的权限框架对这部分进行了封装,如shiro,但是如果不想引入新框架,保持系统的轻量,该如何做呢?

对于普通Spring MVC项目来说,每个@RequestMapping标注的方法应该就对应了一个操作行为。
如何配置用户权限信息让用户在到达每个操作行为前就判断用户是否有进行当前操作的权限就是需要解决的问题。  
最终目的是保持唯一性,以及访问URL的时候,能获取当前访问的资源的权限代码是什么,从而验证权限。

方式一
最开始是给每个资源定义了一个权限代码,该权限代码在应用中保持唯一,采用约定优于配置的方式,该权限代码即URL中除去IP,端口,上下文,余下的部分。给角色分配资源的时候,自然就等于分配了这些权限代码。访问的时候,通过URL拿到权限代码,验证是否有权限即可。权限代码的组成多种多样,根据系统需要,也可以将 url+method作为权限代码。

方式二
我们的url,method,甚至是parameter和header定义都可以写到@RequestMapping注解内,我们有必要到数据库重复一遍吗?  
url包含通配符或者PathVariable的时候,哪怕使用AntPathMatcher也可能出现一条url映射出多个urlPattern的情况,选择最优匹配能不能和Spring的结果一致?而Spring MVC总是能为我们的请求找到对应的方法,我们能不能交给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。 

相比之下方式二更加优雅。