如果用户已经通过身份验证,使用 vue.js 和 Auth0 如何跳过登录页面?

kin*_*ian 5 auth0 vue-router vue-component vuejs2 vuetify.js

描述

我有一个非常标准SPA的内置vue.js我使用其中Auth0通过以下的处理认证部正式例子。应用流程如下:

Register in the Initial.vue via Auth0 lock-> Callback is called->User's redirected to /home

上述流程中的所有内容都可以正常工作,但问题在于:

问题

一旦用户注册并且/home我希望他能够访问所有其他路由(例如/doctors),如果经过身份验证,如果没有,他应该提示他再次登录。根据上面的链接,这是在router.beforeEach函数中处理的。

访问/登录页面 ( Initialvue)时出现我的问题。当用户已经注册并尝试访问该路线时,我希望他被重定向到/home并跳过该login页面。我试过用beforeEnter路由来实现它,但auth.isAuthenticated由于为tokenExpiry空而失败(即使用户已经过身份验证!

代码

我的AuthService.js

import auth0 from 'auth0-js';
import EventEmitter from 'events';
import authConfig from '../config/auth_config.json';

const webAuth = new auth0.WebAuth({
  domain: authConfig.domain,
  redirectUri: `${window.location.origin}/callback`,
  clientID: authConfig.clientId,
  responseType: 'id_token',
  scope: 'openid profile email'
});

const localStorageKey = 'loggedIn';
const loginEvent = 'loginEvent';

class AuthService extends EventEmitter {
  idToken = null;
  profile = null;
  tokenExpiry = null;

  // Starts the user login flow
  login(customState) {
    webAuth.authorize({
      appState: customState
    });
  }

  // Handles the callback request from Auth0
  handleAuthentication() {
    return new Promise((resolve, reject) => {
      webAuth.parseHash((err, authResult) => {
        if (err) {
          reject(err);
        } else {
          this.localLogin(authResult);
          resolve(authResult.idToken);
        }
      });
    });
  }

  localLogin(authResult) {
    // console.log(authResult); TODO-me: Handle this
    this.idToken = authResult.idToken;
    this.profile = authResult.idTokenPayload;

    // Convert the JWT expiry time from seconds to milliseconds
    this.tokenExpiry = new Date(this.profile.exp * 1000);

    localStorage.setItem(localStorageKey, 'true');

    this.emit(loginEvent, {
      loggedIn: true,
      profile: authResult.idTokenPayload,
      state: authResult.appState || {}
    });
  }

  renewTokens() {
    return new Promise((resolve, reject) => {
      if (localStorage.getItem(localStorageKey) !== "true") {
        return reject("Not logged in");
      }``;

      webAuth.checkSession({}, (err, authResult) => {
        if (err) {
          reject(err);
        } else {
          this.localLogin(authResult);
          resolve(authResult);
        }
      });
    });
  }

  logOut() {
    localStorage.removeItem(localStorageKey);

    this.idToken = null;
    this.tokenExpiry = null;
    this.profile = null;

    webAuth.logout({
      returnTo: window.location.origin
    });

    this.emit(loginEvent, { loggedIn: false });
  }

  isAuthenticated() {
     console.log('In tokenExp is:');
     console.log(this.tokenExpiry); //THIS returns null when /home -> /
    return (
      Date.now() < this.tokenExpiry &&
      localStorage.getItem(localStorageKey) === 'true'
    );
  }
}

export default new AuthService();
Run Code Online (Sandbox Code Playgroud)

我的Initial.vue

<template>
    <v-container
        app
        fluid
    >
        <v-parallax
            src="https://cdn.vuetifyjs.com/images/backgrounds/vbanner.jpg"
            height="1000"
        >
            <v-layout
                row
                wrap
            >
                <!-- LOGIN-->

                    <v-toolbar
                        flat
                        light
                        dense
                        color="transparent"
                    >
                        <v-spacer></v-spacer>
                        <v-toolbar-items>
                            <v-btn
                                medium
                                color="lime lighten-2"
                                @click="login"
                                class="font-weight-bold title text-uppercase"
                            >
                                Login
                            </v-btn>
                        </v-toolbar-items>
                    </v-toolbar>
            <v-layout
                align-center
                column
            >
                <h1 class="display-2 font-weight-thin mb-3 text-uppercase lime--text lighten-2" >Pulse</h1>
                <h4 class="subheading">A digital intelligent insurance built for you!</h4>
            </v-layout>

            </v-layout>
        </v-parallax>
    </v-container>
</template>

<script>
    import VContainer from "vuetify/lib/components/VGrid/VContainer";
    import VFlex from "vuetify/lib/components/VGrid/VFlex";
    import VLayout from "vuetify/lib/components/VGrid/VLayout";
    import VBtn from "vuetify/lib/components/VBtn/VBtn";
    import VToolbar from "vuetify/lib/components/VToolbar/VToolbar";
    import VParallax from "vuetify/lib/components/VParallax/VParallax";

    export default {
        name: "Initial",
        components: {
            VContainer,
            VLayout,
            VFlex,
            VBtn,
            VToolbar,
            VParallax
        },
        data() {
            return {
            isAuthenticated: false
            };
        },
        async created() {
            try {
                await this.$auth.renewTokens();
            } catch (e) {
            // console.log(e);
            }
        },
        methods: {
            login() {
                this.$auth.login();
        },
            // logout() {
            //     this.$auth.logOut();
            // },
            handleLoginEvent(data) {
                this.isAuthenticated = data.loggedIn;
                this.profile = data.profile;
            }
        }


    }
</script>

<style scoped>

</style>
Run Code Online (Sandbox Code Playgroud)

我的Callback.vue

<template>
  <div>
    <p>Loading...</p>
  </div>
</template>

<script>
    export default {
      methods: {
        handleLoginEvent(data) {
            console.log('State.target is:');
            console.log(data.state.target);
          //If user has just signed up redirect to complete-signup form
          if ((data.profile['<AUTH_DOMAIN>'].justSignedUp) && (data.state.target===undefined)){
              // this.$router.push(data.state.target || "/complete-signup");
              this.$router.push('/complete-signup');
              }else {
                  // this.$router.push('/home');
                  this.$router.push(data.state.target);
              }
        }
      },
      created() {
        this.$auth.handleAuthentication();
      }
    }

</script>

<style scoped>

</style>
Run Code Online (Sandbox Code Playgroud)

我的router.js

import Vue from 'vue';
import Router from 'vue-router';
import auth from '../auth/AuthService';

import Callback from '../components/Callback';

Vue.use(Router)

// export default new Router({
const router = new Router({
    mode: 'history',
    base: process.env.BASE_URL,
    routes: [
        // {
        //     path: '/',
        //     name: 'login',
        //     component: () => import('@/views/Login')
        // },
        {
            path: '/',
            name: 'initial',
            component: () => import('@/views/Initial'),
            // meta: {isAuth: true},
            beforeEnter: ((to, from, next) => {
                // if (to.matched.some(record => record.meta.isAuth)) {
                     console.log(auth.isAuthenticated()); //THIS is false for the above scenario
                    if (auth.isAuthenticated()) {
                        next({
                            path: '/home',
                            query: {redirect: to.fullPath}
                        })
                    } else {
                        next()
                    }
                // }
            })

        },
        {
            path: '/callback',
            name: 'callback',
            component: Callback
        },
        {
            path: '/home',
            name: 'home',
            component: () => import('@/views/Home')
        },
        {
            path: '/doctors',
            name: 'doctors',
            component: () => import('@/views/Doctors')
        },
        {
            path: '/complete-signup',
            name: 'complete-signup',
            component: () => import('@/views/CompleteSignup')
        },

    ]
});

// Add a `beforeEach` handler to each route
router.beforeEach((to, from, next) => {
  if (to.path === "/" || to.path === "/callback" || auth.isAuthenticated()) {
    return next();
  }

  // Specify the current path as the customState parameter, meaning it
  // will be returned to the application after auth
    console.log('OUT beforeach if');
  auth.login({ target: to.path });
});
Run Code Online (Sandbox Code Playgroud)

'CompleteSignup is my signup form after registering where the user's is filling out a form and then posting it viaaxios and then redirected to/home`:

//Form data before
methods: {
this.$store.dispatch(REGISTER,registerFormData)
          .then(() => this.$router.push('/home'));
}
Run Code Online (Sandbox Code Playgroud)

我也在使用vuetify,我的主要App.vue组件是:

<template>

    <v-app
        style= "background: #E0EAFC;  /* fallback for old browsers */
        background: -webkit-linear-gradient(to left, #CFDEF3, #E0EAFC);  /* Chrome 10-25, Safari 5.1-6 */
        background: linear-gradient(to left, #CFDEF3, #E0EAFC); /* W3C, IE 10+/ Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ */
        "
    >  
      <v-content>
        <router-view></router-view>
      </v-content>
    </v-app>
</template> 


<script>   
  export default {
      name: 'App',
      components: {

      }

  };


</script>

<style>
</style>
Run Code Online (Sandbox Code Playgroud)

kin*_*ian 0

我想到了。问题在于this.tokenExpiry, , this.idToken,值在视图this.profile中被分配了一个值,该值位于该值之后,此外,这些值还与我在. 因此,当导航回初始页面时,它是未定义的,因为它不与特定的 Vue 实例关联。callbackloginmixinthis