如果令牌在URL中作为查询字符串出现,则阻止Laravel API处理令牌

nis*_*evi 5 cors jwt laravel laravel-5.3

我能够处理令牌,如果它作为查询字符串在URL中出现,或者如果它出现在标题中Authentication,并且令牌前缀为令牌Bearer,我只希望能够在标题中接收它.

这是我的app/Http/Controllers/API/V1/AuthenticationController.php档案:

<?php

namespace app\Http\Controllers\API\V1;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Tymon\JWTAuth\Exceptions\JWTException;
use App\Models\Role;
use App\Models\User;
use App\Traits\Controllers\ApiParseBody;
use App\Traits\Controllers\ApiException;
use App\Traits\Controllers\ApiEvaluateCredentials;
use Tymon\JWTAuth\JWTAuth;
use App\Exceptions\Unauthorized\InvalidCredentials;
use App\Exceptions\InternalServerError\CouldNotCreateToken;
use Illuminate\Contracts\Hashing\Hasher;

class AuthenticationController extends Controller
{
    use ApiParseBody;
    use ApiEvaluateCredentials;
    use ApiException;

    /**
     * The user implementation.
     *
     * @var User
     */
    protected $user;


    /**
     * The role implementation.
     *
     * @var Role
     */
    protected $role;

    /**
     * The hash implementation.
     *
     * @var Hash
     */
    protected $hash;

    /**
     * The jwtauth implementation.
     *
     * @var JWTAuth
     */
    protected $jwtauth;

    /**
     * Instantiate a new controller instance.
     *
     * @return void
     */
    public function __construct(
        User $user,
        Role $role,
        Hasher $hash,
        JWTAuth $jwtauth
    ) {
        $this->middleware('jwt.auth', ['except' => ['signin', 'signup']]);
        $this->user = $user;
        $this->role = $role;
        $this->hash = $hash;
        $this->jwtauth = $jwtauth;
    }

    /**
     * Signin user.
     *
     * @param Request $request
     *
     * @return Response
     */
    public function signin(Request $request)
    {
        $attributes = array('email', 'password');
        $credentials = $this->parseBody($attributes, $request);
        $this->validateCredentialsArePresent($credentials);
        try {
            if (! $token = $this->jwtauth->attempt($credentials)) {
                throw new InvalidCredentials('invalid_credentials');
            }
        } catch (JWTException $e) {
                throw new CouldNotCreateToken('could_not_create_token');
        }
        return response()->json(compact('token'));
    }

