Laravel 护照和 Vue 登录

Posted

技术标签:

【中文标题】Laravel 护照和 Vue 登录【英文标题】:Laravel passport & Vue login 【发布时间】:2019-01-23 16:28:30 【问题描述】:

我已经在 laravel 中使用护照 api 进行了登录功能,我得到状态 200,问题是我不知道如何登录用户并在成功后重定向到主页请求 (我正在使用 vuejs 组件).

代码

controller

public function login(Request $request)
    
        $credentials = [
            'email' => $request->email,
            'password' => $request->password
        ];

        if (Auth::attempt($credentials)) 
            // $token = auth()->user()->createToken('AppName')->accessToken;
            // $success['token'] =  $token;
            // $success['name'] =  auth()->user()->name;
            // $success['id'] =  auth()->user()->id;
          $user = Auth::user();
            $success['token'] = $user->createToken('AppName')->accessToken;
            $success['user'] = $user;
            return response()->json(['success'=>$success], 200);
         else 
            return response()->json(['error' => 'UnAuthorised'], 401);
        
    

component script

<script>
    import login from '../../helpers/Auth';

    export default 
        name: "login",
        data() 
            return 
                form: 
                    email: '',
                    password: ''
                ,
                error: null
            ;
        ,
        methods: 
            authenticate() 
                this.$store.dispatch('login');

                axios.post('/api/auth/login', this.form)
                .then((response) => 
                    setAuthorization(response.data.access_token);
                    res(response.data);
                )
                .catch((err) =>
                    rej("Wrong email or password");
                )

            
        ,
        computed: 
            authError() 
                return this.$store.getters.authError;
            
        
    
</script>

Auth.js (imported in script above)

import  setAuthorization  from "./general";

export function login(credentials) 
    return new Promise((res, rej) => 
        axios.post('/api/auth/login', credentials)
            .then((response) => 
                setAuthorization(response.data.access_token);
                res(response.data);
            )
            .catch((err) =>
                rej("Wrong email or password");
            )
    )

general.js (imported in script above)

export function setAuthorization(token) 
    axios.defaults.headers.common["Authorization"] = `Bearer $token`

问题

    请求成功后如何登录我的用户?

.................................................. ..................................................... ..................................................... ........

【问题讨论】:

如果令牌正确,则用户将在服务器上获得授权。如果您有令牌,您还需要从服务器获取用户。 我不太明白你的问题是什么。如果你得到一个 200 状态码,你也会得到一个令牌。该令牌表示用户已登录。您可以向要求用户使用该令牌登录的端点发出请求。您已经登录。如果您正在制作一个 SPA,那么this.$router.push('/') 就足以进入主页。您可能希望将登录状态保存在 vuex 存储中。 @Sumurai8 这正是我想要做的,我得到状态 200 和令牌,我所需要的只是在前端带来服务器登录,因此用户可以避免看到登录页面也可以可以访问他们的个人资料页面等。我不知道如何将该服务器登录名带到前端你能帮忙吗? @ИльяЗеленько 我确实有令牌,问题是我不知道如何在前端使用该令牌,所以用户知道是登录并且可以访问需要身份验证的部分 @mafortis,当您拥有令牌时,您可以在每个页面上获取用户。 Token 必须存储在 localeStorage 或 Cookie 中。如果你已经接收到一个用户,那么认为这个用户是被授权的,你可以使用他的数据。或者您不知道如何存储令牌和用户?网上有很多指南。 【参考方案1】:

假设你已经定义了一个带有登录操作的 vuex auth 模块 接受凭据对象。

如果成功,它会收到一个响应,其中包含我们的 API 授予用户的 access_token。

我们存储/提交令牌并更新 axios 设置以在我们发出的以下每个请求中使用该令牌。

import axios from 'axios';

const state = 
    accessToken: null,
;

const mutations = 
    setAccessToken: (state, value) => 
        state.accessToken = value;
    ,
;

const getters = 
    isAuthenticated: (state) => 
        return state.accessToken !== null;
    ,
;

const actions = 
    /**
     * Login a user
     * 
     * @param context Object 
     * @param credentials Object User credentials
     * @param credentials.email string User email
     * @param credentials.password string User password
     */
    login(context, credentials) 
        return axios.post('/api/login', credentials)
            .then((response) => 
                // retrieve access token
                const  access_token: accessToken  = response.data;

                // commit it
                context.commit('setAccessToken', accessToken);

                return Promise.resolve();
            )
            .catch((error) => Promise.reject(error.response));
    ,
