01用户登录,登出,token等框架说明

时间:2022-09-26 12:02:32

01.cookie 设置

src/utils/auth.js

  • 首先要安装 cookies 插件
npm i cookies
  • 代码 11 和 26 行,设置了失效 7 天;
  • 代码 4 和 19 行,key 是可以自定义的;
import Cookies from 'js-cookie'

// token key
const TokenKey = 'mine_token';
// 获取 token
export function getToken() {
  return Cookies.get(TokenKey)
}
// 设置 token,expires 7 天有效
export function setToken(token) {
  return Cookies.set(TokenKey, token, {expires: 7})
}
// 删除 token
export function removeToken() {
  return Cookies.remove(TokenKey)
}

// 用户 key
const UserKey = 'mine_user';
// 获取 
export function getUser() {
  return Cookies.get(UserKey)
}
// 设置 
export function setUser(user) {
  return Cookies.set(UserKey, user, {expires: 7})
}
// 删除 
export function removeUser() {
  return Cookies.remove(UserKey)
}

02.axios 拦截设置

前提要先设置全局 API,在文件 .env.development.env.production

# base api
VUE_APP_BASE_API = 'http://192.168.182.13:8088'

src/utils/request.js

  • 代码 9 行,header 中的 token 不一定要 replace 替换。根据返回的token 字符串而定;
  • 代码 9 和 17 行是否重新设置,有冲突。江西矿山只设置了 20,也没影响;
  • 代码 9 和 16 行,getToken 方法获取 token 有可能为空 或 7 天到期失效。详见 src/utils/auth.js
import axios from 'axios'
import { Message } from 'element-ui'
import router from '@/router'
import { getToken } from '@/utils/auth'

// 新建 axios
const service = axios.create({
	baseURL: process.env.VUE_APP_BASE_API,
	// headers: { 'Authorization': getToken().replace('%20', ' ') } // 设置请求头
	timeout: 5000
})

// request 请求前拦截
service.interceptors.request.use(
	config => {
		if (getToken()) {// 测试,这里是否添加
			config.headers['X-Token'] = token;
		}
		return config
	},
	error => {
		return Promise.reject(error)
	}
)

// response 响应拦截
service.interceptors.response.use(
	response => {
		const res = response.data
		if(res.code == 401){
			Message({
				message: '身份验证过期,请登录',
				type: 'warning',
				duration: 5 * 1000
			})
			router.push('/')
		}
		return res
	},
	error => {
		if (401 === error.response.status) {
			Message({
			message: '身份验证过期,请登录',
			type: 'warning',
			duration: 5 * 1000
			});
			// 这里有可能是 '/' 或 '/login'
			router.push('/');
		} else {
			console.log('err' + error) // for debug
			Message({
				message: error.message,
				type: 'error',
				duration: 5 * 1000
			})
		}
		return Promise.reject(error)
	}
)

export default service

03.用户 API

src/api/user.js

  • 注意如下 url 或请求方式 getpost以具体的接口而定
  • 可能有 登录、获取用户信息、登出等;
import request from '@/utils/request'

// 获取用户信息
export function getInfo(id) {
	return request({
		url: `/mapgis/gm/v1/user/${id}/info`,
		method: 'get'
	})
}

// 登出
export function logout() {
	return request({
		url: '/vue-admin-template/user/logout',
		method: 'get'
	})
}

04.VueX user

src/store/modules/user.js

  • 代码 34 - 45 行,不是使用 axios 拦截,因为登录不需要;
import { getInfo } from '@/api/user'
import { getToken, setToken, removeToken, getUser, setUser, removeUser } from '@/utils/auth'

// 状态
const state =  {
    token: getToken(),
    name: getUser(),
    userId: '',// 可选项
    userRole: '',// 用户角色
    userInfo: null
}

// 同步设置
const mutations = {
    // token
    SET_TOKEN: (state, token) => {
        state.token = token;
    },
    // name
    SET_NAME: (state, name) => {
        state.name = name;
    },
    // 用户 id
    SET_USERID: (state, userId) => {
        state.userId = userId;
    },
    // 用户 角色
    SET_USERROLE: (state, userRole) => {
        state.userRole = userRole;
    },
    // 用户 信息对象
    SET_USERINFO: (state, userInfo) => {
        state.userInfo = userInfo;
    }
}

// 异步设置
const actions = {
    // 登录
    login({ commit }, userInfo) {
        const { form, axios } = userInfo;
        return new Promise((resolve, reject) => {
            let url = '/v1/auth/login';
            axios.post(url, form).then((resp) => {
                if (resp.data.succ) {
                    let obj = resp.data.obj;
                    setToken(obj.token);//设置 token cookie
                    setUser(form.user);//设置用户名 user cookie
                    commit('SET_TOKEN', obj.token);//设置token
                    commit('SET_NAME', form.user);//设置用户名
                    resolve();
                } else {
                    reject(resp)
                }
            });
        })
    },
    // 获取用户信息
    getInfo({ commit, state }) {
        return new Promise((resolve, reject) => {
            getInfo(state.token).then(response => {
                if(resp.succ) {
                    let info = resp.obj;
                    commit('SET_USERID', info.uid)
                    commit('SET_USERROLE', info.roleNames[0])
                    commit('SET_USERINFO', info)
                    resolve();
                } else {
                    reject(resp)
                }
            }).catch(error => {
                reject(error)
            })
        })
    },
    // 登出
    logout({ commit, state }) {
        // 删除 cookie
        removeToken();
        removeUser();
        // 删除信息
        commit('SET_TOKEN', '');
        commit('SET_NAME', '');
        commit('SET_USERID', '');
    }
}

export default {
    namespaced: true,
    state,
    mutations,
    actions
}

05.路由前置守卫

src/router/index.js

  • 引入 cookie
import { getToken } from '@/utils/auth'
router.beforeEach((to, from, next) => {
    //判断是否已登录
    if (!getToken() && to.name !== 'login') {
		//跳转到登录页
		next({ path: '/login' })
    } else {
      	next()
    }
})

06.登录/登出

登录

  • 先安装插件 js-base64

    npm i js-base64
    
  • 或 有的可以使用插件 js-md5

    npm i js-md5
    
  • 在登录页引入;

    import { encode } from 'js-base64';
    // 或
    import md5 from 'js-md5'
    
  • src/store/user.js异步方法 user/login

    • 代码 中的 inputNameinputPwform等参数根据当前页的设置而定;
    • 代码 11 行,路由有可能是 /login
    • 如果登录比较严,如有验证码、30分钟未操作要登出。可参考中山项目;
commit () {
	if (this.inputName.trim() == '' || this.inputPw.trim() == '') {
		this.$message({ type: 'error', message: '请输入用户名密码或验证码!' })
		return
	}
	let form = {
		"user": this.inputName,
		"pwd": md5(this.inputPw),
		"againPwd": md5(this.inputPw),
		"needPhoneAuth": false,
		"needEmailAuth": false
	}
	this.$store.dispatch('user/login', { form, axios: this.$axios }).then(data => {
		this.$router.push('/');
	}).catch((error) => {
		console.error('登录失败', error);
		this.$message({ type: 'error', message: '登录失败' })
	}) 
}

登出

this.$store.dispatch('user/logout');

07.TopHeader

进入主页,显示用户名可设置计算属性 userName参考第三篇《03用户及切换列表》

computed: {
    userName() {
        return this.$store.state.user.name
    }
}