前言

废话不多说,先看我们没有该模块该如何登陆:

<template>
  <div>
    <h1>login page</h1>
    <button @click="login">
      登录
    </button>
  </div>
</template>

<script>
export default {
  methods: {
    login () {
      const userInfo = {
        user: 'userName',
        password: 'password'
      }
      this.$store.dispatch('login', userInfo)
    }
  }
}
</script>

非常经典的登陆模式,用 vuex 的 actions 登陆后直接 commit 存到 vuex 中,再使用 js-cookie 存到 cookie中。

(上面说的这种是一体登陆,如果是单点登陆,cookie 的操作应该在登陆端点,那么 nuxt 这边只需要在 nuxtServerInit() 直接取 cookie 然后存到 vuex 即可)

@nuxtjs/auth

该模块的作用实质上是很大的,简单的说,就是做了:

路由卫士 + cookie / vuex 持久化操作 + 登入登出重定向 + 自带 auth 请求头

四个功能,非常的实用。

下面开始详细介绍~

安装
yarn add @nuxtjs/auth

注:使用 @nuxtjs/auth 时,他的请求是基于 @nuxtjs/axios 的,没有的话要装一下并配置一下 axios ,相信大家初始化项目的时候都有了。

配置

nuxt.config.js ,先把模块功能配置上:

modules: [
    '@nuxtjs/axios',
    '@nuxtjs/auth'
  ],

全局路由卫士配置上:

router: {
    middleware: ['auth']
  },

注:相信有经验的朋友已经知道了,nuxt 的路由卫士只在切换路由的时候生效,第一次刷新进入页面不生效,后面会探讨这个问题。

加入 @nuxtjs/auth 的核心配置:

auth: {
    strategies: {
      local: {
        endpoints: {
          login: {
            url: '/api/login',
            method: 'post',
            propertyName: 'data.token'
          },
          logout: { url: '/api/logout', method: 'get' },
          user: {
            url: '/api/home',
            method: 'post',
            propertyName: 'data'
          }
        }
      }
    },
    redirect: {
      login: '/login',
      logout: '/',
      callback: '/login',
      home: '/'
    },
    cookie: {
      options: {
        maxAge: 60 * 60 * 24 * 7
      }
    },
    localStorage: false
  },

你可以在官方说明文档找到更详细的内容:官方文档

上面的配置具体什么意思请看一个实例,直接说的话会很难理解。

实例

我们做一个简单的登入登出 demo 来体验 @nuxtjs/auth 的便捷。

抛弃 localStorage

首先,老 nuxt 玩家应该知道 localStorage 的弊端,而每次请求自带 cookie ,应该使用 cookie 存储验证信息,默认情况下,@nuxtjs/auth 会把验证信息在 localStorage 和 cookie 都存一份,没必要,而且没法控制有效期,所以我们先把 localStorage 存储验证信息关闭:

cookie: {
      options: {
        maxAge: 60 * 60 * 24 * 7
      }
    },
localStorage: false

并且给 cookie 配了 7 天有效期,这就是上文这段配置的原因。

配置 mockjs

为了在本地模拟接口,我选用 mockjs 来拦截 axios 请求,这部分可参看下文:

《nuxt.js开发环境使用mockjs模拟数据》

当然,有 easy mock 那就再简单不过了(记得配置 axios 的 baseURL )。

我们先做了三个接口:

const Mock = require('mockjs')

// 登陆接口,返回一个 token
Mock.mock(RegExp('/api/login'), 'post', (data) => {
  return {
    code: 20000,
    message: 'success',
    data: {
      token: 'awesomeToken'
    }
  }
}
)

// 获取用户信息接口,返回用户的信息
Mock.mock(RegExp('/api/home'), 'post', (data) => {
  console.log(data)
  return {
    code: 20000,
    message: 'success',
    data: {
      userName: 'userName',
      otherInfo: 'otherInfo'
    }
  }
}
)

// 退出接口,一请求即代表退出(后端在 redis 清除 token ,便于克服 JWT 的缺点)
Mock.mock(RegExp('/api/logout'), 'get', () => {
  return {
    code: 20000,
    message: 'success'
  }
}
)
端点与策略

配置好 mockjs 接口,我们介绍一下端点和策略,在上文配置中,@nuxtjs/auth 默认给我们提供了一个权限策略名为 local ,当然还有其他平台的策略(比如 Github、Facebook 等),我们的策略就是基于默认策略 local 进行修改:

strategies: {
      local: {
      	// 修改默认策略
      }
   }

该策略默认有三个端点,也就是三个 api ,login 是登陆端点,logout 是退出端点,user 是用户信息端点,propertyName 参数就是返回的 response.data 内我们要获取的内容,propertyName: 'data.token' 就是获取了我们的 response.data.data.token

个人主页 home.vue

下面写一个个人主页 pages/home.vue

<template>
  <div>home page</div>
</template>

<script>
export default {
}
</script>
登陆页 login.vue

