hyperf按钮权限验证

本文介绍了如何在Hyperf框架下创建Permission注解和PermissionMiddleware中间件,用于实现权限控制。通过注解定义接口访问权限,并在中间件中检查用户权限,确保只有拥有相应权限的用户才能执行特定操作。同时,文章涵盖了用户、角色、权限和菜单等表的设计,展示了完整的权限管理体系。
摘要由CSDN通过智能技术生成

CREATE TABLE `auths` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `role_id` int(11) NOT NULL DEFAULT '0' COMMENT '角色ID',
  `menu_id` int(11) NOT NULL DEFAULT '0' COMMENT '菜单ID',
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `updated_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10462 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='权限表'

CREATE TABLE `menu` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `pid` int(11) NOT NULL DEFAULT '0' COMMENT '父类ID',
  `name` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '菜单名称',
  `icon` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '菜单图标',
  `url` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '菜单地址',
  `level` tinyint(3) unsigned NOT NULL DEFAULT '1' COMMENT '菜单等级',
  `type` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '菜单类型,0菜单,1按钮',
  `sign` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '标识',
  `sort` int(11) NOT NULL DEFAULT '0' COMMENT '菜单排序,越小越靠前',
  `hide_in_menu` tinyint(4) NOT NULL DEFAULT '0',
  `hide_in_bread` tinyint(4) NOT NULL DEFAULT '0',
  `not_cache` tinyint(4) NOT NULL DEFAULT '1',
  `params` json DEFAULT NULL,
  `query` json DEFAULT NULL,
  `component` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `remark` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '菜单描述',
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `updated_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=498 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='菜单表'

CREATE TABLE `role` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `level` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '角色创建级别,0系统',
  `name` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '角色名称',
  `remark` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '角色描述',
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `updated_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=104 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='角色表'

CREATE TABLE `role_user` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `role_id` int(11) NOT NULL DEFAULT '0' COMMENT '角色ID',
  `user_id` int(11) NOT NULL DEFAULT '0' COMMENT '用户ID',
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `updated_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `role_id` (`role_id`)
) ENGINE=InnoDB AUTO_INCREMENT=69 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户角色表'

CREATE TABLE `user` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `account` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '系统生成账号',
  `level` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '0系统用户',
  `username` varchar(50) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '用户名',
  `user_pass` varchar(64) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '用户密码',
  `user_salt` varchar(32) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '密码盐值',
  `email` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '邮箱地址',
  `mobile` varchar(50) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '手机号码',
  `login_name` varchar(50) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '登录名称',
  `avatar` longtext COLLATE utf8mb4_unicode_ci,
  `reg_time` int(10) unsigned NOT NULL,
  `reg_ip` varchar(45) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `login_time` int(10) unsigned NOT NULL DEFAULT '0',
  `login_ip` varchar(45) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `expire_at` int(10) unsigned NOT NULL COMMENT '用户账号有效时间',
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `updated_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `user_account_unique` (`account`),
  UNIQUE KEY `user_username_unique` (`username`)
) ENGINE=InnoDB AUTO_INCREMENT=91 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户表'

1.首先创建 Permission.php注解

<?php declare(strict_types=1);

namespace App\Annotation;

use Hyperf\Di\Annotation\AbstractAnnotation;

/**
 * @Annotation
 * @Target({"METHOD"})
 */
class Permission extends AbstractAnnotation
{
    /**
     * 权限名称
     * @var string
     */
    public $value;

    /**
     * 接口访问地址
     * @var string
     */
    public $path;
}

2.接着创建PermissionMiddleware.php 中间件

<?php

declare(strict_types=1);

namespace App\Middleware;

use App\Annotation\Permission;
use Dpot\DpotInterface\Admin\UserServiceInterface;
use Hyperf\Di\Annotation\AnnotationCollector;
use Hyperf\HttpMessage\Stream\SwooleStream;
use Hyperf\Utils\Context;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;

class PermissionMiddleware implements MiddlewareInterface
{
    /**
     * @var ContainerInterface
     */
    protected $container;

    /**
     * @var UserServiceInterface
     */
    protected $userService;


    public function __construct(ContainerInterface $container, UserServiceInterface $userService)
    {
        $this->container = $container;
        $this->userService = $userService;
    }

    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        $response = Context::get(ResponseInterface::class);
        $request = Context::get(ServerRequestInterface::class, $request);

        $path = $request->getUri()->getPath();
        $arrPath = explode('/', $path);
        if (is_numeric(end($arrPath))) {
            array_pop($arrPath);
            $path = implode('/', $arrPath);
        }

        $permissions = $this->getAllPermissions();

        $userInfo = $request->getAttribute('userInfo');
        if (!empty($userInfo) && $userInfo['account'] != 'admin') {
            //没有分配权限
            if (!$this->checkPermission($permissions, $path)) {
                $data = json_encode([
                    'code' => 403,
                    'message' => '您没有该操作权限',
                ], JSON_UNESCAPED_UNICODE);
                return $response->withStatus(200)->withAddedHeader('content-type', 'application/json; charset=utf-8')->withBody(new SwooleStream($data));
            }

            //权限验证
            $permission = $permissions[$path];
            $hasPermission = $this->getHasPermissions($userInfo);
            if (!in_array('sys_user_login_info', $hasPermission)) {
                array_push($hasPermission,'sys_user_login_info');
            }
            if (!in_array($permission, $hasPermission)) {
                $data = json_encode([
                    'code' => 403,
                    'message' => '您没有该操作权限',
                ], JSON_UNESCAPED_UNICODE);
                return $response->withStatus(200)->withAddedHeader('content-type', 'application/json; charset=utf-8')->withBody(new SwooleStream($data));
            }
        }
        return $handler->handle($request);
    }

    private function formatPath($path)
    {
        $arrPath = explode('/', $path);
        if (is_numeric(end($arrPath))) {
            array_pop($arrPath);
            $path = implode('/', $arrPath);
        }
        return $path;
    }

    private function checkPermission($permissions, $path): bool
    {
        $result = false;
        foreach ($permissions as $permissionPath => $permission) {
            $b = str_replace('*', '____x____', $permissionPath);
            $c = preg_quote($b);
            $d = str_replace('/', '\/', $c);
            $e = '/' . str_replace('____x____', '.+', $d) . '/is';
            $res = preg_match($e, $path, $match);
            if ($res) {
                $result = true;
                break;
            }
        }
        return $result;
    }

    private function getAllPermissions()
    {
        $annotationValues = [];
        $annotations = AnnotationCollector::getMethodsByAnnotation(Permission::class);
        foreach ($annotations as $annotation) {
            $annotationPath = $annotation['annotation']->path;
            $annotationValue = $annotation['annotation']->value;
            if (empty($annotationPath)) {
                $annotationPath = '/' . str_replace('_', '/', $annotationValue);
            }
            $annotationValues[$annotationPath] = $annotationValue;
        }
        return $annotationValues;
    }

    private function getHasPermissions($userInfo)
    {
        $hasPermission = [];
        foreach ($userInfo['roles'] as $role) {
            foreach ($role['menus'] as $menu) {
                if ($menu['level'] == 3 && !in_array($menu['sign'], $hasPermission)) {
                    $hasPermission[] = $menu['sign'];
                }
            }
        }
        return $hasPermission;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值