缘起

最近在写代码时,不可避免的会写成出进行大量的鉴权逻辑。 如下面代码所示,每一个方法都要添加一个鉴权逻辑(样例只有4个方法,实际工作中会很多)

class Action{public void get() {checkRights(); //鉴权代码//业务代码}public void put() {checkRights(); //鉴权代码//业务代码}public void delete() {checkRights(); //鉴权代码//业务代码}public void post() {checkRights(); //鉴权代码//业务代码}
}

作为一个善于偷懒的码农,看到如上代码应该会敏锐得意识到‘Don't repeat yourself’的编程箴言了,重复代码带来的问题,我就不再累述了,相信大家都身受其害。

如何解决呢?

那么该如何消除到这些大量烦人的重复逻辑呢。 有的同学可能已经想到了,可以在web框架的流水线中增加一个鉴权处理器,这的确是一个可行方案,我们这里就不详细解释了。 这里给出另外一个利用AOP进行重复代码消除的技术,那么什么是AOP呢?

这里说下个人比较粗浅的理解:AOP(Aspect-Oriented Programming)面向切面编程,是一种根据位置描述规则(Pointcut切点)把代码(Advice)添加(织入weav)到指定位置的技术。 通过 (位置描述规则 + 代码)把散落在代码中的重复逻辑提取出来,对重复代码完成的这形式的抽象就叫AOP。

AOP在天然支持元编程的语言里面(如lisp),很容易直接写代码实现。 但是在大部分不支持元编程的语言,就由各种工具或框架各显神通了,如C++里面有AspectC++等。 在java世界中有2个著名的实现一个是经典全能版的AspectJ、另外一个阉割版的Spring AOP。 我们的项目使用spring,一开始很自然的想使用 SpringAOP,但是很不幸 SpringAOP 仅支持容器管理对象的AOP,这无法满足我的需求。 所以只能使用AspectJ了。 AspectJ 有2种织入方式(使用acj编译器静态织入,使用javaagent动态织入),这里顺便提一下 javaagent技术,它允许用户在类加载前改变类的字节码,受益于java的动态能力,aspectJ可以优雅的实现动态织入技术。 AOP的核心思想是比较简单的,但是切点规则相当繁琐,不容易全面掌握,Pointcut表达式以后再详细写吧。 把AOP run起来,废了不少时间,解决了各种奇葩问题,因此现在这里写一下过程,供对AOP应用有兴趣的同学参考。

项目实践

下面以项目为例详细说明实现过程,这里使用了动态织入的方式:

增加包依赖

注意: aspectJ包的版本和java 版本一致,否则运行时会出现类被损坏的异常。 我们项目使用的java8,这个地方我掉过坑。

<dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.8.12</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjrt</artifactId><version>1.8.12</version></dependency>

classpath路径里面增加 META-INFO/aop.xml

配置很简单,一个切面类。 织入目标的包路径(注意要包含切面类的路径,否则切面类会缺少需要被织入的aspectOf()方法,这也是掉过坑的)

<?xml version="1.0"?>
<aspectj><aspects><aspect name="com.taobao.bright.service.system.auth.AclRightAspect"/></aspects><weaver options="-showWeaveInfo "><include within="com.taobao.bright.web.sre.module..*" /><include within="com.taobao.bright.service.system.auth.*" /></weaver>
</aspectj>

启动方式

有2种方式

1.  javaagent方式  (我使用的这种方式)
java "-javaagent:/Users/qiyu/.m2/repository/org/aspectj/aspectjweaver/1.8.7/aspectjweaver-1.8.7.jar"2. tomcat server.xml配置文件增加
<Context><Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"/> </Context>

实现代码样例

废话少说,放码过来!

2个注解类,一个切面类都贴出来了,供大家参考借鉴。


//权限位注解
@Repeatable(AclRightAnnotations.class)
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface AclRightAnnotation {AclRightType value() ;
}
//可以添加多个权限位的注解 (java8新特性)
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface AclRightAnnotations {AclRightAnnotation[] value() ;
}@Aspect
public class AclRightAspect {//含有AclRightAnnotation注解的目标类且为public方法 切点定义@Pointcut("@within(com.taobao.bright.service.system.auth.AclRightAnnotation) && execution(public * *(..))")public void classPointCut() {}//含有AclRightAnnotation注解的方法且为public方法 切点定义@Pointcut("@annotation(com.taobao.bright.service.system.auth.AclRightAnnotation) && execution(public * *(..))")public void actionPointCut() {}//@Around("classPointCut() || actionPointCut()")public void checkPermission(ProceedingJoinPoint joinPoint) throws Throwable {MethodSignature methodSig = (MethodSignature) joinPoint.getSignature();//通过getDeclaredAnnotationsByType反射方法,获取注解中的权限位AclRightAnnotation[] methodAnnotations = methodSig.getMethod().getDeclaredAnnotationsByType(AclRightAnnotation.class);AclRightAnnotation[] classAnnotations = joinPoint.getTarget().getClass().getDeclaredAnnotationsByType(AclRightAnnotation.class);List<AclRightAnnotation> annotations = new ArrayList<>();annotations.addAll(Arrays.asList(classAnnotations));annotations.addAll(Arrays.asList(methodAnnotations));boolean hasRight = false;String right = "";for(AclRightAnnotation acl : annotations){right= acl.value().getValue();if(AclRightCache.checkCurrentUserRight(right)){hasRight = true ;break;}}if(!hasRight){Object[] methodArgs = joinPoint.getArgs();for(Object arg: methodArgs){if (arg instanceof Context) {  //返回鉴权异常给客户端Context context = (Context) arg;Result<String> result = new Result<>();result.addActionError("No permission!");context.put(Result.KEY_SIGN, result);}}}else {joinPoint.proceed();}}
}

使用代码样例

使用起来就很简单了,直接在类或方法上增加注解就可以了。 一行代码就可以搞定这个类的注释了。如果方法上需要特殊的权限,也可以增加注解。

//权限注解可以加到类或方法上。 加在类上,会对类中所有public方法都生效。 多个权限位之间是OR的关系,即有一个权限位验证通过即可。


@AclRightAnnotation(value = AclRightType.BRIGHT_STATION_VIP_MANAGE)
class Action{public void get() {//业务代码}public void put() {//业务代码}public void delete() {//业务代码}public void post() {//业务代码}
}

AOP的使用过程大致如上,使用如上方法后消除了项目代码中大量的重复鉴权代码。欢迎各位参考交流。

终于可以向重复的鉴权代码说byebye 了 -- (玩转 AOP和Annotation )相关推荐

