Hyperf自定义注解,aop切面实现接口参数校验

1.自定义注解

<?php

namespace App\Annotation;


use Hyperf\Di\Annotation\AbstractAnnotation;

/**
 * @Annotation
 * @Target({"CLASS","METHOD"}) #CLASS 参考问档
 */
class ValidateParams extends AbstractAnnotation
{


}

2.创建aop切面

<?php

namespace App\Aspect;

use App\Annotation\ValidateParams;
use App\common\response\SystemCode;
use App\Exception\ValidateException;
use Hyperf\Di\Annotation\Aspect;
use Hyperf\Di\Annotation\Inject;
use Hyperf\Di\Aop\AbstractAspect;
use Hyperf\Di\Aop\ProceedingJoinPoint;
use Hyperf\HttpServer\Router\Dispatched;
use Hyperf\Logger\LoggerFactory;
use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\Validation\Contract\ValidatorFactoryInterface;
use Psr\Container\ContainerInterface;


/**
 * @Aspect
 */
class ValidateAspect extends AbstractAspect
{

    protected $container;

    protected $request;

    protected $logger;

    /**
     * @Inject()
     * @var ValidatorFactoryInterface
     */
    protected $validationFactory;

    public function __construct(ContainerInterface $container, RequestInterface $request, LoggerFactory $logger)
    {
        $this->container = $container;
        $this->request = $request;
        $this->logger = $logger->get('log', 'default');
    }

    // 要切入的类或 Trait,可以多个,亦可通过 :: 标识到具体的某个方法,通过 * 可以模糊匹配
    /*public $classes = [
        'App\Controller\TestController::*Method',
    ];*/

    // 要切入的注解,具体切入的还是使用了这些注解的类,仅可切入类注解和类方法注解
    public $annotations = [
        ValidateParams::class,
    ];

    /**
     * @inheritDoc
     */
    public function process(ProceedingJoinPoint $proceedingJoinPoint)
    {
        // 在调用前进行某些处理
        $this->logger->info(date('Y-m-d H:i:s', time()),["ValidateParams注解调用前执行..."]);
        //获取控制器和方法
        list($LongController, $method) = $this->request->getAttribute(Dispatched::class)->handler->callback;
        $controller = substr(substr(strrchr($LongController,'\\'),1),0,-10);
        $res = $this->paramsValidate($controller,$method,$this->request);
        if($res["code"] === -1){
            //return RespResult::result(SystemCode::SYSTEM_ERROR_PARAM_NULL,$res["data"],[]);//方式1
            throw new ValidateException($res["data"],SystemCode::SYSTEM_ERROR_PARAM_NULL);//方式2
        }

        $result = $proceedingJoinPoint->process();

        // 在调用后进行某些处理
        $this->logger->info(date('Y-m-d H:i:s', time()),["ValidateParams注解调用后执行..."]);
        return $result;
    }


    /**
     * 参数校验函数
     * @param $controller
     * @param $method
     * @param $request
     * @return array
     */
    private function paramsValidate($controller,$method,$request){
        $nameSpace = '\App\Vilidate\\'.$controller;
        $ValidateObj = (new $nameSpace)->$method;
        $validator = $this->validationFactory->make(
            $request->all(),$ValidateObj["rule"],$ValidateObj["msg"]
        );
        if ($validator->fails()){
            // Handle exception
            $errorMessage = $validator->errors()->first();
            return ["code"=>-1,"msg"=>"校验不通过!","data"=>$errorMessage];
        }
        //校验通过
        return ["code"=>0,"msg"=>"校验通过!","data"=>[]];
    }
}

3.添加校验规则

<?php

namespace App\Vilidate;

/**
 * test控制器下的验证规则类
 */
class Test
{

    public $index = [
        'rule'=>[
        ],
        'msg'=>[
        ]
    ];


    public $exceptionTest = [
        'rule'=>[
            'title' => 'required|max:5',
            'body' => 'required',
        ],
        'msg'=>[
            'title.required' => 'title参数不能为空!',
            'title.max' => 'title最大长度超限',
            'body.required' => 'body参数不能为空!',
        ]
    ];



    public $eventTest = [
        'rule'=>[
            'title' => 'required|max:5',
            'body' => 'required',
        ],
        'msg'=>[
            'title.required' => 'title参数不能为空!',
            'title.max' => 'title最大长度超限',
            'body.required' => 'body参数不能为空!',
        ]
    ];

    public $getUser = [
        'rule'=>[
            'userId' => 'required|min:0|numeric',
        ],
        'msg'=>[
            'userId.required' => 'userId参数不能为空!',
            'userId.numeric' => 'userId格式必须为数字!',
            'userId.min' => 'userId最小长度超限',
        ]
    ];

    public $validateTest = [
        'rule'=>[
            'userId' => 'required|min:0|numeric',
        ],
        'msg'=>[
            'userId.required' => 'userId参数不能为空!',
            'userId.numeric' => 'userId格式必须为数字!',
            'userId.min' => 'userId最小长度超限',
        ]
    ];


}

4.使用

/**
     * @RequestMapping(path="/validateTest", methods="get,post")
     * @ValidateParams
     * @param RequestInterface $request
     * @return array
     */
    public function validateTest(RequestInterface $request)
    {
        $params = $request->all();
        $userId = $params["userId"];
        return RespResult::result(SystemCode::SYSTEM_SUCCESS, SystemMessage::SYSTEM_SUCCESS, $this->userModel->getUser($userId));
    }

5.检验是否可以拦截

在这里插入图片描述

注:用到的注解,一定要use引进来哈

  • 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、付费专栏及课程。

余额充值