【问题标题】:Httponly cookie not being set / stored (Laravel / Vue)未设置/存储 Httponly cookie (Laravel / Vue)
【发布时间】:2020-03-01 17:57:54
【问题描述】:

我已经为如何解决这个问题苦苦挣扎了几个小时,但我现在似乎无法解决这个问题。

正在构建一个简单的身份验证系统,其前端有Vue(使用vue-cli 创建),后端使用Laravel 5.8(api);在阅读this 文章后,测试使用 httponly cookie 进行身份验证和保护对某些路由的访问的想法。我使用tymondesigns/jwt-auth 进行身份验证,而不是文章中使用的laravel passport,并且还使用barryvdh/laravel-cors 包来添加CORS(跨域资源共享)标头支持。

后端

这是我在routes/api.php中的代码

Route::group(['prefix' => 'auth', 'namespace' => 'Auth'], function () {
    Route::post('login', 'AuthController@login');

    Route::group(['middleware' => ['auth.api'],], function () {
        Route::get('me', 'AuthController@me');
        Route::post('logout', 'AuthController@logout');
    });
});

并且正在使用的中间件的代码在app/Http/Kernel.php中如下所示

'auth.api' => [
    \App\Http\Middleware\AddAuthTokenHeader::class,
    'throttle:60,1',
    'bindings',
    'auth:api',
    \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
],

这是我在app/Http/Controllers/Auth/AuthController.php中的代码

<?php

namespace App\Http\Controllers\Auth;

use App\Http\Requests\Auth\LoginRequest;

use App\Http\Controllers\Controller;

class AuthController extends Controller
{
    /**
     * Authenticate user via given credentials.
     *
     * @param \App\Http\Requests\Auth\LoginRequest $request
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function login(LoginRequest $request)
    {
        $credentials = $request->all(['email', 'password']);

        if (!$token = auth()->attempt($credentials)) {
            return response()->json(['error' => 'Invalid credentials'], 401);
        }

        $cookie = $this->getCookie($token);

        return response()->json([
            'token' => $token,
            'user' => auth()->user(),
        ])->withCookie($cookie);
    }

    /**
     * Set cookie details and return cookie
     *
     * @param string $token JWT
     *
     * @return \Illuminate\Cookie\CookieJar|\Symfony\Component\HttpFoundation\Cookie
     */
    private function getCookie($token)
    {
        return cookie(
            env('AUTH_COOKIE_NAME'),
            $token,
            auth()->factory()->getTTL(),
            null,
            null,
            env('APP_DEBUG') ? false : true,
            true,
            false,
            'Strict'
        );
    }

    public function logout()
    {
        // ...
    }

    public function me()
    {
        // ...
    }
}

而自定义中间件auth.api中使用的中间件类(app/Http/Middleware/AddAuthTokenHeader.php)中handle方法的代码是

public function handle($request, Closure $next)
{
    $cookie_name = env('AUTH_COOKIE_NAME');

    if (!$request->bearerToken()) {
        if ($request->hasCookie($cookie_name)) {
            $token = $request->cookie($cookie_name);

            $request->headers->add([
                'Authorization' => 'Bearer ' . $token
            ]);
        }
    }

    return $next($request);
}

正如您在我的AuthController 中看到的,一旦登录请求成功,json 响应就会与仅 http 的 cookie 一起发送。

注意:我正在使用php artisan serve 运行我的后端

前端

在我的vue-cli 生成的项目中运行npm run serve 后,我转到login 路由,该路由显示Login@/views/Login.vue 表示的组件。

这是我的Login.vue代码

<template>
    <div>
        <form @submit.prevent="submit" autocomplete="off">
            <p>
                <label for="email">Email: </label>
                <input
                    type="email"
                    name="email"
                    id="email"
                    v-model.lazy="form.email"
                    required
                    autofocus
                />
            </p>
            <p>
                <label for="password">Password: </label>
                <input
                    type="password"
                    name="password"
                    id="password"
                    v-model.lazy="form.password"
                    required
                />
            </p>
            <button type="submit">Login</button>
        </form>
    </div>
</template>

<script>
import axios from 'axios';

export default {
    name: 'login',
    data() {
        return {
            form: {
                email: '',
                password: '',
            },
        };
    },

    methods: {
        async submit() {
            const url = 'http://localhost:8000/api/auth/login';
            const response = await axios.post(url, this.form, {
                headers: {
                    Accept: 'application/json',
                    'Content-Type': 'application/json',
                },
            });

            console.log(response);
            // this.$router.replace({ name: 'home' });
        },
    },
};
</script>

给定路由上的有效凭据(http:localhost:8080/login),cookie 将返回,如下面的响应标头所示

但由于某种原因,它没有设置在浏览器 cookie cookie 存储中,如下所示

注意:上面显示的 cookie 来自我在运行 php artisan serve 并在浏览器中打开 http:localhost:8000 后测试是否一切正常。

问题是,为什么 cookie 没有存储在浏览器 cookie 存储中。

我应该注意,当我使用 POSTMAN 调用相同的后端 api 路由时,一切正常(登录时设置 cookie,注销时清除)。

谢谢。

【问题讨论】:

  • 我不熟悉 PHP,所以无法给出完整的答案,但我的第一个想法是您在请求中缺少 withCredentials。见developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/…。默认情况下,axios 不启用此功能,但您可以使用 withCredentials: true 启用它。我相信您还需要确保您的服务器没有使用* 代替Access-Control-Allow-Origin,请参阅developer.mozilla.org/en-US/docs/Web/HTTP/Headers/…
  • @skirtle 谢谢你的提示。让我试试你的建议,看看效果如何。
  • @skirtle 我尝试在我的 axios 标头中设置 withCredentials: true 并将 Access-Control-Allow-Origin 限制为调用客户端,但它仍然无法正常工作。
  • withCredentials 不是标题。请检查 axios 文档并确保将其放在正确的位置。
  • @digout 我知道你来自哪里;我认为您指的是此代码return response()-&gt;json(['token' =&gt; $token, 'user' =&gt; auth()-&gt;user(),])-&gt;withCookie($cookie);。就我而言,我这样做了,所以我可以在我的 vuex 代码中使用它来进行用户身份验证,但事实证明,我不需要它。

标签: laravel vue.js cookies laravel-5.8


【解决方案1】:

感谢@skirtle 帮助我解决了这个问题;您的帮助非常宝贵。

这是我为使其工作而采取的步骤。

后端

我运行命令php artisan vendor:publish --provider="Barryvdh\Cors\ServiceProvider"config 目录下创建一个文件cors.php

然后我将 config/cors.php 中的这一行 'supportsCredentials' =&gt; false, 更改为 'supportsCredentials' =&gt; true, 并保留其他所有内容,然后运行以下命令以确保捕获新的更改。

php artisan config:clear
php artisan cache:clear

php artisan serve

前端

我所要做的就是将Login.vue 中的submit 方法更改为此

async submit() {
    const url = 'http://localhost:8000/api/auth/login';
    const response = await axios.post(url, this.form, {
        withCredentials: true,
        headers: {
            Accept: 'application/json',
            'Content-Type': 'application/json',
        },
    });

    console.log(response.data);
    // this.$router.replace({ name: 'home' });
},

现在正在设置 cookie,如下所示

再次感谢@skirtle 的提示。

【讨论】:

    猜你喜欢
    • 2020-01-06
    • 1970-01-01
    • 2023-04-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-21
    • 2017-02-04
    • 2012-10-20
    相关资源
    最近更新 更多