Laravel API 验证/保护后续请求:没有登录/注销和没有“用户”表
Posted
技术标签:
【中文标题】Laravel API 验证/保护后续请求:没有登录/注销和没有“用户”表【英文标题】:Laravel API verification/protection on subsequent requests: no login / logout and no "users" table 【发布时间】:2021-03-18 18:07:08 【问题描述】:TLDR;见下图3 - 这可能吗?如何实现?
我阅读了有关 API 保护的信息 - Sanctum 和 Passport,但这些似乎都不是我可以用我的应用程序完成的,因为它在某种程度上有点具体和简化。
例如,Sanctum 的身份验证方式听起来像是我想要的,但没有 /login 部分(我有一个自定义 /auth 部分,见下文。):https://laravel.com/docs/8.x/sanctum#spa-authenticating。
如果登录请求成功,您将获得身份验证并 对您的 API 路由的后续请求将自动 通过 Laravel 后端发布的会话 cookie 进行身份验证 给你的客户。
我的应用程序本身没有登录 - 如果用户具有由 3rd 方 API 验证的指定 cookie 令牌,我们会登录用户(我知道令牌验证不是最好的方法,但它是一个非常具体的应用/使用)。它在/auth,
上,所以上面的 Sanctum 描述可以工作,我想如果我知道在哪里摆弄它。我们的逻辑:
-
VueJS:移动设备发送加密的 cookie 令牌 - 应用在 JS 中读取它,将其发送到我的 Laravel API 进行验证。
在 Laravel API 中获取令牌,解密,发送到第二个 API(不在我的控制范围内),验证令牌,然后发回带有一些数据的 OK 或 NOT OK 响应。
如果响应正常,则用户“已登录”。
用户可以浏览应用程序,并且会出现其他 API 响应 - 我如何验证是他而不是冒名顶替者或直接在浏览器中访问 API 的人?
我想这个会话可以解决这个问题,但这是我第一次使用 Laravel,似乎没有任何效果。此外,如果需要,我并不期待存储在文件或数据库中的会话。
例如,我尝试在上面的第 3 步发生时设置一个简单的会话参数并将其发送回来,但会话存储尚未设置,但似乎在那时。然后我可以检查该会话值以确保他是刚刚验证的同一用户。
为了更容易理解我想要完成的工作以及它是否可行:
主要问题是,什么是获得基本 API 保护/身份验证/验证的最简单方法,同时仅在第一次请求时将用于身份验证的令牌发送到第 3 方 API(当然,如果应用程序重新打开/刷新) - 请记住,我的 Laravel API 上不存在实际用户。
或者最好在每个请求上对第 3 方 API 进行令牌验证?
【问题讨论】:
【参考方案1】:如果我正确理解您的情况,则不涉及真正的用户模型,对吗?如果是这样,您将无法使用 Laravel 的任何内置身份验证方法,因为它们都依赖于此类模型的存在。
在这种情况下,您需要一个端点和一个自定义身份验证中间件,您需要在 Laravel 中自己创建以处理所有事情:
端点定义:
Route::post('authenticate', [TokenController::class, 'login']);
控制器:
class TokenController extends Controller
public function login(Request $request)
// First read the token and decrypt it.
// Here you'll need to replace "some_decryption()" with the required decrypter based on how your VueJS app encrypts the token.
$token = some_decryption( $request->input('token') );
// Then make the request to the verification API, for example using Guzzle.
$isTokenOk = Http::post('http://your-endpoint.net', [
'token' => $token,
])->successful();
// Now issue a Laravel API token only if the verification succeeded.
if (! $isTokenOk)
abort(400, 'Verification failed');
// In order to not store any token in a database, I've chosen something arbitrary and reversibly encrypted.
return response()->json([
'api-token' => Crypt::encrypt('authenticated'),
]);
后续请求应将 Authorization 标头中的 api 令牌作为 Bearer 令牌传递。然后在中间件中检查 Bearer 令牌并检查它是否符合我们的预期值:
class AuthTokenAuthenticationMiddleware
public function handle($request, Closure $next)
$authToken = $request->bearerToken();
if (! $authToken || ! Crypt::decrypt($authToken) === 'authenticated')
abort(401, 'Unauthenticated');
return $next($request);
中间件需要在app/Http/Kernel.php
注册:
protected $routeMiddleware = [
...
'auth-token' => AuthTokenAuthenticationMiddleware::class,
];
最后将这个新的中间件应用到任何应该被认证的路由:
Route::middleware('auth-token')->get('some/api/route', SomeController::class);
警告:此身份验证机制依赖于可逆加密。任何能够解密或拥有您的 APP_KEY 的人最终都将能够访问您受保护的端点!
当然,这是处理自定义无用户身份验证的一种方法,还有更多。例如,您可以在加密令牌中插入过期日期而不是字符串“authenticated”,并验证它是否在中间件中过期。但是你得到了要遵循的步骤的要点......
如果你确实有一个用户模型,那么你可以使用 Laravel Sanctum 并在用户检索后发布一个 API 令牌,而不是伪造一个自定义的加密令牌。见https://laravel.com/docs/8.x/sanctum#issuing-mobile-api-tokens
// Fetch the corresponding user...
$user = User::where('token', $request->input('token'))->first();
return $user->createToken('vuejs_app')->plainTextToken;
后续请求应将 Authorization 标头中的令牌作为 Bearer 令牌传递。
使用 Sanctum 提供的中间件保护路由:
Route::middleware('auth:sanctum')->get('some/api/route', SomeController::class);
【讨论】:
嘿!谢谢你的回答,我明天有时间试试。我猜我也可以使用 Laravel 的 Crypt / Decrypt 吗? laravel.com/docs/8.x/encryption 不然看起来我要找的东西有点像! 当然。使用的函数encrypt()
和 decrypt()
实际上是 Laravel 的 Crypt/Decrypt 功能的助手,尽管它们在 Laravel 7 中被删除了。看来我还生活在旧时代。我会相应地更新我的答案。
请注意,为简洁起见,我省略了命名空间导入。不要忘记导入 Facades 和类。
似乎第一个选项(不是很安全的同意)如您所描述的那样工作,谢谢。无论如何,我是否可以使用用户表,例如,当我获得某个唯一 ID(除了令牌)时,如果他不存在,则创建用户。每次我都会用 Bearer 发送这个 ID。它可以工作吗?我倾向于这种方式,因为 Sanctum 肯定更安全 - 生成令牌等
当然,如果发送的是唯一 ID,您肯定可以在控制器中插入用户模型:User::firstOrCreate()
就是您要查找的内容。以上是关于Laravel API 验证/保护后续请求:没有登录/注销和没有“用户”表的主要内容,如果未能解决你的问题,请参考以下文章