vue实现token登录

小白记录成长史,如有错误还请谅解并联系本人,本人会及时更正。

1.安装所需插件

1.1 安装qs

安装qs:
npm install qs
在main.js中全局引用
import qs from 'qs'
Vue.prototype.$qs = qs;
使用时
this.$qs.stringify(obj);
this.$qs.parse(url);

在单页面使用:
import qs from 'qs';
qs.stringify(obj)

qs 是一个增加了一些安全性的查询字符串解析和序列化字符串的库。
qs.parse();作用是将URL解析成对象的形式 。qs.stringify();作用是将对象序列化成URL的形式,以&进行拼接。

1.2安装MD5加密

npm安装:npm install --save js-md5

在main.js中全局引用
import md5 from 'js-md5';
Vue.prototype.$md5 = md5;
使用
this.$md5('123456')  
 
单页面使用:port md5 from 'js-md5';
md5('123456')  

1.3安装axios

安装:
npm install axios --save
在main.js中全局引用
import axios from 'axios'
Vue.prototype.$axios = axios;

1.4安装vuex

安装:npm install vuex --save
在main.js中引用
import store from './store';
new Vue({
   el: '#app',
   router,
   store,
   components: { App },
   template: '<App/>'
})

1.5安装进度条

 npm install --save nprogress
 //导入
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
 //用法
NProgress.start();
NProgress.done();

2.登陆页面

<template>
  <div>
    <div style="margin:0 auto;width:30%;">
      <el-input placeholder="请输入账号" v-model="userInfo.username" clearable></el-input>
      <el-input placeholder="请输入密码" v-model="userInfo.password" clearable style="margin:20px 0;"></el-input>
      <el-button size="medium" type="primary" @click="login">登录</el-button>
    </div>
  </div>
</template>

<script>
export default {
  name: "",
  props: [""],
  data() {
    return {
      userInfo: {
        username: "admin",
        password: "123456"
      }
    };
  },
  /* 组件 */
  components: {},
  /* HTML DOM加载后马上执行的,如赋值*/
  computed: {},
  /* 模板渲染成html前调用,即通常初始化某些属性值,然后再渲染成视图 */
  created() {},
  /* 模板渲染成html后调用,通常是初始化页面完成后,再对html的dom节点进行一些需要的操作 */
  mounted() {},
  /* methods则必须要有一定的触发条件才能执行 */
  methods: {
    //登录
    login() {
      let that = this;
      this.$store
        .dispatch("user/login", this.userInfo)
        .then(res => {
          console.log("按钮", res);
          // 登录成功跳转首页
          that.$router.push({
            path: "/home"
          });
        })
        .catch(res => {});
    }
  },
  /* 观察Vue实例上的数据变动 */
  watch: {}
};
</script>
<style lang='' scoped>
</style>

3.请求封装

import axios from 'axios'
import { MessageBox, Message } from 'element-ui'
import store from '@/store'
import qs from 'qs'

// create an axios instance
const service = axios.create({
  baseURL: "/api", // 后台接口地址
  timeout: 5000 // request timeout
})

// request interceptor
service.interceptors.request.use(


  config => {
    let isLogin = store.getters.token;
    let isGet = config.method;
    config.params = config.data;
    console.log(isGet, "vuex+store", isLogin, config.params);
    // get请求方式用qs.stringify(),将对象序列化成URL的形式,以&进行拼接。
    if (isGet == "get") qs.stringify(config.params);
    //  请求头部Content-Type设置,不然后台接不到参数
    //  如果有token请求头带token
    config.headers = {
      'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
      'token': isLogin ? store.getters.token : ""
    };
  },
  error => {
    console.log(error) 
    return Promise.reject(error)
  }
)

// response interceptor
service.interceptors.response.use(
  response => {
    const res = response.data;
    console.log("请求响应", res);
    if (res.code === "000000") {
      return res.datum || [];
    } else {
      // 提示弹框展示错误信息
      Message({
        message: res.reason,
        type: 'error',
        duration: 5 * 100
      })
      return Promise.reject(res)
    }
  },
  error => {
    console.log('err' + error) // for debug
    Message({
      message: error,
      type: 'error',
      duration: 5 * 100
    })
    return Promise.reject(error)
  }
)

export default service



**跨域**
proxyTable: {
    '/api': {//这里的api相当于后台地址
      target: 'http://后台地址',
      changeOrigin: true,
      pathRewrite: {
      '^/api': ''
        }
      }
    },

4.userApi

import request from '@/utils/request'

let userApi = {};
userApi.login = function (data) {
    return request({
        url: '/login',
        method: 'post',
        data
    })
}
userApi.logout = function (data) {
    console.log("data", data);
    return request({
        url: "logout",
        method: 'get',
        data
    })
}
export default userApi

5.vuex

5.1新建件夹
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200605141514810.png
5.2store–index.js
公开方法,方便使用

import Vue from 'vue'
import Vuex from 'vuex'
import getters from "./getters"
import user from "./modules/user"
import role from "./modules/role"
Vue.use(Vuex);
const store = new Vuex.Store({
  modules: {
    user,
    role,
  },
  getters
})
export default store

5.3store–getters.js

getters取得state里面的数据,并公开
const getters={
    token: state => state.user.token,
    userInfo: state => state.user.userInfo,
}
export default getters

5.4store–modules–user.js

import vue from 'vue';
import md5 from 'js-md5';
import userApi from "@/api/userApi"
// 取缓存中数据

