【问题标题】:Laravel Passport middleware protected routes "Unauthenticated" problemLaravel Passport 中间件保护路由“未验证”问题
【发布时间】:2019-10-28 15:57:48
【问题描述】:

我使用 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 不知道该用户已登录。

我应该将令牌放在哪里?在控制器内部还是登录方法?还是我需要做其他事情?

【问题讨论】:

  • 请在retrieveToken函数内部分享console.log(response)的输出。

标签: laravel vue.js laravel-5 vuejs2 laravel-passport


【解决方案1】:

同时登录的用户看到的页面只有 auth 用户可以看到。

你是怎么做到的?如果用户可以看到身份验证用户可以看到的内容,这意味着您正在使用身份验证令牌发出GET 请求,对吗?如果您使用的是护照,则应将令牌放入您的 Authorization 标头中。

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

登录后使用它将令牌放入所有 axios 请求中,那么你应该很高兴。

【讨论】:

  • 我试图把它放在fetchToken() 的里面然后.then() 部分但仍然弹出同样的错误。
  • 尝试检查你的标题,Authorization 标题在那里吗?
  • 当我在那里登录时,但当我刷新页面时它消失了。
  • 那你在加载你的应用的时候把token放到header里面了吗?
  • 我保存了令牌 localStorage。并在我获取文章或用户时使用该令牌(将其放在标题上)......例如像这样。 imgur.com/a/duEJIFT 我可以在控制台看到 json 的预览。但是在浏览器上看不到端点,它说您必须登录... @NipunTharuksha 将我重定向到登录页面
【解决方案2】:

在登录组件中使用

methods: {
    login() {
      var instance = axios.create({
        baseURL: "http://apiendpoint.com/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://apiendpoint.com/api/";
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;

并在Router中定义所有vue路由。

【讨论】:

    【解决方案3】:

    如果您只是 Consuming your api with javascript,我建议您将 CreateFreshApiToken 中间件添加到您的 Web 中间件组。

    来自文档:

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

    否则,正如其他人所说,请确保在您的请求中包含 Authorization 标头和 Content-Type 标头。

    【讨论】:

      【解决方案4】:

      如果您使用带有 laravel 护照的令牌进行身份验证,请务必在从客户端调用时为受保护的路由设置身份验证标头(对于任何客户端调用)Authorization = Bearer your_token。我用 Laravel Passport 和 Vue.js 做了一个简单的身份验证示例并将其上传到 github 请查看on this link。我还建议您阅读this post

      你在 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');
          });
      
      });
      

      我的guardsconfig/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}';,但您可以在全局范围内执行一次。

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

      【讨论】:

        猜你喜欢
        • 2021-12-06
        • 2020-05-10
        • 1970-01-01
        • 1970-01-01
        • 2015-12-17
        • 2018-06-30
        • 2020-08-02
        • 2015-08-12
        • 2018-08-20
        相关资源
        最近更新 更多