axios 拦截 , 页面跳转, token 验证(自己摸索了一天搞出来的)

最近做项目,需要登录拦截,验证。于是使用了axios的拦截器(也是第一次使用,摸索了1天,终于搞出来了,真是太高兴啦!!!),废话不多说,直接上代码,

项目结构:vue-cli + webpack + vue + vue-router + vuex

项目结构截图:

其中src下store文件夹中有两个文件,store.js和type.js,其中store.js为:

 1 /**
 2  * Created by yuwenjing on 17/9/13.
 3  */
 4 import Vuex from 'vuex'
 5 import Vue from 'vue'
 6 import * as types from './types'
 7 
 8 Vue.use(Vuex);
 9 export default new Vuex.Store({
10     state: {
11         token: null,
12         userName: ''
13     },
14     mutations: {
15         [types.LOGIN]: (state, data) => {
16             localStorage.token = data;
17             state.token = data;
18         },
19         [types.LOGOUT]: (state) => {
20             localStorage.removeItem('token');
21             state.token = null
22         },
23         [types.USERNAME]: (state, data) => {
24             localStorage.userName = data;
25             state.userName = data;
26         }
27     }
28 })
View Code

types.js为:

 1 /**
 2  * Created by yuwenjing on 17/9/13.
 3  * vuex types
 4  */
 5 
 6 export const LOGIN = 'login';
 7 
 8 export const LOGOUT = 'logout';
 9 
10 export const USERNAME = 'userName'
View Code

 

主要业务代码结构:

 

 其中main.js为:

 1 // The Vue build version to load with the `import` command
 2 // (runtime-only or standalone) has been set in webpack.base.conf with an alias.
 3 import Vue from 'vue'
 4 import App from './App'
 5 import store from './store/store'
 6 import * as types from './store/types'
 7 import router from './router'
 8 import axios from 'axios'
 9 
10 Vue.config.productionTip = false
11 //创建axios实例
12 var $http = axios.create({});
13 
14 // http request 拦截器
15 $http.interceptors.request.use(
16   config => {
17     if(config.url.indexOf('loginCheck')>=0){
18       return config;
19     }else{
20       if (store.state.token) {
21         config.headers.authorization = store.state.token;
22       }
23       return config;
24     }
25 
26   },
27   err => {
28     return Promise.reject(err);
29   });
30 
31 // http response 拦截器
32 $http.interceptors.response.use(
33   response => {
34     return response;
35   },
36   error => {
37     if (error.response) {
38       switch (error.response.data.message) {
39         case "false":
40           // 清除token信息并跳转到登录页面
41           store.commit(types.LOGOUT);
42           router.replace({
43             path: '/'
44           })
45       }
46     }
47     // console.log(JSON.stringify(error));//console : Error: Request failed with status code 402
48     return Promise.reject(error.response.data)
49   });
50 
51 Vue.prototype.$http = $http
52 
53 /* eslint-disable no-new */
54 new Vue({
55   el: '#app',
56   store,
57   router,
58   $http,
59   template: '<App/>',
60   components: { App }
61 })
View Code

router文件夹下index.js为:

 1 import Vue from 'vue'
 2 import Router from 'vue-router'
 3 import login from '@/components/login'
 4 import homePage from '@/components/homePage'
 5 import store from '../store/store'
 6 import * as types from '../store/types'
 7 
 8 Vue.use(Router)
 9 
10 const routes = [
11   {
12     path:'/',
13     component:login
14   },
15   {
16     path: '/homePage',
17     meta: {
18       requireAuth: true,
19     },
20     component: homePage
21   }
22 ];
23 
24 // 页面刷新时,重新赋值token,用户名也在界面上展示
25 if (window.localStorage.getItem('token')) {
26   store.commit(types.LOGIN, window.localStorage.getItem('token'));
27 }
28 if(window.localStorage.getItem('userName')){
29   store.commit(types.USERNAME, window.localStorage.getItem('userName'));
30 }
31 
32 const router = new Router({
33   routes
34 });
35 
36 router.beforeEach((to, from, next) => {
37   if (to.matched.some(r => r.meta.requireAuth)) {
38     if (store.state.token) {
39       next();
40     }
41     else {
42       next({
43         path: '/'
44       })
45     }
46   }
47   else {
48     next();
49   }
50 })
51 
52 export default router;
View Code

