前言
废话不多说,先看我们没有该模块该如何登陆:
<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'
]
我们点击按钮会发现:
- 前两行是请求了登陆接口
- 三四行是登陆完成后请求了个人信息接口
- 第五行是我们在个人信息接口打印的消息(上文中 mockjs 接口中我们写了一个 console.log )
请求过程我们清楚了,存到哪里了呢?
↑ 看一下 vuex 发现,登陆成功后 loggedIn
会变为 true
,也就是我们上文使用的判断标识 this.$auth.loggedIn
拿到的。而个人信息存到了 user
中(可通过 this.$auth.user
取)
↑ 看一下 cookie 发现,token 自动加了 Bearer
存起来了。
↑ 再细看一下请求个人信息接口 /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
到底有什么好处:
- 请求全局自带 token 头,省去写拦截器
- 自动登录、获取用户信息,省去大片代码
- 自动鉴权、跳转,省去路由卫士
- 令牌持久化,刷新页面不丢失,省去大片代码
- 友好的 api ,人性化存取(官方还提供了操作的 api ,详见官方文档)
真的是太好了。