Laravel Passport промежуточное программное обеспечение защищенных маршрутов "Неаутентифицированные" проблема - PullRequest
12 голосов
/ 14 июня 2019

Я использую Laravel Passport для аутентификации, поэтому я помещаю свои маршруты в защиту промежуточного ПО.

ОБНОВЛЕНО

Чтобы было понятно, я добавляю UsersController.

public function getUser()
{
    $users = Auth::user();
    return response()->json($users);
}

//

Route::group(['prefix' => 'v1', 'middleware' => 'auth:api'], function () {
    /* users */
    Route::get('/users', 'Api\UsersController@getUser');

    /* fetch */
    Route::get('/articles', 'Api\ArticlesController@allArticles');
    Route::get('/article/{id}', 'Api\ArticlesController@singleArticle');
});

Конечно, мне нужно войти в систему, или я не вижу защищенные маршруты. Я сделал AuthController и внутри него функцию входа в систему контроллера.

Контроллер

public function login(Request $request)
{
    $http = new \GuzzleHttp\Client;
    try {
        $response = $http->post(config('services.passport.login_endpoint'), [
            'form_params' => [
                'grant_type' => 'password',
                'client_id' => config('services.passport.client_id'),
                'client_secret' => config('services.passport.client_secret'),
                'username' => $request->email,
                'password' => $request->password,
            ]
        ]);
        return $response->getBody();
    } catch (\GuzzleHttp\Exception\BadResponseException $e) {
        if ($e->getCode() === 400) {
            return response()->json('Invalid Request. Please enter a username or a password.', $e->getCode());
        }

        if ($e->getCode() === 401) {
            return response()->json('Your credentials are incorrect. Please try again', $e->getCode());
        }

        return response()->json('Something went wrong on the server.', $e->getCode());
    }
}

В интерфейсе моего vuex у меня есть призыв к действию.

retrieveToken(context, credentials){
    return new Promise((resolve, reject) => {
            axios.post("api/v1/login", {
                email: credentials.username,
                password: credentials.password,
            })
            .then(response => {
                const token = response.data.access_token;
                localStorage.setItem("access_token", token);
                context.commit("retrieveToken", token);
                resolve(resolve);
            })
            .catch(error => {
                console.log(error);
                reject(response);
            })
    })
},

Все хорошо. Я храню токен и использую его для входа в систему и удаляю его для выхода из системы. Но на сервере чего-то не хватает. Потому что, даже если войти, я все еще не вижу защищенные маршруты. Аутентификатор Laravel не знает, что пользователь вошел в систему.

Где я должен положить токен в шапку? Внутри контроллера или метода входа? Или мне нужно сделать что-то еще?

Ответы [ 4 ]

3 голосов
/ 08 июля 2019

В компоненте входа используется

methods: {
    login() {
      var instance = axios.create({
        baseURL: "http://tetragolf-api.cubettech.in/api/"
      });

      instance
        .post("/admin-login", {
          email: this.username,
          password: this.password,
          device_type: "Web",
          device_token: "Web"
        })
        .then(response => {
          // console.log(response);

          localStorage.setItem("token", response.data.data.token);
          this.$router.push("/");
        })
        .catch(error => {
          console.log(error);
        });
    }
  },

Затем определите конфигурацию axios в файле как Repository.js, который можно использовать со всеми ресурсами.

/******************** Repository js ****************/
import axios from "axios";
import router from "./router";

const baseDomain = "http://tetragolf-api.cubettech.in";
const baseURL = `${baseDomain}/api`;

const api = axios.create({
    baseURL, // headers: {
    //  'Authorization': 'Bearer ' + localStorage.getItem('api_token')
    // },
    validateStatus: function(status) {
        if (status == 401) {
            router.push("/login");
        } else {
            return status;
        }
    }
});
api.interceptors.request.use(
    function(config) {
        const token = localStorage.getItem("token");

        if (token == null) {
            console.log("Token Is empty");
            console.log("Redirecting to Login");
            router.push({ name: "login" });
        }

        if (token) {
            config.headers.Authorization = `Bearer ${token}`;
        }
        return config;
    },
    function(response) {
        return response;
        console.log(response);
    },
    function(error) {
        console.log(error);

        return error;
    }
);
// Add a response interceptor
api.interceptors.response.use(
    function(response) {
        // Do something with response data
        return response;
    },
    function(error) {
        // Do something with response error
        console.log("Error Found");

        return Promise.reject(error);
    }
);
export default api;

И определить все маршруты Vue в Маршрутизаторе.

3 голосов
/ 14 июня 2019

Также вошедший в систему пользователь видит страницы, которые может видеть только авторизованный пользователь.

Как ты это делаешь? Если пользователь может видеть то, что может видеть пользователь авторизации, что означает, что вы делаете запрос GET с токеном аутентификации, верно? Если вы используете паспорт, вы должны поместить токен в заголовок авторизации.

axios.defaults.headers.common.Authorization = `Bearer ${token}`;

