【问题标题】:Vue.js / Laravel - Handle logout correctlyVue.js / Laravel - 正确处理注销
【发布时间】:2019-01-31 22:26:13
【问题描述】:

我目前正在尝试使用 Vue 和 Laravel 创建一个简单的 SPA。我已经掌握了基本工作 - 用户可以注册和登录。

我只是不知道如何创建注销功能。

这是我目前拥有的:

AuthController.php:

public function logout()
{
        $accessToken = auth()->user()->token();

        $refreshToken = DB::table('oauth_refresh_tokens')
        ->where('access_token_id', $accessToken->id)
        ->update([
            'revoked' => true
        ]);

        $accessToken->revoke();

        return response()->json(['status' => 200]);
}

routes/api.php:

Route::middleware('auth:api')->group(function () {
    Route::post('/logout', 'API\AuthController@logout');
    Route::get('/get-user', 'API\AuthController@getUser');
});

现在,这是我尝试做的:

Layout.vue:

methods: {
            logout() {
                axios.post('/api/logout').then(response => {
                    this.$router.push("/login")

                }).catch(error => {
                    location.reload();
                });
            }
 }

Auth.js中调用我的注销功能:

logout() {
    localStorage.removeItem('token')
    localStorage.removeItem('expiration')
}

但是,当用户点击注销功能时,他们不会立即注销(重定向到登录页面)——他们仍然可以浏览“仅限用户页面”。

我必须在正确注销之前刷新页面。

谁能帮我解决这个问题?这甚至是“安全”注销功能的正确方法吗?

【问题讨论】:

    标签: php laravel vue.js vuejs2


    【解决方案1】:

    要注销安装 axios 并在 Laravel 6* / 7* / 8* 中执行其余代码

    npm install axios
    

    点击注销时触发此代码

    axios.post("logout").then(response => { 
       console.log(response);
    })
    .catch(error => {
       console.log(error);
    });
    

    【讨论】:

      【解决方案2】:

      这有点老了,但是,我刚开始使用 Laravel/Vue 并设法做到这一点非常简单。使用 Laravel 的集成身份验证,您可以像这样模拟 app.blade.php 的注销:

      <b-dropdown-item href="#" onclick="event.preventDefault(); document.getElementById('logout-form').submit();">Sign Out</b-dropdown-item> //that's instead of a regular <a> tag
      <b-form id="logout-form" action="logout" method="POST" style="display: none;">
         <input type="hidden" name="_token" :value="csrf">
      </b-form>
      

      您需要让 csrf 令牌通过脚本中的数据传递,以便它像这样工作:

      export default {
       data() {
         return {
           csrf: document.querySelector('meta[name="csrf-token"]').getAttribute('content')
         }
       },
       methods: {
         submit : function(){
           this.$refs.form.submit();
         }
       }
      }
      

      除了在你的头脑中添加一个元 csrf(blade.php 文件),像这样:

      <meta name="csrf-token" content="{{ csrf_token()}}">
      

      我假设您将在导航栏 .vue 文件中使用注销

      【讨论】:

        【解决方案3】:

        对于我的注销链接,我想向 Laravel 发出请求,以使当前用户的 (Passport JWT) 令牌无效。

        这是我的做法:

        在我的后端

        AuthController.php

        我有一个注销方法:

          ...
        
          public function logout(Request $request) {
            $request->user()->token()->revoke();
        
            return response()->json([
               'message' => 'Successfully logged out'
            ]);
          }
        

        routes/api.php

        我有一条只有经过身份验证才能访问的路由。

        Route::group(['middleware' => 'auth:api'], function() {
          ...
        
          Route::get('/logout', 'AuthController@logout');
        });
        

        我的前端:

        为此,我使用 Vue 的 single file components

        App.vue

        <template>
          <nav>
            <ul>
              ...
                <li v-if="isLoggedIn">
                  <a id="logout-link" href="#" @click.prevent="logout">Logout</a>
                </li>
            </ul>
          </nav>
          ...
        </template>
        
        <script>
        export default {
           ...
           methods: {
             logout(evt) {
               if(confirm("Are you sure you want to log out?")) {
                 axios.get('api/logout').then(response => {
                  localStorage.removeItem('auth_token');
        
                  // remove any other authenticated user data you put in local storage
        
                  // Assuming that you set this earlier for subsequent Ajax request at some point like so:
                  // axios.defaults.headers.common['Authorization'] = 'Bearer ' + auth_token ;
                  delete axios.defaults.headers.common['Authorization'];
        
                  // If using 'vue-router' redirect to login page
                  this.$router.go('/login');
                })
                .catch(error => {
                  // If the api request failed then you still might want to remove
                  // the same data from localStorage anyways
                  // perhaps this code should go in a finally method instead of then and catch
                  // methods to avoid duplication.
                  localStorage.removeItem('auth_token');
                  delete axios.defaults.headers.common['Authorization'];
                  this.$router.go('/login');
                });       
               }
             }
           }
        }
        </script>
        

        这种方法的重点是在注销时使后端的令牌无效。不过,如果令牌的到期日期较短,则可能没有必要这样做。

        【讨论】:

          【解决方案4】:

          尝试在成功注销时使用 javascript 重定向:

          window.location.replace("desiredURL");
          

          【讨论】:

          • 我更喜欢在 Vue 中处理一切
          【解决方案5】:

          我自己从未使用过 Laravel,但您应该能够在客户端处理注销,而无需在后端执行任何操作。目前您从本地存储中删除身份验证令牌,因此用户无法访问需要您登录才能获取的数据。

          当您刷新页面时,您可能会调用您的getUser,这就是为什么您当时只注销 - 您将空令牌发送到后端服务器,它找不到与之关联的用户并返回一个空/默认来宾对象。剩下要做的就是在删除 logout() 函数中的令牌或向 /get-user 端点发送请求后清除您的用户状态。

          【讨论】:

          • 听起来正确。关于如何实现这一点的任何想法?一个例子?抱歉,我对 Vue 很陌生
          • localStorage.removeItem('expiration')之后做类似axios.get('/api/get-user').then(response =&gt; { &lt;your_user_data_state&gt; = response.data }).catch(err =&gt; console.log(err.response.data))的事情
          • 你不需要注销路由来处理注销;您需要重置您现在在页面刷新时执行的用户状态。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2018-01-15
          • 2010-09-22
          • 2013-09-27
          • 2021-11-25
          • 2016-01-02
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多