Vuejs2 如果用户';它已经被认证了?

Vuejs2 如果用户';它已经被认证了?,vuejs2,vue-component,vue-router,vuetify.js,auth0,Vuejs2,Vue Component,Vue Router,Vuetify.js,Auth0,说明 我用vue.js构建了一个非常标准的SPA,在这里我使用Auth0通过下面的示例来处理身份验证部分。应用程序流程如下所示: 通过Auth0锁在Initial.vue中注册->回调被调用->用户重定向到/home 上述流程中的所有内容都可以正常工作,但问题在于: 问题 一旦用户注册并在/home中,我希望他能够访问所有其他路径(例如/doctors),如果未通过身份验证,则应提示他再次登录。根据上述链接,这在路由器中处理。在每个功能之前 访问/登录页面(Initialvue)时出现我的问题。

说明

我用
vue.js
构建了一个非常标准的
SPA
,在这里我使用
Auth0
通过下面的示例来处理身份验证部分。应用程序流程如下所示:

通过Auth0锁在Initial.vue中注册
->
回调被调用
->
用户重定向到/home

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

问题

一旦用户注册并在
/home
中,我希望他能够访问所有其他路径(例如
/doctors
),如果未通过身份验证,则应提示他再次登录。根据上述链接,这在
路由器中处理。在每个
功能之前

访问
/
登录页面(
Initialvue
)时出现我的问题。当用户已经注册并试图访问该路由时,我希望他被重定向到
/home
并跳过
登录
页面。我曾尝试使用
beforenter
路由实现此功能,但
auth.isAuthenticated
失败,原因是
tokenexpiration
为空(即使用户已通过身份验证

代码

我的
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();
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 });
});
我的
回调.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>
<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>
“CompleteSignup
是我的注册表单,注册后用户填写表单,然后通过
axios
发布,然后重定向到
/home`:

//Form data before
methods: {
this.$store.dispatch(REGISTER,registerFormData)
          .then(() => this.$router.push('/home'));
}
我还使用了
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>

导出默认值{
名称:“应用程序”,
组成部分:{
}
};

您可以简化问题,将默认行为设置为用户登录的行为,然后使用route guard保护相应的路由

1) 将您的
/
指向
/home

2) 为登录创建单独的路由/“初始”
3) 使用
beforeach
钩子确保用户经过身份验证,如果没有,则将其重定向到您的
Initial.vue
(或直接触发
auth.login()


我想出来了。问题在于
this.tokenexpiration
this.idToken
this.profile
值将在
回调
视图中分配一个值,该视图位于
登录
之后,此外,这些值与我在
mixin
中定义的特定Vue原型实例相关联。因此,当导航回初始页面时,
未定义,因为它与特定的Vue实例没有关联。

我也遇到过同样的情况(使用React),我将尝试解释如何解决它

  • 首先,在身份验证中,需要在客户端存储令牌(可以使用localStorage/cookie)

  • 您需要一个
    SecureComponent
    ,此组件将仅检查存储的令牌是否存在

  • FetchHandler
    此组件处理每个受保护的应用程序
    
    并将检查响应代码,如果是401(例如),则将用户重定向到身份验证组件。此步骤可以作为附加层添加到
    SecureComponent

  • 您是否检查了
    localLogin
    中的
    authResult
    ,并首先验证了
    tokenExpiry
    设置是否正确?是。注册后,我可以在应用程序中导航,也可以在控制台中看到tokenExpiry有一个值;这将是一个解决办法。我会试试看。顺便说一下,进一步的调试表明,在这种情况下,所有
    this
    值(例如
    idToken
    profile
    tokenexpiration
    )都为空。这让我相信,当我试图访问
    这个
    实例时,组件没有被渲染。
    ...
      {
        path: '/',
        redirect: 'home'
      },
      {
        path: '/initial',
        ...
      ...
    }
    ...
    router.beforeEach((to, from, next) => {
      if(to.name == 'callback' || auth.isAuthenticated()) { 
        next()
      } else { // trigger auth0 login or redirect to your Initial.vue
        auth.login()
        // next({ path: '/initial' })
      }
    })