    /**
     * Signup user. Default role is 'common'.
     *
     * @param Request $request
     *
     * @return Response
     */
    public function signup(Request $request)
    {
        $attributes = array('email', 'password');
        $params = $this->parseBody($attributes, $request);
        $this->validateCredentialsArePresent($params);
        $this->evaluateCredentials($params);
        $credentials = array(
            'email' => $params['email'],
            'password' => $this->hash->make($params['password'])
        );
        $this->validateUserAlreadyExists($credentials);
        $commonRole = $this->role->where('name', 'common')->firstOrFail();
        $user = new User($credentials);
        $commonRole->users()->save($user);
        return response()->json(array( 'message' => 'User signed up.'));
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我的config/cors.php档案:

<?php

return [
   'defaults' => [
       'supportsCredentials' => false,
       'allowedOrigins' => [],
       'allowedHeaders' => [],
       'allowedMethods' => [],
       'exposedHeaders' => [],
       'maxAge' => 0,
       'hosts' => [],
   ],

   'paths' => [
       'v1/*' => [
           'allowedOrigins' => ['*'],
           'allowedHeaders' => [
               'Origin',
               'Content-Type',
               'Accept',
               'Authorization',
               'X-Request-With'
           ],
           'allowedMethods' => ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'],
           'exposedHeaders' => ['Authorization'],
           'maxAge' => 3600,
       ],
   ],
];
Run Code Online (Sandbox Code Playgroud)

下面的图片将显示我的意思,以防万一我不清楚我正在尝试传输的内容.

这个展示了我如何使用Postman对Heroku上的应用程序进行GET.你会看到我正在使用标题Authorization:

在此输入图像描述

我想要阻止的是通过在URL中发送令牌来获得相同的结果,如下所示:

在此输入图像描述

我甚至都不知道这是否可行,所以我非常感谢这方面的任何指导.

nis*_*evi 5

我所做的是创建一个中间件,以便拒绝所有以“token”作为查询字符串中的关键参数的请求。

首先我们必须创建中间件:

php artisan make:middleware BeforeMiddleware正如您可能注意到的那样,这是一个 before 中间件,这意味着它将在请求到达应用程序之前运行:

<?php

namespace App\Http\Middleware;

use Closure;
use App\Exceptions\BadRequest\RejectTokenAsQuerystring;

class BeforeMiddleware
{
    /**
     * Handle an incoming request.
     *
     * @param \Illuminate\Http\Request  $request
     * @param \Closure  $next
     *
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        if ($request->token) {
            throw new RejectTokenAsQuerystring('reject_token_as_querystring');
        }
        return $next($request);
    }
}
Run Code Online (Sandbox Code Playgroud)

我还必须将我创建的中间件添加到我的内核中:

<?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 = [
        'api' => [
            'throttle:60,1',
            'bindings',
        ],
    ];

    /**
     * The application's route middleware.
     *
     * These middleware may be assigned to groups or used individually.
     *
     * @var array
     */
    protected $routeMiddleware = [
        'reject-token-in-url' => \App\Http\Middleware\BeforeMiddleware::class,
        '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,
    ];
}
Run Code Online (Sandbox Code Playgroud)

最后,全局定义的中间件可以在我的路由定义中使用:

<?php

/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/

Route::group(
    [
        'domain' => getenv('API_DOMAIN'),
        'middleware' => ['cors', 'reject-token-in-url'],
        'prefix' => '/v1',
        'namespace' => 'V1'
    ],
    function () {
    }
);
Run Code Online (Sandbox Code Playgroud)

我还实现了自己的错误定义,因此我有一个我想在应用程序中触发的所有可能错误的列表,它们在我的文件中定义如下config/errors.php

<?php

return [
    "reject_token_as_querystring" => [
            "title"  => "Reject token as querystring.",
            "detail"  => "Token MUST be passed in the Header of the request."
    ]
];
Run Code Online (Sandbox Code Playgroud)

然后您需要定义自定义异常类:

<?php

namespace App\Exceptions;

use Exception;

abstract class CustomException extends Exception
{
    /**
     * The id of the error that is being triggered.
     *
     * @var string
     */
    protected $errorId;

    /**
     * Status code for the triggered error.
     *
     * @var string
     */
    protected $status;

    /**
     * Title of the error.
     *
     * @var string
     */
    protected $title;

    /**
     * Detailed description about the error.
     *
     * @var string
     */
    protected $detail;

    /**
     * Instantiate a new Exception with the provided message.
     *
     * @param @string $message
     *
     * @return void
     */
    public function __construct($message)
    {
        parent::__construct($message);
    }

    /**
     * Get the status
     *
     * @return Int
     */
    public function getStatus()
    {
        return (int) $this->status;
    }

    /**
     * Return the Exception as an array
     *
     * @return Array
     */
    public function toArray()
    {
        return [
            'id'     => $this->id,
            'status' => $this->status,
            'title'  => $this->title,
            'detail' => $this->detail
        ];
    }

    /**
     * Build the Exception.
     *
     * @param array $args
     *
     * @return string
     */
    protected function build(array $args)
    {
        $this->id = array_shift($args);
        $error = config(sprintf('errors.%s', $this->id));
        $this->title  = $error['title'];
        $this->detail = vsprintf($error['detail'], $args);
        return $this->detail;
    }
}
Run Code Online (Sandbox Code Playgroud)

您将使用该类来扩展您的自定义错误:

<?php

namespace App\Exceptions\BadRequest;

use App\Exceptions\CustomException;

class BadRequestException extends CustomException
{
    /**
     * Status error number.
     *
     * @var string
     */
    protected $status = '400';

    /**
     * Instantiate a new 'bad request exception'.
     *
     * @return void
     */
    public function __construct()
    {
        $message = $this->build(func_get_args());

        parent::__construct($message);
    }
}
Run Code Online (Sandbox Code Playgroud)

为了创建保存错误本身的类:

<?php

namespace App\Exceptions\BadRequest;

use App\Exceptions\BadRequest\BadRequestException;

class RejectTokenAsQuerystring extends BadRequestException
{

}
Run Code Online (Sandbox Code Playgroud)

最后,如果您尝试使用 url 中的令牌密钥请求信息,您将得到:

{
  "id": "reject_token_as_querystring",
  "status": "400",
  "title": "Reject token as querystring.",
  "detail": "Token MUST be passed in the Header of the request."
}
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述