如何防止 Laravel API 处理查询字符串上的参数?
Posted
技术标签:
【中文标题】如何防止 Laravel API 处理查询字符串上的参数?【英文标题】:How to prevent Laravel API from processing parameters on query-string? 【发布时间】:2017-08-11 04:07:20 【问题描述】:我想限制我的 Laravel API 在尝试对用户进行身份验证时将参数作为查询字符串处理。我一直在尝试使用 POSTMAN,并且无论我将凭据放在正文上还是作为查询字符串放在 url 中,我都能从我的 API 中获取令牌。
根据 Laravel 文档,我认为这是我想要避免的行为:
Retrieving Input Via Dynamic Properties
您还可以使用 Illuminate\Http\Request 实例。例如,如果您的一个 应用程序的表单包含一个名称字段,您可以访问的值 像这样的字段:
$name = $request->name;
当使用动态属性时,Laravel 会 首先在请求有效负载中查找参数的值。如果是 不存在,Laravel 会搜索路由中的字段 参数。
我正在使用 Laravel 5.3 和 PHP 7.1.0
这是使用查询字符串的 POST:
这是使用正文中的参数的 POST:
我已经使用 laravel-cors 配置了我的 CORS:
<?php
return [
'defaults' => [
'supportsCredentials' => false,
'allowedOrigins' => [],
'allowedHeaders' => [],
'allowedMethods' => [],
'exposedHeaders' => [],
'maxAge' => 0,
'hosts' => [],
],
'paths' => [
'v1/*' => [
'allowedOrigins' => ['*'],
'allowedHeaders' => ['Accept', 'Content-Type'],
'allowedMethods' => ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'],
'exposedHeaders' => ['Authorization'],
'maxAge' => 3600,
],
],
];
我的路线(相关路线):
Route::group(
[
'domain' => getenv('API_DOMAIN'),
'middleware' => 'cors',
'prefix' => '/v1',
'namespace' => 'V1'
],
function()
/* AUTHENTICATION */
Route::post(
'signin',
'AuthenticationController@signin'
)->name('signin');
Route::post(
'signup',
'AuthenticationController@signup'
)->name('signup');
);
在列出我的路线php artisan route:list
时,我得到:
------------------------------------------------------------------------------------------------------------------------------------
| Domain | Method | URI | Name | Action | Middleware |
| localhost | POST | api/v1/signin | api.signin | App\Http\Controllers\API\V1\AuthenticationController@signin | api,cors |
| localhost | POST | api/v1/signup | api.signup | App\Http\Controllers\API\V1\AuthenticationController@signup | api,cors |
------------------------------------------------------------------------------------------------------------------------------------
我的AuthenticationController
:
<?php
namespace App\Http\Controllers\API\V1;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Tymon\JWTAuth\Exceptions\JWTException;
use App\Http\Requests;
use JWTAuth;
class AuthenticationController extends Controller
public function __construct()
$this->middleware('jwt.auth', ['except' => ['signin', 'signup']]);
public function signin(Request $request)
$credentials = $request->only('email', 'password');
try
if (! $token = JWTAuth::attempt($credentials))
return response()->json(
[
'error' => 'invalid_credentials'
],
401
);
catch (JWTException $e)
return response()->json(
[
'error' => 'could_not_create_token'
],
500
);
return response()->json(compact('token'));
public function signup(Request $request)
try
$user = User::where(['email' => $request["email"]])->exists();
if($user)
return Response::json(
array(
'msg' => "Email $request->email already exists"
),
400
);
$user = new User;
$user->create($request->input());
return Response::json(
array(
'msg' => 'User signed up.'
)
);
catch (Exception $exception)
return Response::json(
array(
'success' => false,
'exception' => $exception
)
);
我的Kernel
:
<?php
namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel
/**
* The application's global HTTP middleware stack.
*
* These middleware are run during every request to your application.
*
* @var array
*/
protected $middleware = [
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
\Barryvdh\Cors\HandleCors::class,
];
/**
* The application's route middleware groups.
*
* @var array
*/
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'api' => [
'throttle:60,1',
'bindings',
],
];
/**
* The application's route middleware.
*
* These middleware may be assigned to groups or used individually.
*
* @var array
*/
protected $routeMiddleware = [
'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'jwt.auth' => \Tymon\JWTAuth\Middleware\GetUserFromToken::class,
'jwt.refresh' => \Tymon\JWTAuth\Middleware\RefreshToken::class,
];
我把各自的配置放在config/app.php
:
...
/*
* Package Service Providers...
*/
Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider::class,
Collective\html\HtmlServiceProvider::class,
Laracasts\Flash\FlashServiceProvider::class,
Prettus\Repository\Providers\RepositoryServiceProvider::class,
\InfyOm\Generator\InfyOmGeneratorServiceProvider::class,
\InfyOm\CoreTemplates\CoreTemplatesServiceProvider::class,
/*
* Application Service Providers...
*/
App\Providers\AppServiceProvider::class,
// App\Providers\BroadcastServiceProvider::class,
App\Providers\AuthServiceProvider::class,
App\Providers\EventServiceProvider::class,
App\Providers\RouteServiceProvider::class,
Tymon\JWTAuth\Providers\JWTAuthServiceProvider::class,
Barryvdh\Cors\ServiceProvider::class,
Asvae\ApiTester\ServiceProvider::class,
],
我不想使用dingoapi。
我检查了这些资源:
JSON Web Token Tutorial: An Example in Laravel and AngularJS SERIES: BUILD AN APP WITH LARAVEL5 (BACKEND) AND ANGULARJS (FRONTEND) – PART 1最后但同样重要的是,我的composer.json
:
"name": "laravel/laravel",
"description": "The Laravel Framework.",
"keywords": ["framework", "laravel"],
"license": "MIT",
"type": "project",
"require":
"php": "^7.1.0",
"laravel/framework": "5.3.*",
"barryvdh/laravel-ide-helper": "v2.2.1",
"laravelcollective/html": "v5.3.0",
"infyomlabs/laravel-generator": "5.3.x-dev",
"infyomlabs/core-templates": "5.3.x-dev",
"infyomlabs/swagger-generator": "dev-master",
"jlapp/swaggervel": "2.0.x-dev",
"doctrine/dbal": "2.3.5",
"league/flysystem-aws-s3-v3": "1.0.13",
"tymon/jwt-auth": "0.5.9",
"barryvdh/laravel-cors": "v0.8.2",
"fzaninotto/faker": "~1.4",
"caouecs/laravel-lang": "3.0.19",
"asvae/laravel-api-tester": "^2.0"
,
"require-dev":
"fzaninotto/faker": "~1.4",
"mockery/mockery": "0.9.*",
"phpunit/phpunit": "~5.7",
"symfony/css-selector": "3.1.*",
"symfony/dom-crawler": "3.1.*"
,
"autoload":
"classmap": [
"database"
],
"psr-4":
"App\\": "app/"
,
"autoload-dev":
"psr-4":
"Tests\\": "tests/"
,
"scripts":
"post-root-package-install": [
"php -r \"file_exists('.env') || copy('.env.example', '.env');\""
],
"post-create-project-cmd": [
"php artisan key:generate"
],
"post-install-cmd": [
"Illuminate\\Foundation\\ComposerScripts::postInstall",
"php artisan optimize"
],
"post-update-cmd": [
"Illuminate\\Foundation\\ComposerScripts::postUpdate",
"php artisan optimize"
]
,
"config":
"preferred-install": "dist"
更新
感谢“Basheer Ahmed”给出的答案,他为我指明了正确的方向,我最终做了一个 Trait 来解析我想要根据请求获得的 body
属性:
<?php
namespace KeepClear\Traits\Controllers;
trait ApiRequest
/**
* Parse all attributes and return an array with the present values only.
*
* @param array $attributes
* @param Request $request
*
* @return Array
*/
public function parseBody($attributes, $request)
$params = [];
foreach ($attributes as $attribute)
$value = $request->request->get($attribute);
if ($value)
$params[$attribute] = $value;
return $params;
此方法将主要用于create
和update
操作,如下所示,AddressController
:
<?php
namespace KeepClear\Http\Controllers\API\V1;
...
use KeepClear\Traits\Controllers\ApiRequest;
...
class AddressController extends Controller
use ApiRequest;
/**
* Instantiate a new controller instance.
*
* @return void
*/
public function __construct()
$this->middleware('jwt.auth');
...
/**
* Create address for the specified user.
*
* @param Request $request
* @param String $user_id
*
* @return Response
*/
public function createUserAddress(Request $request, $user_id)
try
$attributes = ['city', 'county_province', 'zip_code'];
$params = $this->parseBody($attributes, $request);
User::find($user_id)->addresses()->create($params);
return Response::json(
array(
'message' => 'The address was successfully created.',
'success' => true
)
);
catch (Exception $exception)
return Response::json(
array(
'success' => false,
'exception' => $exception
)
);
...
/**
* Update address for the specified user.
*
* @param Request $request
* @param String $user_id
* @param String $address_id
*
* @return Response
*/
public function updateUserAddress(Request $request, $user_id, $address_id)
try
$attributes = ['city', 'county_province', 'zip_code'];
$params = $this->parseBody($attributes, $request);
Address::where(["user_id" => $user_id, "id" => $address_id])
->update($params);
return Response::json(
array(
'message' => 'The address was successfully updated.',
'success' => true
)
);
catch (Exception $exception)
return Response::json(
array(
'success' => false,
'exception' => $exception
)
);
...
通过这种方式并通过使用$request->request->get('my_param');
,我可以确定在测试了该方法的工作原理后,我只能获取主体的属性。
这是AddressController
在这些方法上的测试:
<?php
namespace Tests\Api;
use Tests\TestCase;
...
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Faker\Factory;
...
class AddressControllerTest extends TestCase
use ApiTestTrait;
use DatabaseMigrations;
use WithoutMiddleware;
...
public function testMethodCreateUserAddress()
$admin = factory(Role::class, 'admin')->create();
$user = $admin->users()->save(factory(User::class)->make());
$uri = 'api/v1/users/' . $user->id . '/addresses';
$faker = Factory::create();
$attributes = array(
'city' => $faker->city,
'county_province' => $faker->state,
'zip_code' => $faker->postcode
);
$this->json('POST', $uri, $attributes)
->seeStatusCode(200)
->seeJsonEquals(
[
'message' => 'The address was successfully created.',
'success' => true
]
);
...
public function testMethodUpdateUserAddress()
$admin = factory(Role::class, 'admin')->create();
$user = $admin->users()->save(factory(User::class)->make());
$address = $user->addresses()->save(factory(Address::class)->make());
$uri = 'api/v1/users/' . $user->id . '/addresses/' . $address->id;
$attributes = array(
'city' => 'newCity',
'county_province' => 'newCountyProvince',
'zip_code' => 'newZipCode'
);
$this->json('PUT', $uri, $attributes)
->seeStatusCode(200)
->seeJsonEquals(
[
'message' => 'The address was successfully updated.',
'success' => true
]
);
$updated_address = Address::find($address->id);
$this->assertEquals($updated_address->city, 'newCity');
$this->assertEquals(
$updated_address->county_province,
'newCountyProvince'
);
$this->assertEquals($updated_address->zip_code, 'newZipCode');
...
【问题讨论】:
【参考方案1】:附加到 url 栏的任何内容都被视为获取请求,并且可以通过 $_GET
超级全局变量获得。我假设 laravel Request
请求将合并 post 和 get 请求,然后当您尝试调用通过 get 或 post 发送的任何参数时,您可以通过
$request->myparam
但如果你只是尝试
$request->request->get('my_param');
你不会得到类似的结果。
:)
【讨论】:
您好,我正在尝试您的建议,但这个“$request->request->post('my_param');”如果这个“$request->request->get('my_param');”,它不起作用,但正在起作用的那个。而且我正在检查“$request->getContent();”这也是只返回body的参数,很好!但使用这种方法“$request->request->get('my_param');”我已经为每个我想从请求中获取的参数写了一个,不是很酷:P,并且使用这个“$request->getContent();”我必须解析结果,因为该方法返回“email=nisevi%40gmail.com&password=password”。 你知道从body获取参数的唯一方法是“$request->request->get('my_param');”吗?和“$request->getContent();” ? 我还发现了一个关于如何从这里github.com/symfony/symfony/issues/13585 获取参数的问题,只是为了添加更多信息...... @nisevi$request->all()
将给出所有请求数据的key value
对...
是的,但是如果参数在 URL 中,该方法也可以使用...所以如果它们不在正文中,则转到 URL 并且我不想要那个...无论如何我使用您建议的方法$request->request->get('my_param');
请更新您的答案,因为另一个post
它不存在,我会将您的答案标记为正确?以上是关于如何防止 Laravel API 处理查询字符串上的参数?的主要内容,如果未能解决你的问题,请参考以下文章
如何访问我在 Laravel 4 中手动发送的请求的查询字符串参数?
错误:防止写入仅在大小写或查询字符串方面与已写入文件不同的文件。反应js laravel