• PHP:laravel中间件和控制器的请求参数传递与获取


    在这里插入图片描述

    接口开发中,通常我们需要在中间件里边做一些全局性的前置判断,获取请求中的公共参数,然后传递给控制器

    参考网络上的大部分文章,整理出以下传递参数的方式,并深入研究,作出一些思考

    1、中间件和控制器测试

    中间件

    
    
    namespace App\Http\Middleware;
    
    use Illuminate\Http\Request;
    
    /**
     * 测试中间件
     */
    class TestMiddleware
    {
    
        public function handle(Request $request, \Closure $next)
        {
            // 设置参数
            $request->attributes->set('name', 'Tom');
            return $next($request);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    控制器中取值

    
    
    namespace App\Http\Controllers;
    
    use Illuminate\Http\Request;
    
    class TestController extends Controller
    {
        public function index(Request $request): array
        {
            return [
                'name:input' => $request->input('name'),
                'name:get'   => $request->get('name')
            ];
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    请求提交参数

    {
        "name":  "Jack"
    }
    
    • 1
    • 2
    • 3

    返回参数

    {
      "data": {
        "name:input": "Jack",
        "name:get": "Tom"
      },
      "msg": "success",
      "code": 0
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    2、安全隐患

    目前看,都挺好的

    如果中间件中没有设置参数,就会取到用户传递过来的参数

    public function handle(Request $request, \Closure $next)
        {
            // $request->attributes->set('name', 'Tom');
            return $next($request);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    如果用于安全性较高的场景,有点不适用

    {
      "data": {
        "name:input": "Jack",
        "name:get": "Jack"
      },
      "msg": "success",
      "code": 0
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    假设,需要一个当前登录用户的id,假设是变量 current_login_user_id

    如果我们没有加中间件,前端中接口中传递了这个参数,那么我们的代码将会出现安全隐患。

    3、支持的传参方式

    我们看下支持的传参方式

    中间件

    class TestMiddleware
    {
    
        public function handle(Request $request, \Closure $next)
        {
            $request->name = 'prototype_name';
            $request->attributes->set('name', 'attr_name');
            return $next($request);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    控制器

    public function index(Request $request): array
        {
            return [
                'name:prototype'  => $request->name,
                'name:input' => $request->input('name'),
                'name:query' => $request->query('name'),
                'name:attr'   => $request->get('name')
            ];
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    请求

    POST {{api_url}}/test?name=query_name
    Content-Type: application/json; charset=utf-8
    
    {
        "name":  "post_name"
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    {
        "name:prototype": "prototype_name",
        "name:input": "post_name",
        "name:query": "query_name",
        "name:attr": "attr_name"
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    如果取消中间件,发现数据并不是所期待的那样,取到null值

    {
        "name:prototype": "post_name",
        "name:input": "post_name",
        "name:query": "query_name",
        "name:attr": "query_name"
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    4、总结

    综上,可以采用如下方式传递中间件参数到控制器是可行的

    // 中间件设置值 设置为null,就算请求参数中携带了name, 也能取到null值
    $request->attributes->set('name', null);
    
    // 控制器取值
    $request->get('name')
    
    • 1
    • 2
    • 3
    • 4
    • 5

    看下get的实现代码

    public function get(string $key, mixed $default = null): mixed
        {
            if ($this !== $result = $this->attributes->get($key, $this)) {
                return $result;
            }
    
            if ($this->query->has($key)) {
                return $this->query->all()[$key];
            }
    
            if ($this->request->has($key)) {
                return $this->request->all()[$key];
            }
    
            return $default;
    }
    
    public function get(string $key, mixed $default = null): mixed
    {
            return \array_key_exists($key, $this->parameters) ? $this->parameters[$key] : $default;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    array_key_exists 意味着,如果设置了值,就会直接返回,不再往下查找其他值

    5、一种更为安全的做法

    一种更为安全的做法,是建立一个枚举变量,来替代字符串变量

    const key = '192b9bdd22ab9ed4d12e236c78afcb9a393ec15f71bbf5dc987d54727823bcbf'
    
    // 就算没有设置值,也不会错误的从请求参数中获取值
    $value = input->get(key)
    
    • 1
    • 2
    • 3
    • 4

    利用Python,可以很容易生成这种很长的数字
    Python编程:使用os.urandom生成Flask的秘钥SECRET_KEY

  • 相关阅读:
    Spring 6【前置通知注解实现、同一切面多个相同类型通知执行顺序、代理设计模式、动态代理示例】(十六)-全面详解(学习总结---从入门到深化)
    CentOS(5)——rpm包和源码包区别
    线程安全问题 的小案例
    这次我设计了一款TPS百万级别的分布式、高性能、可扩展的RPC框架
    数据结构--栈
    Alpha-Beta剪枝的原理的深入理解(无图预警)
    Jenkins 打包到其他服务器上执行
    Java基于SpringBoot+Vue+nodejs的在线小说阅读平台 element
    Ubuntu搭建团队文档协作在线平台
    SELinux 介绍
  • 原文地址:https://blog.csdn.net/mouday/article/details/127813981