laravel - Laravel Vue SPA 登录
问题描述
我刚刚创建了 Vue + Laravel SPA 登录,但我不确定它是否足够安全。我是 VUE 的新手 :)
我正在使用 JWT 身份验证。当用户输入凭据并提交表单时,Laravel 端的 Auth 返回带有令牌的用户模型。此用户存储在本地存储中。在我的 Vue 路由器中,我创建了在每次视图更改之前运行的中间件。这很好用,但数据库中没有与该用户相关的实际令牌。当我手动更改存储中的令牌时,我仍在传递中间件,因为不再检查令牌。它只是检查本地存储中是否存在......我应该将令牌存储在数据库中并在每次视图更改时检查它吗?或者...??
解决方案
保护您的服务器端路由很重要。我为此使用的解决方案是使用 .php 中的 php jwtlcobucci/jwt
库Laravel
。
我将解释使用默认且更简单的方法 JWT 秘密策略,而不是私钥/公钥策略(如 RSA)。
无论您使用什么框架进行JWT
身份验证,步骤都将始终相同:
- 用户登录。
- 用户凭据(电子邮件/用户名和密码)作为发布请求从您的客户端(vue)发送到您的服务器端(Laravel)
- 在服务器端验证凭据是否正确
- 如果正确,请使用 jwt 密钥为该用户签署 JWT 令牌。
- 将创建的 jwt 令牌作为响应发送给客户端。
- 将 JWT 令牌存储在 localStorage 中,并将其添加到标头以供将来请求。
一个简单的服务器端实现将包括
- 创建
jwt secret
环境变量 - 创建登录路径
- 为传入请求创建中间件以验证令牌
对于这些步骤,创建一个JWT_SECRET
环境变量。这将是一个很大的随机字符串。您可以为此使用任何随机字符串生成器。例子:
JWT_SECRET=bX7fsuHzOksB27Pwh31qmazMsalw4bchu7Ft1X4PMOhO23Zq8nwBKA0FZQOK
创建 apisign-in
路由
Route::post('authenticate', 'AuthenticateController@signIn');
app/Http/Controllers/AuthenticateController.php
<?php
namespace App\Http\Controllers;
use App\Services\JWTService;
class AuthenticateController extends Controller
{
protected $jwt;
public function __construct(JWTService $jwt)
{
$this->jwt = $jwt;
}
public function signIn(Request $request){
$token = $this->jwt->createToken();
$response = response()->json([
'message' => StatusCode::$texts[StatusCode::HTTP_OK],
'data' => [ 'token' => (string)$token]
], StatusCode::HTTP_OK);
return $response;
}
}
app/Services/JWTService.php
<?php
namespace App\Services;
use Lcobucci\JWT\Builder;
use Lcobucci\JWT\Signer\Key;
use Lcobucci\JWT\Signer\Hmac\Sha256;
use Lcobucci\JWT\Parser;
use Lcobucci\JWT\Token;
class JWTService
{
public function createToken($privilege = 'externalUser'){
// eval(\Psy\sh());
$signer = new Sha256();
$key = new Key(env('JWT_SECRET')); // vindo null
$time = time();
$token = (new Builder())->issuedBy($privilege)->expiresAt($time + 3600)->getToken($signer, $key);
//->withClaim('uid', 1) // Configures a new claim, called "uid"
return $token;
}
public function parseString($bearerToken) : Token {
return (new Parser())->parse($bearerToken);
}
public function verify($token){
$signer = new Sha256();
$key = new Key(env('JWT_SECRET'));
if(!$token->verify($signer, $key))
abort(401, 'Unauthorized access.');
return true;
}
}
为了保护您的路由,请为所有传入请求(登录除外)添加一个中间件。使用 jwt 声明的授权逻辑将由您自己制作。
<?php
namespace App\Http\Middleware;
use Lcobucci\JWT\Parser;
use Lcobucci\JWT\Signer\Key;
use Lcobucci\JWT\Signer\Hmac\Sha256;
use OutOfBoundsException;
use BadMethodCallException;
use Closure;
class Authorization
{
public function handle($request, Closure $next)
{
try {
$bearerToken = $request->bearerToken();
if(!isset($bearerToken))
abort(401, 'Unauthorized access.');
$token = (new Parser())->parse($bearerToken); // Parses from a string
$signer = new Sha256();
$key = new Key(env('JWT_SECRET'));
if(!$token->verify($signer, $key))
abort(401, 'Unauthorized access.');
return $next($request);
} catch(OutOfBoundsException $e){
abort(401, 'Requested data is not configured.');
} catch(BadMethodCallException $e){
abort(403, 'Token not signed.');
}
}
// $token->getHeaders(); // Retrieves the token header
// $token->getClaims(); // Retrieves the token claims
// $token->getClaim('iss');
// $token->getClaim('exp');
}
将中间件添加到kernel.php
protected $routeMiddleware = [
...
'tokenAuth' => \App\Http\Middleware\Authorization::class
];
这样您就可以通过routes/api.php
这种方式添加中间件:
Route::group(['middleware' => 'tokenAuth'], function(){
Route::resource('user', 'UserController');
Route::resource('Foo', 'FooController');
}
我强烈建议阅读Laravel 文档和lcobucci/jwt以更好地理解这些步骤以及如何使用jwt claims
和Laravel
内置工具实现安全和良好的解决方案。
推荐阅读
- flutter - 如何使用 setState 更新 AlertDialog 的内容?
- python - 我想获得一个列表的单行输入,它接受在 python 中预定义的最高值'N'
- javascript - K6 WebSockets 负载测试报告令人困惑
- python - 当导入的模块名称未明确定义时,python解决模块名称冲突
- html - 如何在标签的值内应用 css
- sql - 对 SQL 记录应用多重验证并识别所有失败的验证
- java - 在不同的功能文件和步骤定义文件中运行测试时出现 NullPointerException
- qt - 禁用按钮时不会触发 MouseMoveEvent
- flutter - Flutter 未加载设备并显示“正在等待另一个 Flutter 命令释放启动锁......”
- .net - MassTransit:取消长时间运行的作业