登录界面login.vue代码为:

  1 <template>
  2   <div class="login-wrapper">
  3     <!--顶部-->
  4     <div class="top">
  5       <span class="content">
  6         <img src="../../static/img/login_logo.png" class="system-logo">
  7         <span class="system-name">北京热力面积投停管理系统</span>
  8       </span>
  9     </div>
 10     <!--顶部结束-->
 11 
 12     <!--中部-->
 13     <div class="center">
 14       <div class="login">
 15 
 16         <!--中部左侧-->
 17         <div class="left">
 18           <img src="../../static/img/login_city.png">
 19         </div>
 20         <!--中部左侧结束-->
 21 
 22         <!--中部右侧-->
 23         <div class="right">
 24 
 25 
 26           <span class="login-title">用户登录</span>
 27 
 28           <!--用户名输入-->
 29           <div class="username-wrapper">
 30             <i class="username-logo"></i>
 31             <input type="text" class="username" placeholder="用户名" v-model="username" ref="username" @focus="usernameFocus" :class="{'username-focus': isUsernameFocus}">
 32           </div>
 33           <!--用户名输入结束-->
 34 
 35           <!--密码输入-->
 36           <div class="pwd-wrapper">
 37             <i class="pwd-logo"></i>
 38             <input type="password" class="pwd" placeholder="密码" v-model="pwd" ref="pwd" @focus="pwdFocus" :class="{'pwd-focus': isPwdFocus}">
 39           </div>
 40           <!--密码输入结束-->
 41 
 42           <!--提交按钮-->
 43           <button class="login-btn" @click="clickLoginBtn">登录</button>
 44           <!--提交按钮结束-->
 45         </div>
 46         <!--中部右侧结束-->
 47       </div>
 48     </div>
 49     <!--中部结束-->
 50 
 51     <!--底部-->
 52     <div class="bottom"></div>
 53     <!--底部结束-->
 54 
 55   </div>
 56 </template>
 57 
 58 <script type="text/ecmascript-6">
 59   import * as types from '../store/types'
 60   import {SWAGGER_CONFIG} from '../config/config'
 61   export default {
 62     data() {
 63       return {
 64         // 用户名密码
 65         username: '',
 66         pwd: '',
 67         isUsernameFocus: true,
 68         isPwdFocus: false
 69       }
 70     },
 71 
 72     methods: {
 73       // 点击登录按钮
 74       clickLoginBtn() {
 75         if (this.username && this.pwd) {
 76           this.requestLoginInterface();
 77         } else {
 78           alert('用户名或密码不能为空');
 79         }
 80       },
 81 
 82       // 请求登录接口数据
 83       requestLoginInterface () {
 84         var self = this;
 85         self.$http.post(SWAGGER_CONFIG+'/Ddaas/userrole/loginCheck',
 86           {
 87             "userName":self.username,
 88             "passWord":self.pwd
 89           }
 90         ).then(function (response) {
 91           if(response.data.data == false){
 92             alert("用户名或密码不匹配!")
 93             return;
 94           }else{
 95             self.$store.commit(types.USERNAME,self.username);
 96             self.$store.commit(types.LOGIN, response.data.data);
 97             self.$router.push({path:"/homePage"});
 98           }
 99         })
100           .catch(function (error) {
101             console.log(error);
102           });
103       },
104 
105       usernameFocus () {
106         this.isUsernameFocus = true;
107         this.isPwdFocus = false;
108       },
109 
110       pwdFocus() {
111         this.isUsernameFocus = false;
112         this.isPwdFocus = true;
113       }
114     },
115 
116     mounted () {
117       // 挂在成功就聚焦输入框
118       this.$refs.username.focus();
119     }
120   }
121 
122 </script>
123 
124 <style scoped>
125   .login-wrapper {
126     width: 100%;
127     height: 100%;
128     min-width: 700px;
129     min-height: 750px;
130   }
131 
132   .login-wrapper .top {
133     width: 100%;
134     height: 22%;
135     display: flex;
136     align-items: center;
137   }
138 
139   .login-wrapper .top .content {
140     display: block;
141     width: 100%;
142     height: 61px;
143     text-align: center;
144   }
145 
146   .login-wrapper .top .content .system-logo {
147     vertical-align: top;
148   }
149 
150   .login-wrapper .top .content .system-name {
151     font-size: 30px;
152     line-height: 61px;
153     color: #077fb7
154   }
155 
156   .center {
157     width: 100%;
158     height: 56%;
159     background: linear-gradient(to bottom, #057fbf, #1697d4);
160     /*text-align: center;*/
161     display: flex;
162     justify-content: center;
163     align-items: center;
164   }
165 
166   .center .login {
167     width: 52%;
168     height: 68%;
169     background-color: white;
170     border-radius: 5px;
171     border: 15px solid white;
172     box-shadow: 0 0 0 7px rgba(139, 208, 255, 0.5);
173   }
174 
175   .center .login .left {
176     width: 60%;
177     height: 100%;
178     box-sizing: border-box;
179     float: left;
180   }
181 
182   .center .login .right {
183     float: right;
184     width: 40%;
185     height: 100%;
186     padding: 22px 8px 30px 22px;
187   }
188 
189   .center .login .right .login-title {
190     display: block;
191     width: 100%;
192     height: 24px;
193     font-size: 24px;
194     text-align: center;
195     line-height: 24px;
196     vertical-align: middle;
197   }
198 
199   .center .login .right .username-wrapper {
200     position: relative;
201   }
202 
203   .center .login .right .username-logo {
204     display: inline-block;
205     position: absolute;
206     top: 12px;
207     left: 10px;
208     width: 14px;
209     height: 14px;
210     background: url('../../static/img/login_user.png') no-repeat;
211   }
212 
213   .center .login .right .username {
214     display: block;
215     width: 100%;
216     height: 40px;
217     margin-top: 25px;
218     outline: none;
219     padding-left: 34px;
220     border: 1px solid #e2e7eb;
221     color: #404040;
222   }
223 
224   .center .login .right .username-focus {
225     display: block;
226     width: 100%;
227     height: 40px;
228     margin-top: 25px;
229     outline: none;
230     padding-left: 34px;
231     border: 1px solid #0782bb;
232     color: #404040;
233   }
234 
235   .center .login .right .username::-webkit-input-placeholder {
236     color: #d2d2d2;
237   }
238 
239   .center .login .right .username:-moz-placeholder {
240     color: #d2d2d2;
241   }
242 
243   .center .login .right .username:-ms-input-placeholder {
244     color: #d2d2d2;
245   }
246 
247   .center .login .right .pwd-wrapper {
248     position: relative;
249   }
250 
251   .center .login .right .pwd-logo {
252     display: inline-block;
253     position: absolute;
254     top: 12px;
255     left: 10px;
256     width: 14px;
257     height: 15px;
258     background: url('../../static/img/login_pwd.png') no-repeat;
259   }
260 
261   .center .login .right .pwd {
262     display: block;
263     width: 100%;
264     height: 40px;
265     margin-top: 25px;
266     outline: none;
267     padding-left: 34px;
268     border: 1px solid #e2e7eb;
269     color: #404040;
270   }
271 
272   .center .login .right .pwd-focus {
273     display: block;
274     width: 100%;
275     height: 40px;
276     margin-top: 25px;
277     outline: none;
278     padding-left: 34px;
279     border: 1px solid #0782bb;
280     color: #404040;
281   }
282 
283   .center .login .right .pwd::-webkit-input-placeholder {
284     color: #d2d2d2;
285   }
286 
287   .center .login .right .pwd:-moz-placeholder {
288     color: #d2d2d2;
289   }
290 
291   .center .login .right .pwd:-ms-input-placeholder {
292     color: #d2d2d2;
293   }
294 
295   .center .login .right .login-btn {
296     display: block;
297     width: 100%;
298     height: 40px;
299     margin-top: 30px;
300     background: linear-gradient(to bottom, #1799d6, #047db5);
301     border: none;
302     color: white;
303     font-size: 20px;
304     outline: none;
305   }
306 
307   .center .login .left img {
308     width: 100%;
309     height: 100%;
310   }
311 
312   .bottom {
313     width: 100%;
314     height: 22%;
315   }
316 </style>
View Code

展示用户名和注销功能都在headTop.vue中,headTop.vue为:

  1 <template>
  2     <div id="all">
  3       <div class="top-left">
  4         <p>
  5           <img src="../../../static/img/BJRLLOGO.png">
  6           <span>北京热力面积投停管理系统</span>
  7         </p>
  8       </div>
  9       <div class="top-right">
 10 
 11           <div>
 12             <ul class="first-ul">
 13               <li class="first-li">
 14                 <img src="../../../static/img/index.png" class="base-img">
 15                 <span class="nav-span">首页</span>
 16               </li>
 17               <li class="dropdown">
 18                 <img src="../../../static/img/user.png">
 19                 <span class="dropdown-toggle nav-span" data-toggle="dropdown">
 20                   {{userName}}
 21                   <!--<b class="caret"></b>-->
 22                   <img src="../../../static/img/userxiala.png">
 23                 </span>
 24                 <ul class="dropdown-menu">
 25                   <li>
 26                     <img src="../../../static/img/qiehuan.png">
 27                     <span>切换账号</span>
 28                   </li>
 29                   <li>
 30                     <img src="../../../static/img/xiugai.png">
 31                     <span>修改密码</span>
 32                   </li>
 33 
 34                   <li>
 35                     <img src="../../../static/img/tuichu.png">
 36                     <span @click="logout">退出登录</span>
 37                   </li>
 38 
 39                 </ul>
 40               </li>
 41             </ul>
 42           </div>
 43 
 44 
 45       </div>
 46 
 47     </div>
 48 </template>
 49 <style scoped>
 50   #all{
 51     width:100%;
 52     height:100%;
 53     background: #0A86C0;
 54   }
 55   .top-left{
 56     width:50%;
 57     height:100%;
 58     float:left;
 59     display: table;
 60   }
 61   .top-left p{
 62     display: table-cell;
 63     vertical-align: middle;
 64   }
 65   .top-left img{
 66     width:auto;
 67     height:auto;
 68     max-width: 100%;
 69     max-height: 100%;
 70     margin-left: 2%;
 71   }
 72   .top-left span{
 73     display: inline-block;
 74     color:#fff;
 75     font-size: 1.3vw;
 76     font-weight: bold;
 77     font-family: "Microsoft YaHei UI";
 78   }
 79   .top-right{
 80     width:50%;
 81     height:100%;
 82     float:left;
 83   }
 84   .top-right div{
 85     width:100%;
 86     height:100%;
 87     position: relative;
 88     display: table;
 89   }
 90   .first-ul{
 91     list-style: none;
 92     position: absolute;
 93     right:2%;
 94     top:36%;
 95     width:27%;
 96   }
 97   .first-ul>li{
 98     display: inline;
 99   }
100   .dropdown-menu li{
101     text-align: center;
102   }
103   .nav-span{
104     color:#fff;
105     font-size: 0.8vw;
106     font-family: "Microsoft YaHei UI";
107     cursor: pointer;
108   }
109   .dropdown-menu{
110     min-width: 98px;
111   }
112   .dropdown-menu li{
113     margin-top:6%;
114   }
115   .dropdown-menu span{
116     font-size: 0.6vw;
117     font-family: "Microsoft YaHei UI";
118     cursor: pointer;
119     color:#121212;
120   }
121   .first-li{
122     margin-right: 20%;
123   }
124   .base-img{
125     vertical-align: text-top;
126   }
127 </style>
128 <script>
129   import * as types from '../../store/types'
130   import {mapState} from 'vuex'
131     export default{
132         data(){
133             return{
134 
135             }
136         },
137         methods:{
138           logout(){
139             var self = this;
140             self.$store.commit(types.LOGOUT)
141             self.$router.push({
142               path: '/'
143             })
144 
145           }
146 
147         },
148         computed: mapState({
149             userName: state => state.userName
150         })
151 
152     }
153 </script>
View Code

要说一句,就是vuex中的state里的值在页面刷新的时候会消失(即vuex中的状态管理是响应式的),因此我们使用localStorage来解决这个问题

这就是为什么这么麻烦在state和localStorage中传来传去,是因为state的值刷新后会没了,而localStorage的值不能响应式地变化(Vue 仅可以对其管理的数据做响应式处理,可以理解为 data 中的数据,localStorage 并不在 Vue 的管理下,自然不会有响应特性);

完整的项目地址为:

https://github.com/yuwenjing0727/heating-power

posted @ 2017-09-13 15:07  yuwenjing  阅读(4095)  评论(0编辑  收藏  举报