  1. java鉴权模块,鉴权代码示例

    本文为您介绍URL鉴权的代码示例(Python.Java.Go和PHP),您可以根据业务需要,方便的对URL进行鉴权处理. URL鉴权规则请参见 说明 代码示例中的key参数对应控制台中URL鉴权的主 ...

  2. qcloud apigateway hmac鉴权代码-go语言版本

    启动命令 编译 go build 执行 ./qcloud-apigateway-sign-demo-go 成功打印结果 x-date: Tue, 15 May 2018 03:48:52 GMT so ...

  3. 【Spring Cloud Alibaba 实战 | 总结篇】Spring Cloud Gateway + Spring Security OAuth2 + JWT 实现微服务统一认证授权和鉴权

    一. 前言 hi,大家好~ 好久没更文了,期间主要致力于项目的功能升级和问题修复中,经过一年时间这里只贴出关键部分代码的打磨,[有来]终于迎来v2.0版本,相较于v1.x版本主要完善了OAuth2认证 ...

  4. ASP.netcore MVC钉钉H5微应用(二)鉴权

    官方文档:鉴权 由于官方文档没有C#的,所以自己弄了个C#的 需要注意的是,不是所有功能都需要鉴权,但是在需要鉴权的地方,一定要有 -第一步:获得access_token 我使用的是企业内部应用 具体 ...

