[TOC] >[success] # 登录代码案例 ~~~ 1.用户输入用户名密码 --》 后台返回一个状态 --》 保存这个状态的token --》 输入url --》 判断有没有token --》有就走后台验证token 接口--》没有就让用户登录 2.退出后要跳回登录页 3.下面的案例对安全性不高的需求使用,高安全的建议后台设置cookies ~~~ >[info] ## 在lib文件下的util.js 添加获取和增加cookie的方法 ~~~ 1.需要npm install js-cookie -- 用来操作cookie ~~~ >[danger] ##### setToken -- 添加一个cookie ~~~ 1.当我们从后台获取的token验证的钥匙,可以存到cookies中 ~~~ ~~~ export const setToken = (token, tokenName = 'token') => { Cookies.set(tokenName, token) } ~~~ >[danger] ##### getToken -- 获得cookie中的token ~~~ 1.当我们从获取保存在cookie中的token时候 ~~~ ~~~ export const getToken = (tokenName = 'token') => { return Cookies.get(tokenName) } ~~~ >[info] ## 对lib文件下的axios进行改造 ~~~ 1.和之前代码不同点,这里请求拦截的时候配置了一个请求头,这个请求头 传递token,后台人员获取这个请求头中的token 来判断token是否失效,或 者真假'config.headers['Authorization'] = getToken()' 2.好处是当我们使用其他接口的时候,每次请求自动拼接在请求头中,不用 在每个接口使用的时候都传递token 3.因为要在请求头传递token,所以这里面使用了,在lib文件夹下的util.js, 中的getToken 方法 ~~~ >[danger] ##### 改造后的代码 ~~~ import axios from 'axios' import { baseURL } from '@/config' import { getToken } from '@/lib/util' class HttpRequest { constructor (baseUrl = baseURL) { this.baseUrl = baseUrl this.queue = {} } getInsideConfig () { const config = { baseURL: this.baseUrl, headers: { // } } return config } distroy (url) { delete this.queue[url] if (!Object.keys(this.queue).length) { // Spin.hide() } } interceptors (instance, url) { instance.interceptors.request.use(config => { // 添加全局的loading... if (!Object.keys(this.queue).length) { // Spin.show() } this.queue[url] = true config.headers['Authorization'] = getToken() return config }, error => { return Promise.reject(error) }) instance.interceptors.response.use(res => { this.distroy(url) const { data } = res return data }, error => { this.distroy(url) return Promise.reject(error) }) } request (options) { const instance = axios.create() options = Object.assign(this.getInsideConfig(), options) this.interceptors(instance, options.url) return instance(options) } } export default HttpRequest ~~~ >[info] ## 编写api 文件夹下的user.js中文件的登陆接口 ~~~ 1.我们将有关用户的接口,都维护到user.js 文件件中 ~~~ >[danger] ##### 登陆接口 ~~~ export const login = ({ userName, password }) => { return axios.request({ url: '/index/login', method: 'post', data: { userName, password } }) } ~~~ >[info] ## 编写api 文件夹下的user.js中文件的token验证接口 ~~~ 1.每次访问视图组建时候,需要我们去调用这个接口,也是后台提供一个验 证,登陆是否失效和正确的预留接口 ~~~ >[danger] ##### 验证token接口 ~~~ export const authorization = () => { return axios.request({ url: '/users/authorization', method: 'get' }) } ~~~ >[info] ## 在store 文件下moudule文件夹下的user.js文件 ~~~ 1.在vuex 中调用登陆接口,为了让项目更茁壮在store 文件夹下创建了, 一个负责个个模块的module 文件夹,再里面创建了一个user.js 文件专门 保存用户模块的vuex 2.因为登陆是异步请求,因此使用vuex中的actions方法去调用接口 3.下面'login' 方法返回的是一个'Promise'对象,因为请求调用的接口是异步 的,所以我们将这个异步封装到'Promise'在使用的时候可以更加方便 4.commit 是文档中说的载荷也是用来控制mutations一个方法 5.catch抓的不是200 status 会走catch里面 6.登陆成功需要使用我们封装的setToken ,将token存进cookie中 7.'authorization ' token是正确的就给他重新赋值一个cookie ~~~ >[danger] ##### user.js 内容一个是调用登陆接口,一个是验证token接口,一个注销方法 ~~~ import { login, authorization } from '@/api/user' import { setToken } from '@/lib/util' const state = { userName: 'Lison' } const getters = { firstLetter: (state) => { return state.userName.substr(0, 1) } } const mutations = { SET_USER_NAME (state, params) { state.userName = params } } const actions = { updateUserName ({ commit, state, rootState, dispatch }) { // rootState.appName }, login ({ commit }, { userName, password }) { return new Promise((resolve, reject) => { login({ userName, password }).then(res => { if (res.code === 200 && res.data.token) { setToken(res.data.token) resolve() } else { reject(new Error('错误')) } }).catch(error => { reject(error) }) }) }, authorization ({ commit }, token) { return new Promise((resolve, reject) => { authorization().then(res => { if (parseInt(res.code) === 401) { reject(new Error('token error')) } else { setToken(res.data.token) resolve() } }).catch(error => { reject(error) }) }) }, logout () { setToken('') } } export default { getters, state, mutations, actions, modules: { // } } ~~~ >[info] ## 视图组件login.vue中使用 ~~~ 1....mapActions是快速使用vuex 中actions 里面的方法 2.用户登录成功用'this.$router.push'就跳转到首页 ~~~ >[danger] ##### 代码 ~~~ <template> <div> <input v-model="userName" /> <input type="password" v-model="password"/> <button @click="handleSubmit">登录</button> </div> </template> <script> import { mapActions } from 'vuex' export default { name: 'login_page', data () { return { userName: '', password: '' } }, methods: { ...mapActions([ 'login' ]), handleSubmit () { this.login({ userName: this.userName, password: this.password }).then(() => { console.log('success!!') this.$router.push({ name: 'home' }) }).catch(error => { console.log(error) }) } } } </script> ~~~ >[info] ## 在router文件下的index.js 做路由拦截 ~~~ 1.先调用封装的'getToken' 方法判断token是否存在cookie中 2.如果存在调用在'vuex' actions 方法存在的'authorization' 方法,这个方法 需要接受一个参数'token',vuex 中的这个方法实际调用的是一个后台,接口 方法,这个方法用来判断当前token是否正确 3.如果不正确一定要清除当前的cookie中保存的token ~~~ >[danger] ##### 代码 ~~~ import Vue from 'vue' import Router from 'vue-router' import routes from './router' import store from '@/store' import { setTitle, setToken, getToken } from '@/lib/util' Vue.use(Router) const router = new Router({ routes }) const HAS_LOGINED = false router.beforeEach((to, from, next) => { to.meta && setTitle(to.meta.title) // if (to.name !== 'login') { // if (HAS_LOGINED) next() // else next({ name: 'login' }) // } else { // if (HAS_LOGINED) next({ name: 'home' }) // else next() // } const token = getToken() if (token) { store.dispatch('authorization', token).then(() => { if (to.name === 'login') next({ name: 'home' }) else next() }).catch(() => { setToken('') next({ name: 'login' }) }) } else { if (to.name === 'login') next() else next({ name: 'login' }) } }) export default router ~~~