Laravel Проблема с rest api приложением с использованием jwt-auth

mstdmstd

Новичок
Всем привет,
Делая laravel 7 backend rest api приложение с использованием jwt-auth и настройками в /config/jwt.php
PHP:
[B]'ttl' [/B]=> 20,  [I]# 20 minutes[/I]
'refresh_ttl' => 20160, // [I]2 weeks[/I]
и с @vue/cli 4.0.5 / vuex приложением для клиента

Проблема что если пользователь работает под логином то через 20 минут генерится 401 ошибка
с логаутом на фронтенде
Но нужно чтобы 401 генерился если в течении 20 минут клиентское приложение простаивает...
Тут https://github.com/tymondesigns/jwt-auth/wiki/Authentication
я нашел описание метода getAuthenticatedUser - вроде он для этого и предназачен ?

Я вставил его в свой app/Http/Controllers/API/AuthController.php и натыкал в него
сообщений в лог - и вижу что этот метод не вызывается.

В app/Http/Kernel.php :

PHP:
    protected $routeMiddleware = [
        'auth' => \App\Http\Middleware\Authenticate::class,
        'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
        'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
        'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
        'can' => \Illuminate\Auth\Middleware\Authorize::class,
        'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
        'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
        'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
        'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
        'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,

        'jwt.auth' => 'Tymon\JWTAuth\Middleware\GetUserFromToken',
        'jwt.refresh' => 'Tymon\JWTAuth\Middleware\RefreshToken',

    ];
/config/auth.php :
PHP:
    'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],

        'api' => [
            'driver' => 'jwt',
            'provider' => 'users',
            'hash' => false,
        ],
    ],
routes/api.php :
PHP:
Route::middleware('auth:api')->get('/user', function (Request $request) {
    return $request->user();
});

Route::post('app_settings', 'API\HomeController@app_settings');

Route::post('login', 'API\AuthController@login');
Route::post('register', 'API\AuthController@register');
Route::post('logout', 'API\AuthController@logout');
Route::post('refresh', 'API\AuthController@refresh');
Route::post('me', 'API\AuthController@me');

