axios 拦截 , 页面跳转, token 验证(自己摸索了一天搞出来的)
最近做项目,需要登录拦截,验证。于是使用了axios的拦截器(也是第一次使用,摸索了1天,终于搞出来了,真是太高兴啦!!!),废话不多说,直接上代码,
项目结构:vue-cli + webpack + vue + vue-router + vuex
项目结构截图:
其中src下store文件夹中有两个文件,store.js和type.js,其中store.js为:
/**
* Created by yuwenjing on 17/9/13.
*/
import Vuex from 'vuex'
import Vue from 'vue'
import * as types from './types' Vue.use(Vuex);
export default new Vuex.Store({
state: {
token: null,
userName: ''
},
mutations: {
[types.LOGIN]: (state, data) => {
localStorage.token = data;
state.token = data;
},
[types.LOGOUT]: (state) => {
localStorage.removeItem('token');
state.token = null
},
[types.USERNAME]: (state, data) => {
localStorage.userName = data;
state.userName = data;
}
}
})
types.js为:
/**
* Created by yuwenjing on 17/9/13.
* vuex types
*/ export const LOGIN = 'login'; export const LOGOUT = 'logout'; export const USERNAME = 'userName'
主要业务代码结构:
其中main.js为:
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import store from './store/store'
import * as types from './store/types'
import router from './router'
import axios from 'axios' Vue.config.productionTip = false
//创建axios实例
var $http = axios.create({}); // http request 拦截器
$http.interceptors.request.use(
config => {
if(config.url.indexOf('loginCheck')>=0){
return config;
}else{
if (store.state.token) {
config.headers.authorization = store.state.token;
}
return config;
} },
err => {
return Promise.reject(err);
}); // http response 拦截器
$http.interceptors.response.use(
response => {
return response;
},
error => {
if (error.response) {
switch (error.response.data.message) {
case "false":
// 清除token信息并跳转到登录页面
store.commit(types.LOGOUT);
router.replace({
path: '/'
})
}
}
// console.log(JSON.stringify(error));//console : Error: Request failed with status code 402
return Promise.reject(error.response.data)
}); Vue.prototype.$http = $http /* eslint-disable no-new */
new Vue({
el: '#app',
store,
router,
$http,
template: '<App/>',
components: { App }
})
router文件夹下index.js为:
import Vue from 'vue'
import Router from 'vue-router'
import login from '@/components/login'
import homePage from '@/components/homePage'
import store from '../store/store'
import * as types from '../store/types' Vue.use(Router) const routes = [
{
path:'/',
component:login
},
{
path: '/homePage',
meta: {
requireAuth: true,
},
component: homePage
}
]; // 页面刷新时,重新赋值token,用户名也在界面上展示
if (window.localStorage.getItem('token')) {
store.commit(types.LOGIN, window.localStorage.getItem('token'));
}
if(window.localStorage.getItem('userName')){
store.commit(types.USERNAME, window.localStorage.getItem('userName'));
} const router = new Router({
routes
}); router.beforeEach((to, from, next) => {
if (to.matched.some(r => r.meta.requireAuth)) {
if (store.state.token) {
next();
}
else {
next({
path: '/'
})
}
}
else {
next();
}
}) export default router;
登录界面login.vue代码为:
<template>
<div class="login-wrapper">
<!--顶部-->
<div class="top">
<span class="content">
<img src="../../static/img/login_logo.png" class="system-logo">
<span class="system-name">北京热力面积投停管理系统</span>
</span>
</div>
<!--顶部结束--> <!--中部-->
<div class="center">
<div class="login"> <!--中部左侧-->
<div class="left">
<img src="../../static/img/login_city.png">
</div>
<!--中部左侧结束--> <!--中部右侧-->
<div class="right"> <span class="login-title">用户登录</span> <!--用户名输入-->
<div class="username-wrapper">
<i class="username-logo"></i>
<input type="text" class="username" placeholder="用户名" v-model="username" ref="username" @focus="usernameFocus" :class="{'username-focus': isUsernameFocus}">
</div>
<!--用户名输入结束--> <!--密码输入-->
<div class="pwd-wrapper">
<i class="pwd-logo"></i>
<input type="password" class="pwd" placeholder="密码" v-model="pwd" ref="pwd" @focus="pwdFocus" :class="{'pwd-focus': isPwdFocus}">
</div>
<!--密码输入结束--> <!--提交按钮-->
<button class="login-btn" @click="clickLoginBtn">登录</button>
<!--提交按钮结束-->
</div>
<!--中部右侧结束-->
</div>
</div>
<!--中部结束--> <!--底部-->
<div class="bottom"></div>
<!--底部结束--> </div>
</template> <script type="text/ecmascript-6">
import * as types from '../store/types'
import {SWAGGER_CONFIG} from '../config/config'
export default {
data() {
return {
// 用户名密码
username: '',
pwd: '',
isUsernameFocus: true,
isPwdFocus: false
}
}, methods: {
// 点击登录按钮
clickLoginBtn() {
if (this.username && this.pwd) {
this.requestLoginInterface();
} else {
alert('用户名或密码不能为空');
}
}, // 请求登录接口数据
requestLoginInterface () {
var self = this;
self.$http.post(SWAGGER_CONFIG+'/Ddaas/userrole/loginCheck',
{
"userName":self.username,
"passWord":self.pwd
}
).then(function (response) {
if(response.data.data == false){
alert("用户名或密码不匹配!")
return;
}else{
self.$store.commit(types.USERNAME,self.username);
self.$store.commit(types.LOGIN, response.data.data);
self.$router.push({path:"/homePage"});
}
})
.catch(function (error) {
console.log(error);
});
}, usernameFocus () {
this.isUsernameFocus = true;
this.isPwdFocus = false;
}, pwdFocus() {
this.isUsernameFocus = false;
this.isPwdFocus = true;
}
}, mounted () {
// 挂在成功就聚焦输入框
this.$refs.username.focus();
}
} </script> <style scoped>
.login-wrapper {
width: 100%;
height: 100%;
min-width: 700px;
min-height: 750px;
} .login-wrapper .top {
width: 100%;
height: 22%;
display: flex;
align-items: center;
} .login-wrapper .top .content {
display: block;
width: 100%;
height: 61px;
text-align: center;
} .login-wrapper .top .content .system-logo {
vertical-align: top;
} .login-wrapper .top .content .system-name {
font-size: 30px;
line-height: 61px;
color: #077fb7
} .center {
width: 100%;
height: 56%;
background: linear-gradient(to bottom, #057fbf, #1697d4);
/*text-align: center;*/
display: flex;
justify-content: center;
align-items: center;
} .center .login {
width: 52%;
height: 68%;
background-color: white;
border-radius: 5px;
border: 15px solid white;
box-shadow: 0 0 0 7px rgba(139, 208, 255, 0.5);
} .center .login .left {
width: 60%;
height: 100%;
box-sizing: border-box;
float: left;
} .center .login .right {
float: right;
width: 40%;
height: 100%;
padding: 22px 8px 30px 22px;
} .center .login .right .login-title {
display: block;
width: 100%;
height: 24px;
font-size: 24px;
text-align: center;
line-height: 24px;
vertical-align: middle;
} .center .login .right .username-wrapper {
position: relative;
} .center .login .right .username-logo {
display: inline-block;
position: absolute;
top: 12px;
left: 10px;
width: 14px;
height: 14px;
background: url('../../static/img/login_user.png') no-repeat;
} .center .login .right .username {
display: block;
width: 100%;
height: 40px;
margin-top: 25px;
outline: none;
padding-left: 34px;
border: 1px solid #e2e7eb;
color: #404040;
} .center .login .right .username-focus {
display: block;
width: 100%;
height: 40px;
margin-top: 25px;
outline: none;
padding-left: 34px;
border: 1px solid #0782bb;
color: #404040;
} .center .login .right .username::-webkit-input-placeholder {
color: #d2d2d2;
} .center .login .right .username:-moz-placeholder {
color: #d2d2d2;
} .center .login .right .username:-ms-input-placeholder {
color: #d2d2d2;
} .center .login .right .pwd-wrapper {
position: relative;
} .center .login .right .pwd-logo {
display: inline-block;
position: absolute;
top: 12px;
left: 10px;
width: 14px;
height: 15px;
background: url('../../static/img/login_pwd.png') no-repeat;
} .center .login .right .pwd {
display: block;
width: 100%;
height: 40px;
margin-top: 25px;
outline: none;
padding-left: 34px;
border: 1px solid #e2e7eb;
color: #404040;
} .center .login .right .pwd-focus {
display: block;
width: 100%;
height: 40px;
margin-top: 25px;
outline: none;
padding-left: 34px;
border: 1px solid #0782bb;
color: #404040;
} .center .login .right .pwd::-webkit-input-placeholder {
color: #d2d2d2;
} .center .login .right .pwd:-moz-placeholder {
color: #d2d2d2;
} .center .login .right .pwd:-ms-input-placeholder {
color: #d2d2d2;
} .center .login .right .login-btn {
display: block;
width: 100%;
height: 40px;
margin-top: 30px;
background: linear-gradient(to bottom, #1799d6, #047db5);
border: none;
color: white;
font-size: 20px;
outline: none;
} .center .login .left img {
width: 100%;
height: 100%;
} .bottom {
width: 100%;
height: 22%;
}
</style>
展示用户名和注销功能都在headTop.vue中,headTop.vue为:
<template>
<div id="all">
<div class="top-left">
<p>
<img src="../../../static/img/BJRLLOGO.png">
<span>北京热力面积投停管理系统</span>
</p>
</div>
<div class="top-right"> <div>
<ul class="first-ul">
<li class="first-li">
<img src="../../../static/img/index.png" class="base-img">
<span class="nav-span">首页</span>
</li>
<li class="dropdown">
<img src="../../../static/img/user.png">
<span class="dropdown-toggle nav-span" data-toggle="dropdown">
{{userName}}
<!--<b class="caret"></b>-->
<img src="../../../static/img/userxiala.png">
</span>
<ul class="dropdown-menu">
<li>
<img src="../../../static/img/qiehuan.png">
<span>切换账号</span>
</li>
<li>
<img src="../../../static/img/xiugai.png">
<span>修改密码</span>
</li> <li>
<img src="../../../static/img/tuichu.png">
<span @click="logout">退出登录</span>
</li> </ul>
</li>
</ul>
</div> </div> </div>
</template>
<style scoped>
#all{
width:100%;
height:100%;
background: #0A86C0;
}
.top-left{
width:50%;
height:100%;
float:left;
display: table;
}
.top-left p{
display: table-cell;
vertical-align: middle;
}
.top-left img{
width:auto;
height:auto;
max-width: 100%;
max-height: 100%;
margin-left: 2%;
}
.top-left span{
display: inline-block;
color:#fff;
font-size: 1.3vw;
font-weight: bold;
font-family: "Microsoft YaHei UI";
}
.top-right{
width:50%;
height:100%;
float:left;
}
.top-right div{
width:100%;
height:100%;
position: relative;
display: table;
}
.first-ul{
list-style: none;
position: absolute;
right:2%;
top:36%;
width:27%;
}
.first-ul>li{
display: inline;
}
.dropdown-menu li{
text-align: center;
}
.nav-span{
color:#fff;
font-size: 0.8vw;
font-family: "Microsoft YaHei UI";
cursor: pointer;
}
.dropdown-menu{
min-width: 98px;
}
.dropdown-menu li{
margin-top:6%;
}
.dropdown-menu span{
font-size: 0.6vw;
font-family: "Microsoft YaHei UI";
cursor: pointer;
color:#121212;
}
.first-li{
margin-right: 20%;
}
.base-img{
vertical-align: text-top;
}
</style>
<script>
import * as types from '../../store/types'
import {mapState} from 'vuex'
export default{
data(){
return{ }
},
methods:{
logout(){
var self = this;
self.$store.commit(types.LOGOUT)
self.$router.push({
path: '/'
}) } },
computed: mapState({
userName: state => state.userName
}) }
</script>
要说一句,就是vuex中的state里的值在页面刷新的时候会消失(即vuex中的状态管理是响应式的),因此我们使用localStorage来解决这个问题
这就是为什么这么麻烦在state和localStorage中传来传去,是因为state的值刷新后会没了,而localStorage的值不能响应式地变化(Vue 仅可以对其管理的数据做响应式处理,可以理解为 data 中的数据,localStorage 并不在 Vue 的管理下,自然不会有响应特性);
完整的项目地址为:
https://github.com/yuwenjing0727/heating-power
axios 拦截 , 页面跳转, token 验证(自己摸索了一天搞出来的)的更多相关文章
- axios 拦截 , 页面跳转, token 验证
第一步: 路由 多添加一个自定义字段 requireAuth path: '/repository', name: 'repository', meta: { requireAuth: true, / ...
- axios interceptors 拦截 , 页面跳转, token 验证 Vue+axios实现登陆拦截,axios封装(报错,鉴权,跳转,拦截,提示)
Vue+axios实现登陆拦截,axios封装(报错,鉴权,跳转,拦截,提示) :https://blog.csdn.net/H1069495874/article/details/80057107 ...
- vue路由守卫+cookie实现页面跳转时验证用户是否登录----(二)设置路由守卫
上一篇我们已经封装好了cookie方法,登录成功之后也可以吧用户信息存到cookie中,接下来需要在router/index.js中引入一下cookie.js文件 然后继续添加以下代码 /* * be ...
- 由前端登录验证,页面跳转,携带headers token引发的思考和尝试
目录 1 前言 2 我的实现方式与存在的问题 3 我想到的解决方案 3.1 前端跳转时携带headers{'token': token} 不就行了(经验证不可行) 3.2 前端跳转封装请求,携带hea ...
- 通过配置http拦截器,来进行ajax请求验证用户登录的页面跳转
在.NET中验证用户是否登录或者是否过期,若需要登录时则将请求转向至登录页面. 这个流程在进行页面请求时是没问题的,能正确进行页面跳转. 然而在使用xmlhttprequest时,或者jq的getJs ...
- JavaEE权限管理系统的搭建(六)--------使用拦截器实现菜单URL的跳转权限验证和页面的三级菜单权限按钮显示
本小结讲解,点击菜单进行页面跳转,看下图,点击管理员列表后会被认证拦截器首先拦截,验证用户是否登录,如果登录就放行,紧接着会被权限验证拦截器再次拦截,拦截的时候,会根据URL地址上找到对应的方法,然后 ...
- vue拦截器实现统一token,并兼容IE9验证
项目中使用vue搭建前端页面,并通过axios请求后台api接口,完成数据交互.如果验证口令token写在在每次的接口中,也是个不小的体力活,而且也不灵活.这里分享使用vue自带拦截器,给每次请求的头 ...
- Springboot实现filter拦截token验证和跨域
背景 web验证授权合法的一般分为下面几种 使用session作为验证合法用户访问的验证方式 使用自己实现的token 使用OCA标准 在使用API接口授权验证时,token是自定义的方式实现起来不需 ...
- Yii 1.1.17 五、分页类、关联模型、权限验证与默认页面跳转
一.分页类使用 1.在控制器中 // 实例化 $criteria = new CDbCriteria(); $articleModel = Article::model(); // 分页 $total ...
随机推荐
- JDBC请求
做JDBC请求,首先需要两个jar包:mysql驱动-mysql-connector-java-5.1.13-bin.jar 和 sqlServer驱动-sqljdbc4.jar,将这两个jar包放到 ...
- 通过存储过程运行通过DBLINK的查询语句失败-单个语句成功--ORA-00604
版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/q947817003/article/details/24419459 客户遇到个问题,描写叙述例如以 ...
- boost之string_algo
string_algo是用于处理字符串查找,替换,转换等一系列的字符串算法 前缀i:表示大小写不敏感 后缀_copy:表示不变动输入,返回处理结果的拷贝 后缀_if:表示算法需要一个判断式的谓词函数对 ...
- 001infor record 计划时间取值增强-20150622
ZMD_MRP_PARAMETERS 3000公司下工厂跑MRP时,如果为外购则通过外挂表取infor record计划交期. METHOD if_ex_md_mrp_parameters~adjus ...
- 1.4 使用电脑测试MC20的接收英文短信功能
需要准备的硬件 MC20开发板 1个 https://item.taobao.com/item.htm?id=562661881042 GSM/GPRS天线 1根 https://item.taoba ...
- JAVA & C++ 多态
多态,也叫动态绑定. Java: class A { public void f1() { System.out.println("A:f1"); } public void f2 ...
- layer满屏/禁止最大化最小化 可以做选择框使用
1.layer弹窗最大化 var index=layer.open(); layer.full(index); 2.layer禁止最大化最小化 layer.open( [ type:2, title: ...
- 【Tech】mac下svn和scp使用笔记
1.命令行从svn下载代码 mac本身自带svn,所以使用非常简单,在本地创建代码存放的文件夹,然后cd到该文件夹下,运行: svn checkout svn://ip地址/文件路径 . 然后出现要求 ...
- QGIS 编译
QGIS 编译 在编译的过程中花费了很长时间,特别是编译Debug版本.release版本的编译可以从晚上找到很多的资料,但是Debug的编译相对较少.在Debug编译的过程中,需要单独build工程 ...
- Python的装饰器实例用法小结
这篇文章主要介绍了Python装饰器用法,结合实例形式总结分析了Python常用装饰器的概念.功能.使用方法及相关注意事项 一.装饰器是什么 python的装饰器本质上是一个Python函数,它可以让 ...