写一个模拟登陆页 pages/logon.vue

<template>
  <div>
    <h1>login page</h1>
    <button @click="login">
      登录
    </button>
  </div>
</template>

<script>
export default {
  created () {
    if (this.$auth.loggedIn) { this.$router.push('/home') }
  },
  methods: {
    login () {
      const userInfo = {
        user: 'userName',
        password: 'password'
      }
      this.$auth.loginWith('local', { data: userInfo })
    }
  }
}
</script>

其中 this.$auth.loginWith() 就是登陆方法,第一个参数填登陆策略名,第二个参数是 post 传递的 data 数据。

this.$auth.loggedIn 是官方 api 提供给我们的是否登陆判断标识,若已登陆我们让他跳转到个人页面 /home 即可,@nuxtjs/auth 是不会在该页面判断你是否已经登陆了的,需要自己做跳转。

那么我们点击登陆按钮会发生什么呢?

我们需要一个拦截器打印请求,建立 plugins/axios.js

export default function ({ $axios, redirect }) {
  $axios.onRequest((config) => {
    console.log('Making request to ' + config.url)
    console.log('config: ', config)
    return config
  })
}

并在 nuxt.config.js 将其配置:

plugins: [
    '@/plugins/axios'
  ]

我们点击按钮会发现:


nuxt 还用 axios吗 nuxt/auth_vue

  1. 前两行是请求了登陆接口
  2. 三四行是登陆完成后请求了个人信息接口
  3. 第五行是我们在个人信息接口打印的消息(上文中 mockjs 接口中我们写了一个 console.log )

请求过程我们清楚了,存到哪里了呢?


nuxt 还用 axios吗 nuxt/auth_vue_02

↑ 看一下 vuex 发现,登陆成功后 loggedIn 会变为 true ,也就是我们上文使用的判断标识 this.$auth.loggedIn 拿到的。而个人信息存到了 user 中(可通过 this.$auth.user 取)


nuxt 还用 axios吗 nuxt/auth_nuxt 还用 axios吗_03

↑ 看一下 cookie 发现,token 自动加了 Bearer 存起来了。


nuxt 还用 axios吗 nuxt/auth_nuxt 还用 axios吗_04

↑ 再细看一下请求个人信息接口 /api/home 的,发现带上了 token ,太好了!

到了这里,基本上 @nuxtjs/auth 已经摸清楚了,这里提两个很好的地方,第一,cookie 是自动在该域名以及子域下添加的,不用我们手动获取了;第二,请求 token 是默认全局带上的,不用我们配置拦截器了。

主页面 index.vue

我们在写一个主页面 pages/index.vue

<template>
  <div>
      <button v-if="this.$auth.loggedIn" @click="() => {this.$auth.logout()}">退出</button>
      <button v-else @click="() => {this.$router.push('/login')}">登录</button>
  </div>
</template>

<script>
export default {
  auth: false
}
</script>

这个页面就很通俗易懂了,不想让哪个页面需要权限,加上 auth: false 即可。

完备的验证

路由 push 我们可以在页面上控制,但是第一次刷新进入哪个页面我们没法控制,还需要分别验证第一次刷新进入 /home/login

经测试发现,登录页 /login 只要进入,由于我们加了 created() 钩子判断是否登陆,登陆状态进入就会跳转到 /home ,从而我们也知道了 @nuxtjs/auth 刷新页面后会自动从 cookie 里取值并加载到 vuex 状态树,很方便!

个人主页 /home 第一次进入,会跳转到 /login ,若已登陆,会自动再跳回,第一次进入需要权限的 /home 会跳转,这是 @nuxtjs/auth 的机制,因为他要加载 vuex 状态树,并没有什么不友好(微软 oauth2 也是第一次要跳一下),之后我们是路由的 push ,不存在这种现象了。

如果你仔细观察 cookie ,在从 /home 跳到 /login 时会有用来重定向的原网址 cookie 值被插入,跳回后消失,也就是任何需要权限的页面第一次进入都会跳一次之后跳回。

跳转配置说明

相信看完本实例你应该能明白配置中的 redirect 是什么意思:

redirect: {
  	  // 登陆页面,进入需要权限的页面,没有本地 token 就会往这里跳
      login: '/login',
      // 退出后往这里跳
      logout: '/',
      // 第三方平台 OAuth2 使用的重定向回来的地址,这里用不到
      callback: '/login',
      // 个人主页,如果配置 auth: 'guest' 时,已登录用户访问该页面会跳到该地址(也就是限于访客)
      home: '/'
    },

细数 @nuxtjs/auth

@nuxtjs/auth 到底有什么好处:

  1. 请求全局自带 token 头,省去写拦截器
  2. 自动登录、获取用户信息,省去大片代码
  3. 自动鉴权、跳转,省去路由卫士
  4. 令牌持久化,刷新页面不丢失,省去大片代码
  5. 友好的 api ,人性化存取(官方还提供了操作的 api ,详见官方文档)

真的是太好了。