Аксиос не отправляет куки - PullRequest
1 голос
/ 28 октября 2019

У меня есть два приложения: приложение на стороне сервера, написанное на Laravel, и приложение на стороне клиента, написанное на VueJS. Приложение vue использует API, предоставленный приложением laravel.

Поток аутентификации:

Пользователь пытается войти в систему, сервер отправляет два токена клиенту,а) access_token и б) refresh_token при успешном входе в систему. Сервер также отправляет клиенту токен обновления в виде httpOnly cookie, чтобы по истечении срока действия токена доступа его можно было обновить с помощью токена обновления из cookie.

проблема:

Когда пользователь входит в систему, в ответ сервер отправляет следующий заголовок Set-Cookie:

Set-Cookie: refresh_token = tokenvalue;истекает = понедельник, 04 ноября 2019 09:13:28 по Гринвичу;Max-Age = 604800;Путь = / V1 / обновления;домен = http://app.test; httponly;samesite = none

Это означает, что я ожидаю, что cookie будет отправляться на сервер всякий раз, когда есть запрос к конечной точке /v1/refresh. Однако файл cookie отсутствует в запросе. (Я зарегистрировал $request->cookie('refresh_token') в контроллере, но он регистрирует null).

Весь этот механизм обновления токена обрабатывается в действии vuex:

export function refreshToken({commit}, payload) {
    return new Promise((resolve, reject) => {
        // axios.defaults.withCredentials = true;

        // here, payload() function just converts the url to:
        // "http://app.test/v1/refresh"

        axios.post(payload('/refresh'), {}, {
            withCredentials: true, transformRequest: [(data, headers) => {
                delete headers.common.Authorization;
                return data;
            }]
        }).then(response => {
            let token = response.data.access_token;
            localStorage.setItem('token', token);
            commit('refreshSuccess', token);
            resolve(token);
        }).catch(err => reject(err));
    });
}

Как вы можете видеть,Я установил для withCredentials config значение true. Я также отправляю Access-Control-Allow-Credentials: true с сервера. Вот мое промежуточное ПО для cors:

public function handle($request, Closure $next)
    {
        $whiteList = ['http://localhost:8080'];
        if (isset($request->server()['HTTP_ORIGIN'])) {
            $origin = $request->server()['HTTP_ORIGIN'];
            if (in_array($origin, $whiteList)) {
                header('Access-Control-Allow-Origin: ' . $request->server()['HTTP_ORIGIN']);
                header('Access-Control-Allow-Methods: GET, POST, PATCH, PUT, DELETE, OPTIONS');
                header('Access-Control-Allow-Headers: Origin, Content-Type, Authorization');
                header('Access-Control-Allow-Credentials: true');
                header('Access-Control-Expose-Headers: Content-Disposition');
            }
        }
        return $next($request);
    }

Я не знаю, что я сделал не так. Моя версия PHP: 7.3.5. Вот заголовки запроса конечной точки /v1/refresh:

Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9,bn;q=0.8
Connection: keep-alive
Content-Length: 15
Content-Type: application/x-www-form-urlencoded
Host: app.test
Origin: http://localhost:8080
Referer: http://localhost:8080/products
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.70 Safari/537.36

... и заголовки ответа:

Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: Origin, Content-Type, Authorization
Access-Control-Allow-Methods: GET, POST, PATCH, PUT, DELETE, OPTIONS
Access-Control-Allow-Origin: http://localhost:8080
Access-Control-Expose-Headers: Content-Disposition
Cache-Control: no-cache, private
Connection: keep-alive
Content-Type: application/json
Date: Mon, 28 Oct 2019 09:40:31 GMT
Server: nginx/1.15.5
Transfer-Encoding: chunked
X-Powered-By: PHP/7.3.5
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59

Я не знаю, как работает хранение cookie в браузере. Механизм, я также не знаю, можно ли найти файл cookie httpOnly в файловой системе, но в отчаянии, чтобы узнать, действительно ли браузер действительно сохраняет этот файл cookie, я гуглил и обнаружил, что файлы cookie хранятся в файле ~/Library/Application Support/Google/Chrome/Default/Cookies, которыйфайл SQLite. Я открыл этот файл и искал свой файл cookie ?, но его там тоже не было (может быть, httpOnly файлы cookie хранятся где-то еще?).

Теперь мой вопрос: как мне получить файл cookie от клиентаприложение?

1 Ответ

1 голос
/ 28 октября 2019

Поскольку ваше приложение Vue и Laravel (API) имеют разный HOST, оно не будет работать.

Вы можете перепроверить свой ответ сервера:

Set-Cookie: refresh_token= tokenvalue;истекает = понедельник, 04 ноября 2019 09:13:28 по Гринвичу;Max-Age = 604800;Путь = / V1 / обновления;домен = http://app.test; httponly;samesite = none

Устанавливает cookie на http://app.test, а не http://localhost:8080. Таким образом, в вашем http://localhost:8080.

нет набора файлов cookie refresh_token. Очень типичное решение:

  1. Вам необходимо использовать поддомен и разрешить использование файлов cookie. установить на domain=.app.test (весь домен). Я имею в виду, вам нужно убедиться, что Laravel и Vue находятся в одном домене.

  2. Вам не нужно снова получать refresh_token из cookie в вашем приложении Laravel. Во-первых, вам просто нужно сохранить refresh_token, который вы получаете из API, в localStorage или cookie в вашем приложении Vue. Затем просто отправьте refresh_token через формы (данные формы). Наконец, получите refresh_token через $request->get('refresh_token').

Вот пример, просто чтобы проиллюстрировать, что я имею в виду для второго решения.

Предположим (обычно) http://app.test/api/login ответит:

{
    "token_type": "Bearer",
    "expires_in": 31622399,
    "access_token": "xxx",
    "refresh_token": "xxx"
}
import Cookies from 'js-cookie'

async login() {
    const { data } = await axios.post('http://app.test/api/login', {
        email: 'hi@app.test',
        password: 'secret',
    })

    const refreshToken = data.refresh_token

    Cookies.set('refresh_token', refreshToken)
},
async refreshToken() {
    const refreshToken = Cookies.get('refresh_token')

    const response = await axios.post('http://app.test/api/refresh-token', {
        refresh_token: refreshToken,
    })
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...