Laravel 护照和 Vue 登录

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/51881667/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-14 17:59:11  来源:igfitidea点击:

Laravel passport & Vue login

laravelauthenticationvue.jsoauth-2.0laravel-passport

提问by mafortis

I've made login function in laravel with passport api and I'm getting status 200, the issue isthat i don't know how to login the user and redirect to homepage after this successful request (I'm using vuejs component).

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

Code

代码

controller

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

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)

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)

general.js (imported in script above)

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

Question

  1. How can I login my user after successful request?
  1. 请求成功后如何登录我的用户?

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

………………………………………………………………………………………………………………………………………………………… ………………………………………………………………………………………………………………………………………………………… ………………………………………………………………………………………………………………………………………………………… .....

回答by George L.

Say that you have defined a vuex auth module with a login action that accepts a credentials object.

假设您已经定义了一个 vuex auth 模块,其中包含一个接受凭据对象的登录操作。

If success it receives a response that contains the access_token our API granted to the user.

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

We store/commit the token and also update axios settings to use that token on each of the following requests we make.

我们存储/提交令牌并更新 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));
    },
};

Before every request to our API we need to send the token we received and store on our auth module therefore we define a global axios request interceptor on our main.js

在对我们的 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),
);

...

We then define our login component which on a success login redirects us to the dashboard page

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

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

Finally we define our routes and their guards

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

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: '/' },
    ],
});

Now only users with an access token can have access to dashboard route and any child routes you may define in the future. (No further check is necessary as any child of this route will execute that guard).

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

If someone attempts to access dashboard route without an access token will be redirected to login page

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

If someone attempts to access landing or login page with an access token will be redirected back to dashboard.

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

Now what happens if on any of our future API requests our token is invalid?

现在如果在我们未来的任何 API 请求中我们的令牌无效会发生什么?

we add a global axios response interceptor on our main.js and whenever we receive a 401 unathorized response we clear our current token and redirect to login page

我们在 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);
    },
);

...

Final Words

最后的话

I believe that all of the above steps are enough to help you have a better understanding on how to use the access token. Of course you should also store the token on browsers localStorage so that the user doesnot have to login whenever experiences a page refresh and token gets clear from memory. And at least refactor router beforeEnter functions by moving them to a separate file to avoid repetition.

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