  5. CDN > 域名管理 > 访问控制 > URL鉴权配置 > URL鉴权

    URL鉴权 更新时间:2020-03-05 18:09:03 编辑我的收藏 URL鉴权功能主要用于保护用户站点的资源不被非法站点下载盗用.通过防盗链方法添加Referer黑名单和白名单的方式可以解决一 ...

  6. No6-6.从零搭建spring-cloud-alibaba微服务框架,添加用户鉴权逻辑,动态数据权限(使用AOP实现)等(六,no6-6)

    代码地址与接口看总目录:[学习笔记]记录冷冷-pig项目的学习过程,大概包括Authorization Server.springcloud.Mybatis Plus~~~_清晨敲代码的博客-CSDN ...

  7. 微服务网关限流鉴权-wei-fu-wu-wang-guan-xian-liu--jian-quan

    title: 微服务网关限流&鉴权 date: 2022-01-06 14:40:45.047 updated: 2022-01-06 14:40:45.047 url: https://ww ...

  8. 微服务网关鉴权:gateway使用、网关限流使用、用户密码加密、JWT鉴权

    点击上方"芋道源码",选择"设为星标" 管她前浪,还是后浪? 能浪的浪,才是好浪! 每天 10:33 更新文章,每天掉亿点点头发... 源码精品专栏 原创 | ...

  9. 微服务网关鉴权——gateway使用、网关限流使用、用户密码加密、JWT鉴权

    文章目录 微服务网关鉴权 课程目标 1.微服务网关Gateway 1.1 微服务网关概述 1.2 微服务网关微服务搭建 1.3 微服务网关跨域 1.4 微服务网关过滤器 2 网关限流 2.1 思路分析 ...

最新文章

  1. Spring DAO之Hibernate
  2. Programming WCF Services翻译笔记(四)
  3. 新手来博客,请多多指教。
  4. Illustrator 教程,如何在 Illustrator 中添加虚线和箭头?
  5. 支付宝出征世界杯!白岩松:“中国除了足球队没去,其他都去了”
  6. 1u服务器电源制作,1U服务器电源也可以做机箱电源
  7. iOS非常全的第三方库
  8. uk码对照表_36码(uk码和中国码对照表)
  9. modbus模拟器基本使用
  10. 厦门大学计算机专业录取分数线2019,厦门大学2019年各专业录取分数分析
  11. 痞子衡嵌入式:语音处理工具Jays-PySPEECH诞生记(5)- 语音识别实现(SpeechRecognition, PocketSphinx0.1.15)
  12. 数据库无法连接的几种情况
  13. 计算机刷新的作用,为何要刷新BIOS?刷新BIOS能启到什么作用?
  14. Illegal command:debug错误
  15. 将一个大文件分割为若干个小文件的方法
  16. java框架要求合同_java毕业设计_springboot框架的合同管理
  17. 【漏洞复现】shiro 反序列化 (CVE-2016-4437)
  18. java鱼雷3的几何_WFP:Geometries几何图形集合--Geometry几何图形(3)
  19. python环境搭建与配置
  20. js删除数组对象中的某个属性的方法

热门文章

  1. JVM学习:JVM对象分代晋升机制
  2. 云智能电销外呼系统,低成本解决中小企业销售难题
  3. 雷达感应人体存在,雷达感应原理
  4. FreeType 管理字形
  5. 202301读书笔记|《命运》蔡崇达
  6. 荣耀magic3会用鸿蒙,荣耀magic3怎么样-荣耀magic3配置分析
  7. Python 竟然不是最赚钱的编程语言?!
  8. 思维导图绘制就是这样简单,手把手教你绘制一幅思维导图
  9. thinkphp 点击分类显示分类下的文章(完整)
  10. Vue与Angular以及React的区别