;

在向我们的 API 发出每个请求之前,我们需要发送我们收到的令牌并存储在我们的 auth 模块中,因此我们在 main.js 上定义了一个全局 axios 请求拦截器

import store from '@/store';

...

axios.interceptors.request.use(
    (requestConfig) => 
        if (store.getters['auth/isAuthenticated']) 
            requestConfig.headers.Authorization = `Bearer $store.state.auth.accessToken`;
        
        return requestConfig;
    ,
    (requestError) => Promise.reject(requestError),
);

...

然后我们定义我们的登录组件,在成功登录时将我们重定向到仪表板页面

<template>
    <div>
        ...
        <form @submit.prevent="submit">
            ...
            <button>Submit</button>
        </form>
        ...
    </div>
</template>

<script>
import  mapActions  from 'vuex';

export default 
    data() 
        return 
            credentials: 
                email: '',
                password: '',
            ,
        ;
    ,
    methods: 
        ...mapActions('auth', [
            'login',
        ]),
        submit() 
            this.login( ...this.credentials )
                .then(() => 
                    this.$router.replace('/dashboard');
                )
                .catch((errors) => 
                    // Handle Errors
                );
        ,
    ,

最后我们定义了我们的路线和他们的守卫

import store from '@/store'

export default new Router(
    mode: 'history',
    routes: [
        
            path: '/',
            name: 'landing',
            component: Landing,
            // User MUST NOT BE authenticated
            beforeEnter: (to, from, next) => 
                const isAuthenticated = store.getters['auth/isAuthenticated'];

                if (isAuthenticated) 
                    return next(
                        name: 'dashboard',
                    );
                

                return next();
            ,
        ,
        
            path: '/login',
            name: 'login',
            component: Login,
            // User MUST NOT BE authenticated
            beforeEnter: (to, from, next) => 
                const isAuthenticated = store.getters['auth/isAuthenticated'];

                if (isAuthenticated) 
                    return next(
                        name: 'dashboard',
                    );
                

                return next();
            ,
        ,
        
            path: '/dashboard',
            name: 'dashboard',
            component: Dashboard,
            // User MUST BE authenticated
            beforeEnter: (to, from, next) => 
                const isAuthenticated = store.getters['auth/isAuthenticated'];

                if (!isAuthenticated) 
                    return next(
                        name: 'login',
                    );
                

                return next();
            ,
        ,
         path: '*', redirect: '/' ,
    ],
);

现在只有拥有访问令牌的用户才能访问仪表板路由以及您将来可能定义的任何子路由。 (无需进一步检查,因为这条路线的任何孩子都会执行该守卫)。

如果有人尝试在没有访问令牌的情况下访问仪表板路由,将被重定向到登录页面

如果有人尝试使用访问令牌访问登录页面或登录页面,将被重定向回仪表板。

如果我们未来的任何 API 请求我们的令牌无效,会发生什么情况?

我们在 main.js 上添加一个全局 axios 响应拦截器,每当我们收到 401 未经授权的响应时,我们都会清除当前令牌并重定向到登录页面

import store from '@/store';

...

axios.interceptors.response.use(
    response => response,
    (error) => 

        if (error.response.status === 401) 
            // Clear token and redirect
            store.commit('auth/setAccessToken', null);
            window.location.replace(`$window.location.origin/login`);
        

        return Promise.reject(error);
    ,
);

...

结束语

我相信以上所有步骤都足以帮助您更好地了解如何使用访问令牌。当然,您还应该将令牌存储在浏览器的 localStorage 中,这样用户在经历页面刷新并且令牌从内存中清除时不必登录。并且至少重构 router beforeEnter 函数,将它们移动到一个单独的文件以避免重复。

【讨论】:

嗨,非常感谢这个完整的答案。我会对其进行测试并回复您。

以上是关于Laravel 护照和 Vue 登录的主要内容,如果未能解决你的问题,请参考以下文章

Laravel 护照 - 允许用户作为/登录为其他用户

Laravel 护照范围

Laravel 护照公共 api 路线

Laravel 护照授权错误

在 Laravel 护照、vueJS 和 Axios 中获得未经授权的 401

Laravel 护照 500 内部服务器错误