let loginData = localStorage.getItem('loginData');
let userInfo = loginData&&JSON.parse(loginData) || {};
console.log("取缓存中数据", userInfo);

const state = {
    token: "",
    userInfo: userInfo,

}
const mutations = {
    SET_TOKEN: (state, token) => {
        state.token = token
    },
    SET_USERINFO: (state, userInfo) => {
        state.userInfo = userInfo
    },
}
const actions = {
    // 登录
    login({ commit }, userInfo) {
        //赋值解构
        const { username, password } = userInfo;
        return new Promise((resolve, reject) => {
            userApi.login({ username: username.trim(), password: md5(password), loginType: 1 }).then(res => {
                console.log("登录成功", res);
                commit('SET_TOKEN', res.token);
                commit('SET_USERINFO', res);
                // 把数据存到缓存中
                localStorage.setItem("loginData", JSON.stringify(res));
                resolve(res);
            }).catch(res => { reject(res) })
        })
    },
    // 退出登录
    logout({ commit }) {
        //赋值解构
        return new Promise((resolve, reject) => {
            userApi.logout({ uid: state.userInfo.uid }).then(res => {
                console.log("退出登录", res);
                //清除token
                commit('SET_TOKEN', "");
                //清除state里的用户信息
                commit('SET_USERINFO', {});
                // 清除缓存数据
                localStorage.removeItem("loginData");
                resolve();
            }).catch(res => { reject(res) })
        })
    },
    // 清除用户信息
    resetToken({ commit }) {
        return new Promise(resolve => {
            //清除token
            commit('SET_TOKEN', "");
            //清除state里的用户信息
            commit('SET_USERINFO', {});
            // 清除缓存数据
            localStorage.removeItem("loginData");
            resolve()
        })
    },
}
export default {
    namespaced: true,
    state,
    mutations,
    actions
}

6.vue登录拦截

6.1 permission.js

import router from './router'
import user from './store/modules/user'
import NProgress from 'nprogress' // progress bar
import 'nprogress/nprogress.css' // progress bar style
import { Message } from 'element-ui'
import store from './store'
NProgress.configure({ showSpinner: false })

// 第一种简单拦截
    console.log(from, to.path, "======", user.state.token, this);
    if (user.state.token) { // vuex.state判断token是否存在
        console.log("已登录", to.fullPath);
        next() // 已登录
    } else {
        console.log(to.path, "未登录", to.fullPath);
        // 未登录跳转登录页
        if (from.path == "/login") {
            next()
        } else {
            next({
                path: '/login',
                query: { redirect: from.fullPath }
            })
        }
    }
})


// 第二种拦截
const whiteList = ['/login'] // 没有重定向白名单
router.beforeEach(async (to, from, next) => {
    console.log('to   path: ', to.path, to, 'from path: ', from.path, from);

    // 开始进度条
    NProgress.start()

    // 确定用户是否已登录
    if (user.state.token) {
        if (to.path === '/login') {
            // 如果已登录,请重定向到主页
            next({ path: '/home' })
            NProgress.done()
        } else {

            try {
                next()
            } catch (error) {
                // 删除令牌并进入登录页面重新登录
                await store.dispatch('user/resetToken')
                Message.error(error || 'Has Error')
                next(`/login?redirect=${to.path}`)
                NProgress.done()
            }
        }
    } else {
        /* 没有token*/

        if (whiteList.indexOf(to.path) !== -1) {
            // 在登录白名单中,直接进入
            next()
        } else {
            // 其他无权访问的页面将重定向到登录页面。
            next(`/login?redirect=${to.path}`)
            NProgress.done()
        }
    }
})
router.afterEach(() => {
    // 结束进度条
    NProgress.done()
})

6.2 路由

import Vue from 'vue'
import Router from 'vue-router'

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/login',
      name: 'login',
      component: () => import('@/views/login/index')
    },
    {
      path: '/home',
      name: 'home',
      component: () => import('@/views/loginout-demo/index')
    },
  ]
})

7.退出登录

<template>
  <div style="margin:0 auto;width:50%;">
    <el-button size="medium" type="primary" @click="logout">退出登录</el-button>
  </div>
</template>

<script>
export default {
  name: "",
  props: [""],
  data() {
    return {
      userInfo: {
        username: "",
        password: ""
      }
    };
  },
  /* 组件 */
  components: {},
  /* HTML DOM加载后马上执行的,如赋值*/
  computed: {},
  /* 模板渲染成html前调用,即通常初始化某些属性值,然后再渲染成视图 */
  created() {},
  /* 模板渲染成html后调用,通常是初始化页面完成后,再对html的dom节点进行一些需要的操作 */
  mounted() {},
  /* methods则必须要有一定的触发条件才能执行 */
  methods: {
    /**
     * 退出登录
     */
    logout() {
      this.$store
        .dispatch("user/logout")
        .then(res => {
          let getUserInfo = localStorage.getItem("loginData");
          //调到首页
          this.$router.push(`/login?redirect=${this.$route.fullPath}`);
          console.log("按钮", getUserInfo);
        })
        .catch(res => {});
    }
  },
  /* 观察Vue实例上的数据变动 */
  watch: {}
};
</script>
<style lang='' scoped>
</style>

参考文献:
1.https://blog.csdn.net/wn1245343496/article/details/82151273
2.https://blog.csdn.net/xqainyo/article/details/105245826?utm_medium=distribute.pc_relevant.none-task-blog-baidujs-2
3.https://www.cnblogs.com/hspl/p/11189088.html
4.https://segmentfault.com/q/1010000010645817

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值