web-dev-qa-db-ja.com

Laravel Passportミドルウェアで保護されたルートの「認証されていない」問題

認証に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のAuthは、そのユーザーがログインしていることを認識していません。

ヘッダーのどこにトークンを入れればよいですか?コントローラまたはログインメソッドの内部?または私は何か他のことをする必要がありますか?

13
user10828115

laravel passportでトークンによる認証を使用する場合は、常にクライアントから呼び出したときに、保護されたルートに認証ヘッダー(クライアント呼び出しの場合)Authorization = Bearer your_tokenを設定してください。 Laravel PassportとVue.jsを使用してgithubにアップロードした簡単な認証の例を確認してください このリンクで 。また、お読みになることをお勧めします this投稿

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);
        }

私のlaravelルート、'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 in 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呼び出し(保護されたルート)にトークンaxios.defaults.headers.common.Authorization = 'Bearer ${state.token}';を設定しましたが、これはグローバルに1回実行できます。

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}';です。

0
Sabee