未设置/存储Httponly cookie(Laravel / Vue)

时间:2019-11-05 11:04:32

标签: laravel vue.js cookies laravel-5.8

我已经在如何解决这个问题上苦苦挣扎了几个小时,而我似乎暂时无法解决它。

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

BACKEND

这是我在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()
    {
        // ...
    }
}

自定义中间件app/Http/Middleware/AddAuthTokenHeader.php中使用的中间件类(auth.api)中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来运行我的后端

前端

在我的npm run serve生成的项目中运行vue-cli之后,我转到了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,如下面的响应标头所示

enter image description here

但是由于某些原因,未在浏览器cookie的cookie存储中设置它,如下所示。

enter image description here

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

问题是,为什么cookie不存储在浏览器cookie存储中?

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

谢谢。

1 个答案:

答案 0 :(得分:0)

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

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

BACKEND

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

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

php artisan config:clear
php artisan cache:clear

php artisan serve

前锋

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

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

enter image description here

再次感谢和感谢@skirtle的提示。