Используйте это, чтобы поместить токен в ваш запрос на все аксиумы после того, как вы войдете в систему, и тогда вам будет хорошо.

2 голосов
/ 11 июля 2019

Если вы просто используете ваш API с помощью javascript , я бы предложил добавить промежуточное программное обеспечение CreateFreshApiToken в вашу группу веб-промежуточного программного обеспечения.

Из документов:

'web' => [
    // Other middleware...
    \Laravel\Passport\Http\Middleware\CreateFreshApiToken::class,
],

В противном случае, как заявили другие, обязательно включите в запрос заголовок Authorization и заголовок Content-Type.

0 голосов
/ 14 июля 2019

Если вы используете аутентификацию по токену с паспортом laravel, всегда устанавливайте заголовок аутентификации (для любого клиентского вызова) Authorization = Bearer your_token для защищенных маршрутов при вызове из клиента. Я делаю простой пример аутентификации с Laravel Passport и Vue.js и загружаю его в github, пожалуйста, проверьте его по этой ссылке . Я также рекомендую вам прочитать этот пост

Ваш логин в Laravel должен выглядеть следующим образом

 public function login (Request $request) {

        $user = User::where('email', $request->email)->first();

        if ($user) {

            if (Hash::check($request->password, $user->password)) {
                $token = $user->createToken('Laravel Password Grant Client')->accessToken;
                $response = ['token' => $token];
                return response($response, 200);
            } else {
                $response = "Password missmatch";
                return response($response, 422);
            }

        } else {
            $response = 'User does not exist';
            return response($response, 422);
        }

мой маршрут Ларавела, 'middleware' => ['json.response'], я использую, чтобы заставить JSON все данные

Route::group(['middleware' => ['json.response']], function () {

    Route::middleware('auth:api')->get('/user', function (Request $request) {
        return $request->user();
    });

    // public routes
    Route::post('/login', 'Api\AuthController@login')->name('login.api');
    Route::post('/register', 'Api\AuthController@register')->name('register.api');

    // private routes
    Route::middleware('auth:api')->group(function () {
        Route::get('/logout', 'Api\AuthController@logout')->name('logout');
    });

});

мой guards в config/auth.php

  'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],

        'api' => [
            'driver' => 'passport',
            'provider' => 'users',
        ],
    ],

, затем в vue вы можете использовать vuex для хранения токена и пользовательские данные для его повторного использования store/index.js

import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

const debug = process.env.NODE_ENV !== 'production'

export default new Vuex.Store({
    strict: debug,
    state: {
        auth: null,
        token: null,
        check:false
    },
    getters: {
        auth: state => state.auth,
        token: state => state.token,
    },
    mutations: {
        SET_TOKEN(state, token) {
            state.token = token
        },

        FETCH_auth_SUCCESS(state, auth) {
            state.auth = auth
            state.check = true
        },

        FETCH_auth_FAILURE(state) {
            state.token = null
        },

        LOGOUT(state) {
            state.auth = null
            state.token = null
            state.check = false
        },

        UPDATE_auth(state, { auth }) {
            state.auth = auth
        }
    },

    actions: {
        saveToken({ commit, dispatch }, { token, remember }) {
            commit('SET_TOKEN', token)

            // if you need store token in cookie (remember me option)
            // Cookies.set('token', token, { expires: remember ? 365 : null })
        },

        async fetchauth({ commit,state }) {
            try {
                axios.defaults.headers.common.Authorization = `Bearer ${state.token}`;
                const { data } = await axios.get('/api/user')

                commit('FETCH_auth_SUCCESS', data)
            } catch (e) {
                //   Cookies.remove('token')
                commit('FETCH_auth_FAILURE')
            }
        },

        updateauth({ commit }, payload) {
            commit('UPDATE_auth', payload)
        },

        async logout({ commit,state }) {
            try {
                axios.defaults.headers.common.Authorization = `Bearer ${state.token}`;
                await axios.get('/api/logout')
            } catch (e) {console.log(e) }

            // Cookies.remove('token')
            commit('LOGOUT')
        },
    }
});

Примечание Я установил токен axios.defaults.headers.common.Authorization = 'Bearer ${state.token}'; для каждого вызова Axios (защищенные маршруты), но вы можете сделать это глобально один раз.

метод входа в vue

 methods: {
    login() {
      console.log("Login");
      axios
        .post("/api/login", {
          email: this.form.email,
          password: this.form.password
        })
        .then(res => {
          // save token to vuex
          this.$store.dispatch("saveToken", { token: res.data.token });
          // get user data, store in vuex
          this.$store.dispatch("fetchauth");
          // redirect
          this.$router.push({path:'/dashboard'});
        })
        .catch(e => {
          console.log(e);
        });
    }
  }

Когда вы совершаете вызов к защищенным маршрутам с помощью 'auth:api', в первую очередь вам необходимо установить токен в заголовке, чтобы получить доступ к ресурсам. В axios это axios.defaults.headers.common.Authorization = 'Bearer ${state.token}';.

...