java aop+annotation自定义注解 实现权限控制

生活随意,笔记随记,随意参考,多多指正!

1、shiro安全框架大家都很了解,很轻便很好用,但是不管是重量级的还是轻量级的安全框架,主要是根据项目和实际场景来选择最合适的,不用无脑的去选一个最牛逼最强大的,就比如有一句话:最适合自己的才是最好的

2、最近一个项目中,由于需要写一个权限管理系统服务,这个不用像以往独立项目那样需要全方位做好防御措施,毕竟做过微服务的人都应该清楚,每一个服务各司其职,做好自己的本职工作即可,外界的请求统一交给gateway网关去管理

3、目前这个系统,我只是需要一个接口权限控制,当时想着引入shiro,后面觉得没必要,因为自身业务场景的原因,大部分shiro框架的东西是用不上的,为了用它其中某一个去把它搞出来没必要。于是就想到了JAVA AOP面向切面这一层的原理去实现,我目前只想通过权限码控制接口,单个或多个。

4、首先自定义一个注解

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface PersmissionCode {
    String[] value();
    /**
     * 默认为OR,多个值最少需要有一个符合
     * 可选AND,多个值需要同时符合
     */
    Logical logical() default Logical.OR;
}

@Target({ElementType.METHOD})说明了Annotation所修饰的对象范围,这里类型很多,不了解的就自行百度了,我只是需要用到接口上,所以用了method用于描述方法
@Retention(RetentionPolicy.RUNTIME) 这个是注解的生命周期定义,我需要在运行时去获取注解,所以用的runtime,用这个注解的时候主要看各自业务场景

以上自定义注解类里面value是一个字符串数组,因为我这次要通过权限码控制接口,这个是前后端定义好了的,所以就没去纠结别的方法,就用这个了。
而Logical是个枚举,之所以取这个名不光是它的翻译,更多的是向shiro看齐,有兴趣的可以去看看shiro的实现源码,Logical里面枚举类型为 AND 和 OR

5、现在用@Aspect和@Component做一个切面,类名看自己定义取名

@Aspect
@Component
public class AnnotationAspect {
	@Pointcut("@annotation(com.xxx.PersmissionCode)")
    public void permissionCodeAspect() {
        /*切面*/
    }
	
	 @Before("permissionCodeAspect()")
	 public void doBefore(JoinPoint joinPoint) {
		....
	}
}

@Pointcut 可以取了解一下这个注解,用来定义切点范围或者精确指定某一个切入点的,顾名思义,就是指定从哪里切入进去
@Before 这个注解也可以了解一下,这个表明多久开始执行这个切入的动作

Advice通知增强的相关注解:
@Before 在切点方法之前执行
@After 在切点方法之后执行
@AfterReturning 切点方法返回后执行
@AfterThrowing 切点方法抛异常执行
@Around 属于环绕增强,能控制切点执行前,执行后,,用这个注解后,程序抛异常,会影响@AfterThrowing这个注解

6、切面里面Advice我用before也是因为我这只需要用到before
对于@Pointcut定义的范围,我是直接以我自定义的注解名称当作切入点的,没必要对所有接口进行切入,只切有需要的部分。

7、除了@annotation指定注解,还有一种写法是定义范围,用到execution,比如execution(public * com. admin.abc.controller.*(…)) 表示匹配com. admin.abc.controller下面所有的公有方法,还有很多其他表达式写法,可以去百度了解一下。

8、在before方法里面,我们将从joinPoint里面拿到请求方法的注解,以下这个写法比较常见通用,从method当中就可以拿到注解,以及注解的内容

		Object target = joinPoint.getTarget();
        MethodSignature signature = (MethodSignature)joinPoint.getSignature();

        Method method = null;
        try {
            method = target.getClass().getMethod(signature.getName(),signature.getMethod().getParameterTypes());
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }

9、这个isAnnotationPresent是判断注解是否存在的方法,当拿到method后可以拿来判断,在这里可以不用,因为切点就是从指定注解进去的,如果定义的切点是controller层所有接口,那么这个得判断一下,有指定注解的再做相应处理。还是那句话,结合项目实际场景,选择最适合的方法,没有最好的处理方法,只有适合的和更适合的!

boolean annotationPresent = method.isAnnotationPresent(PersmissionCode.class);

可以通过以下方式拿到注解的值

PersmissionCode persmissionCode = method.getAnnotation(PersmissionCode.class);

/*
 *persmissionCode .value()  和 persmissionCode.logical()便是拿到的值了
 */

10、最后,加上了权限注解的相关接口拦截到了,注解值也能获取,剩下的就是看自己需要怎么去判断是否匹配权限了。比如我会拿当前用户的权限code与给接口加上的权限code作比较。Logical 在这里也能派上用场,和shiro一样,一个接口的权限注解定义了多个值,如果是AND,那么用户必须匹配上接口定义的所有权限才能访问接口,如果是OR,满足其中一个code即可访问接口。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
首先,我们需要定义一个自定义注解 `@RequiresPermissions`,用于标识需要授权访问的方法,例如: ```java @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface RequiresPermissions { String[] value(); // 权限值 } ``` 然后,我们需要实现一个切面,用于拦截被 `@RequiresPermissions` 标识的方法,并进行权限校验,例如: ```java @Component @Aspect public class PermissionCheckAspect { @Autowired private AuthService authService; @Around("@annotation(requiresPermissions)") public Object checkPermission(ProceedingJoinPoint joinPoint, RequiresPermissions requiresPermissions) throws Throwable { // 获取当前用户 User user = authService.getCurrentUser(); if (user == null) { throw new UnauthorizedException("用户未登录"); } // 获取当前用户的权限列表 List<String> permissions = authService.getUserPermissions(user); // 校验权限 for (String permission : requiresPermissions.value()) { if (!permissions.contains(permission)) { throw new ForbiddenException("没有访问权限:" + permission); } } // 执行目标方法 return joinPoint.proceed(); } } ``` 在切面中,我们首先通过 `AuthService` 获取当前用户及其权限列表,然后校验当前用户是否拥有被 `@RequiresPermissions` 标识的方法所需的所有权限,如果没有则抛出 `ForbiddenException` 异常,如果有则继续执行目标方法。 最后,我们需要在 Spring 配置文件中启用 AOP 自动代理,并扫描切面所在的包,例如: ```xml <aop:aspectj-autoproxy /> <context:component-scan base-package="com.example.aspect" /> ``` 这样,我们就通过 Spring AOP 和自定义注解模拟实现了类似 Shiro 权限校验的功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值