当前位置:首页 > 时尚

springaop注解实现权限验证

Spring AOP注解实现权限验证

直接说结论:用Spring AOP配合自定义注解做权限校验,注证比在业务代码里写if-else判断要干净得多。解实我接手过一个老项目,现权限验每个Controller方法开头都堆着三五行权限判断,注证改个权限逻辑要动几十处,解实后来全部重构为注解+AOP,现权限验代码量直接砍掉一半。注证

先定义一个权限注解。解实这个注解要能接收参数,现权限验比如模块编码和操作类型。注证我用的解实是@Permission,里面放两个字段:module表示资源模块,现权限验action表示具体操作(增删改查之类)。注证注解标在Controller方法上,解实谁需要权限就标谁,现权限验不标的方法默认放行——这比全局拦截再白名单要灵活,新接口忘加注解也不会误伤。

 @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface Permission {  String module(); String action(); } 

核心是切面。我用@Around环绕通知,因为权限验证失败时要直接抛出异常中断请求。切点表达式直接匹配@annotation,Spring会把方法上的注解实例传进来,不用反射再去拿,省事。切面里先拿到当前登录用户,从Redis里取他的权限集合——注意别每次请求都查数据库,这性能损耗扛不住。

验证逻辑很简单:拼出"module:action"字符串,看用户权限集合里有没有。没有就抛自定义的PermissionDeniedException,由全局异常处理器转成403响应。有就放行。这里有个坑:权限集合为空时要特殊处理,否则用户没任何权限时所有接口都进不去,连登录接口都被切面拦了——别问我怎么知道的。

细节上还得考虑注解的优先级。如果类和方法的注解都有,方法上的应该覆盖类上的。我在切面里先取方法注解,取不到再取类注解。实际业务里经常有这种需求:整个Controller默认需要某个权限,个别方法放宽。用注解继承设计就行,别把逻辑写死在切面里。

另一个实际问题是权限粒度。我见过有人一个注解里塞五个参数,搞出十几种组合,结果切面里全是if-else判断。这违背了AOP的初衷。权限注解就应该简单——模块加操作,最多再加个数据范围。复杂规则就拆成多个注解叠着用,或者直接走表达式引擎。

这套方案跑了一年多,最明显的改善是新人写接口时不用再关心权限逻辑,只管在方法上标个注解。出问题也好排查,直接看注解参数就知道这个接口要求什么权限,比翻业务代码找逻辑直观太多。当然,注解权限验证只解决了"能不能调用"的问题,数据级的行权限过滤还得靠MyBatis拦截器或者领域层校验,那是另一个话题了。

分享到: