php - Laravel API 对后续请求的验证/保护 : no login/logout and no "users" table

标签 php laravel vue.js laravel-8 laravel-sanctum

TLDR;见下图3 - 这可能吗?如何实现?


我读到了有关 API 保护的内容 - Sanctum & Passport ,但这些似乎都不是我可以用我的应用程序完成的,因为它在某种程度上有点具体和简化。

例如,Sanctum 的身份验证方式听起来像是我想要的,但没有/login 部分(我有一个自定义/auth 部分,见下文。): https://laravel.com/docs/8.x/sanctum#spa-authenticating .

If the login request is successful, you will be authenticated and subsequent requests to your API routes will automatically be authenticated via the session cookie that the Laravel backend issued to your client.

我的应用程序本身没有登录 - 如果用户具有由第 3 方 API 验证的指定 cookie token ,我们就会登录用户(我知道 token-auth 不是最好的方法,但它是一个非常具体的方法)应用/使用)。它在 /auth 上, 所以 Sanctum 上面的描述可以工作,我想如果我知道在哪里摆弄它的话。我们的逻辑:

  1. VueJS:移动设备发送加密的 cookie token - 应用程序在 JS 中读取它,将其发送到我的 Laravel API 进行验证。
  2. 在 Laravel API 中获取 token ,解密,发送到第二个 API(不在我的控制范围内),验证 token ,然后发回包含一些数据的 OK 或 NOT OK 响应。
  3. 如果响应正常,则用户已“登录”。
  4. 用户可以导航应用,并且会发生其他 API 响应 - 我如何验证是他本人,而不是冒名顶替者或某个直接在浏览器中访问 API 的人?

我猜这个 session 可以解决这个问题,但这是我第一次使用 Laravel,似乎没有什么能按预期工作。此外,如果需要的话,我不希望存储在文件或数据库中的 session 。

例如,当上述步骤 3 发生时,我尝试设置一个简单的 session 参数并将其发送回来,但 session 存储尚未设置,但似乎在那时。然后我可以检查该 session 值以确保他与刚刚验证的用户是同一用户。

为了更容易地理解我想要完成的任务以及它是否可行: enter image description here

主要问题是,实现基本 API 保护/身份验证/验证的最简单方法是什么,同时仅在第一个请求时将身份验证 token 发送到第 3 方 API(当然,如果应用程序重新打开/刷新) ) - 请记住,我的 Laravel API 上不存在实际用户。

或者最好在每个请求上对第 3 方 API 进行 token 身份验证?

最佳答案

如果我正确理解您的情况,则不涉及真正的用户模型,对吧?如果是这样,您将无法使用 Laravel 的任何内置身份验证方法,因为它们都依赖于此类模型的存在。

在这种情况下,您将需要一个端点和一个自定义身份验证中间件,您需要在 Laravel 中自行创建该中间件才能处理所有事情:

端点定义:

Route::post('authenticate', [TokenController::class, 'login']);

Controller :

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 header 中的 api token 作为 Bearer token 传递。然后在中间件中,您将检查承载 token 并检查它是否符合我们的预期值:

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 的人最终都将能够访问您 protected 端点!

当然,这是处理自定义无用户身份验证的一种方法,还有更多方法。例如,您可以在加密 token 中插入到期日期而不是字符串“authenticated”,并验证它是否在中间件中到期。但您已经了解了要遵循的步骤的要点...


如果您确实有一个 User 模型,那么您可以使用 Laravel Sanctum 并在用户检索后颁发 API token ,而不是伪造自定义加密 token 。请参阅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;

后续请求应将授权 header 中的 token 作为承载 token 传递。

使用Sanctum提供的中间件保护路由:

Route::middleware('auth:sanctum')->get('some/api/route', SomeController::class);

关于php - Laravel API 对后续请求的验证/保护 : no login/logout and no "users" table,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65181651/

相关文章:

php - 如何连接到 heroku 上的外部 mysql 数据库?

PHP Mysql 删除查询无法正常工作

PHP 数组到图表

php - Laravel RouteServiceProvider 中的显式路由模型绑定(bind)问题

php - 将图像保存在公用文件夹中而不是存储 laravel 5

php - Laravel 未定义偏移量 : 2 in for loop

javascript - 通过 Vue.Js 调查导航

php - Codeigniter 数据库类与准备好的语句

javascript - Array Splice 总是从最后删除一个项目?

javascript - 在 vue 中作为 prop 传递的对象以字符串形式到达