Route::group(['middleware' => 'jwt.auth',  'prefix' => 'adminarea', 'as' => 'adminarea.'], function ($router) {
   Route::get('dashboard', 'API\Admin\DashboardController@index');
   ...
app/Http/Controllers/API/Admin/DashboardController.php :

PHP:
<?php

namespace App\Http\Controllers\API\Admin;

use App\Http\Resources\TaskCollection;
use Auth;
use DB;
use Validator;
use App\User;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Facades\MyFuncsClass;

class DashboardController extends Controller
{
    private $requestData;

    public function __construct()
    {
        $request           = request();
        $this->requestData = $request->all();
    }

    public function index()
    {
        if ( ! MyFuncsClass::checkUserGroup([ACCESS_ROLE_ADMIN])) {
            return response()->json(['error' => 'Unauthorized'], HTTP_RESPONSE_NOT_UNAUTHORIZED);
        }

        $loggedUser = Auth::guard('api')->user();

        \Log::info('PersonalController index $loggedUser->id::');
        \Log::info(print_r(  $loggedUser->id, true  ));
Я полагаю что как раз при вызове
PHP:
        $loggedUser = Auth::guard('api')->user();
и должен вызываться метод getAuthenticatedUser
Но видимо что-то не настроено ?

Спасибо !
 

fixxxer

К.О.
Партнер клуба
Упустил, что клиентское приложение должно уметь рефрешить токен.
 

fixxxer

К.О.
Партнер клуба
Если внимательно присмотреться, то проще, думаю, тебе будет использовать миддлварь 'jwt.refresh', вот же в мануале:

This middleware will again try to parse the token from the request, and in turn will refresh the token (thus invalidating the old one) and return it as part of the next response. This essentially yields a single use token flow, which reduces the window of attack if a token is compromised, since it is only valid for the single request.
Скорее всего, достаточно ее начать использовать и все заработает. но это не точно, я же не вижу код клиента.

С ней будет рефрешить токен на каждый запрос и инвалидировать существующий. С точки зрения безопасности это ок, но хранилище блеклистнутых токенов может с таким подходом непомерно распухнуть.

Альтернатива - рефрешить ручками, это уж клиент должен делать - получив ошибку, что токен проэкспайрился, дернуть рефреш ендпоинт. Как конкретно - откуда я знаю? Ты ни строчки кода на JS не показал.
 
Последнее редактирование:

mstdmstd

Новичок
На клиенте в src/views/auth/Login.vue:
JavaScript:
        onSubmit() {

                this.$refs.loginObserverForm.validate().then(success => {
                    if (!success) {
                        this.showPopupMessage('Login', 'Validations Failed !', 'warn')
                        return
                    }
                    this.$store.dispatch('login', this.loginData)
                        .then(() => this.$router.push('/'))
                        .catch(error => console.log(error))
                    this.$nextTick(() => {
                        this.$refs.loginObserverForm.reset()
                    })
                })
         } // onSubmit

и в src/store/index.js :
JavaScript:
import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'
import {bus} from '../main'

import {settingCredentialsConfig} from '@/app.settings.js'

Vue.use(Vuex)

export default new Vuex.Store({
    state: {// store data
        status: '',
        token: localStorage.getItem('token') || '',
        user: null,
    }, // state: { // store data

    getters: {


    actions: { // async methods
        login({commit}, userCredentials) { // Login action
            return new Promise((resolve, reject) => {
                commit('auth_request')
                let apiUrl = process.env.VUE_APP_API_URL
                axios.post(apiUrl + '/login', userCredentials, settingCredentialsConfig)
                    .then((response) => {
                        if (typeof response.data.access_token === 'undefined' || typeof response.data.user === 'undefined') {
                            commit('auth_error') // call auth_error mutation to make changes to vuex store
                            bus.$emit('authLoggedError')
                            return
                        }

                        const token = response.data.access_token
                        const user = response.data.user
                        let avatar_url= ''
                        if ( typeof response.data.filenameData != 'undefined')
                        {
                            avatar_url = response.data.filenameData.avatar_url
                        }
                        axios.defaults.headers.common['Authorization'] = token
                        commit('auth_success', {token: token, user: user, avatar_url : avatar_url }) // call auth_success mutation to make changes to vuex store
                        bus.$emit('authLoggedSuccess', user)
                        resolve(response)
                    })
                    .catch((error) => {
                        commit('auth_error') // call auth_error mutation to make changes to vuex store
                        localStorage.removeItem('token')
                        bus.$emit('authLoggedError')
                        reject(error)
                    })
            })
        }, // login ({ commit }, user) { // Login action
я обрабатываю запросы в src/App.vue:

JavaScript:
        created() {
            let self = this
            this.$http.interceptors.response.use(undefined, function (error) {

                return new Promise(function (/*resolve, reject*/) {
                    if (typeof error.response.status !== 'undefined' && error.response.status === 401) {
                        self.$store.dispatch('logout')  // DEBUGGING
                        self.showPopupMessage('Access', 'Not authorized !', 'warn')
                        let splitted0 = self.getSplitted(error.response.config.url, '/login', 0)

                        if (splitted0 == '') { // not move from login page
                            self.$router.push('/login')   // DEBUGGING
                        }
                    }

                    if (typeof error.response.status !== 'undefined') {
                        if (error.response.status === 401) {
                            self.$store.dispatch('logout') // DEBUGGING
                            self.showPopupMessage('Access', 'Not authorized !', 'warn')
                            self.$router.push('/login')  // DEBUGGING
                        }
                    }

                    throw error
                })
            })


        }, //  created() {
Где я отлавливаю ошибку 401 и видимо тут но как?
 

fixxxer

К.О.
Партнер клуба
Где я отлавливаю ошибку 401 и видимо тут но как?
Из формулировки и кучи копипасты не по сути дела можно сделать вывод, что этот код писал не ты. (Копипаста со stackoverflow написанием не считается).

Тут надо взять https://www.npmjs.com/package/axios-jwt и не мучаться. Или хотя бы посмотреть, как в нем сделано.
 
Сверху