vue+koa2+token登陸驗證

koa2+vue

  • 用vue-cli搭建前端項目
  • 用koa2搭建后臺,給前端提供數據訪問接口

項目結構

pro.png
  • 用vue-cli 搭建的項目,紅色框中是新建的文件夾用于存放koa
  • 剩下的文件在寫項目中慢慢增加,最初就是這樣的
  • 之后將項目跑起來,看一下有沒有問題(這里就當作沒有問題)

前端

  • 這里選用Element-ui和vue搭配
  • 這里采用的是element-UI的完整引入,如果小伙伴想用按需加載的話 參考按需引入
  • 登陸頁面就不介紹了 大家可以直接用(components/login.vue)
安裝element-ui
    npm i element-ui -S
    
在src/main.js中引入
    import ElementUI from 'element-ui';
    import 'element-ui/lib/theme-chalk/index.css';
    Vue.use(ElementUI);

登陸

  • 安裝axios用于前后臺的數據傳輸 npm install --save axios
  • 在main.js中配置全局的axios
  • 在src下新建一個axios文件夾,配置攔截器 和 全局地址 token
import axios from 'axios' // axios引用
import qs from 'qs'

// axios.defaults.baseURL = 'http://localhost:3000'; // 全局的地址,因為我的koa監聽端口是3000, 這里可以按照大家自己的來配置
// axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;  //這是配置token
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
// 添加請求攔截器
axios.interceptors.request.use(function (config) {
  // 在發送請求之前做些什么
  if(config.method === 'post'){
    config.data = qs.stringify(config.data)
  }
  return config;
}, function (error) {
  // 對請求錯誤做些什么
  return Promise.reject(error);
});

// 添加響應攔截器
axios.interceptors.response.use(function (response) {
  // 對響應數據做點什么
  return response;
}, function (error) {
  // 對響應錯誤做點什么
  return Promise.reject(error);
});

export default axios;
  • 在src下新建一個api文件夾,存放訪問后臺的地址
import axios from 'axios';
export default{
  denglu: (data) => {
    return axios.post('/login', data)
  }
}

前端先告一段落,我們來配置后臺接口

搭建koa2

學習koa

  • 安裝koa2 koa-bodyparser koa-router koa2-cors npm install --save koa koa-bodyparser koa-router koa2-cors

  • [x] koa-bodyparser:用于接收并解析前臺發送過來的post數據

  • [x] koa-router:路由

  • [x] koa2-cors:用來解決前端的跨域

  • 搭建koa 在瀏覽器運行localhost:3000 頁面輸出 hello 表示成功了 ??

    下面的代碼是驗證koa是否搭建成功,可以跳過

const Koa = require('koa');
const bodyparser = require('koa-bodyparser');
    
const app = new Koa();
    
app.use(async (ctx) => {
  ctx.body = 'hello';
})
    
app.listen(3000);
  • 接下來 開始搭建koa的路由
const Koa = require('koa'); 
const bodyparser = require('koa-bodyparser');
const router = require('koa-router')();
const login = require('./router/login.js');     //這是登陸路由的文件
const cors = require('koa2-cors');
const app = new Koa();
app.use(bodyparser())
這是處理前端跨域的配置
app.use(cors({
  origin: function (ctx) {
    if (ctx.url === '/login') {
      return "*"; // 允許來自所有域名請求
    }
    return 'http://localhost:8080';
  },
  exposeHeaders: ['WWW-Authenticate', 'Server-Authorization'],
  maxAge: 5,
  credentials: true,
  allowMethods: ['GET', 'POST', 'DELETE'],
  allowHeaders: ['Content-Type', 'Authorization', 'Accept'],
}));
    
router.use('/login',login);   //將路由提取出去便于管理
app
  .use(router.routes())
  .use(router.allowedMethods());
app.listen(3000);
  • 接下來就是去配置登陸的路由
const router = require('koa-router')();

router
  .post('/', async ctx => {
    ctx.body = {  //這是向前臺返回的數據 因為沒有連接數據庫所以我們自己定義,后面講連接數據庫
      user:'111',
      code:1,
      status:200
    };
  });

module.exports = router.routes();
  • 接下來 進入src/axios下的文件打開 將注釋的代碼放開
axios.defaults.baseURL = 'http://localhost:3000'; // 全局的地址,因為我的koa監聽端口是3000, 這里可以按照大家自己的來配置

ok 我們開測試一下

可以用postmain 也可以直接在瀏覽器中測試

postmain

postmain.png

chrome瀏覽器 直接在瀏覽器中測試

chrome.png

能取到數據 那就說明沒有問題
接下來開始連接數據庫 數據庫用的是 mysql

創建數據庫

  • 我在本地用的是mamp+navicat 大家可以用自己熟悉的

  • 安裝mysql-pro 一個連接數據庫的中間件npm install mysql-pro

  • 接下來在創建表

  • 需要的字段

    id user pass
    database.png
  • 隨便添加兩個就可以了,這里沒有做驗證,需要的小伙伴可以自己添加這個功能

  • 到此就結束了,我們來驗證一下

  • 在koa2/sql下新建一個js文件

    const Client = require('mysql-pro');
    const db = new Client({
      mysql:{
        host:'localhost',
        port:3306,
        database:'vue-koa2',
        user:'root',
        password:'root'
      }
    })
    
    module.exports = db;
    
  • 接下來進入koa2/router下的login.js

  • 看一下我們在前端拿到的數據

bodyparser.png

因為我們用了中間件koa-bodyparser ,在koa2/router/login.js中這樣寫

 ```
 const router = require('koa-router')();
const db = require('../sql/sql');

router
  .post('/', async ctx => {
    let user = ctx.request.body   //接收前端傳過來的post數據
    console.log(user);
    ctx.body = {
      user:'111',
      code:1,
      status:200
    };
  });

module.exports = router.routes();
 ```
 控制臺輸出 { user: '123', pass: '123' }

接下來連接數據數據庫,查詢

const router = require('koa-router')();
const db = require('../sql/sql');

router
  .post('/', async ctx => {
    let user = ctx.request.body.user;
    let pass = ctx.request.body.pass;
    // 將接收到的前臺數據和數據庫中的數據匹配
    // 如果匹配成功 返回status 200 code 1
    // 不成功返回status 1000 code 0
    db.query('select * from login where user=? and pass=?;',[user,pass]).then(res => {
      console.log(res);
    })
    ctx.body = {
      user:'111',
      code:1,
      status:200
    };
  });

module.exports = router.routes();

控制臺輸出[ RowDataPacket { id: 1, user: '111', pass: '111' } ]
表示拿到數據
注意
這是個數組的格式,如果將user返回給前端res[0].user,

const router = require('koa-router')();
const db = require('../sql/sql');

router
  .post('/', async ctx => {
    let user = ctx.request.body.user;
    let pass = ctx.request.body.pass;
    // 將接收到的前臺數據和數據庫中的數據匹配
    // 如果匹配成功 返回status 200 code 1
    // 不成功返回status 1000 code 0
    await db.query('select * from login where user=? and pass=?;', [user, pass]).then(res => {
      if (res.length === 0) {   // 數據庫中沒有匹配到用戶
        ctx.body = {
          code: 0,
          status: 1000,
          msg: 'error'
        }
      } else {  //匹配到用戶
        ctx.body = {
          user: res[0].user,
          code: 1,
          status: 200
        }
      }
    })

  });

module.exports = router.routes();

以上就是簡單的前后數據交互
接下來講解的是vuex權限驗證和token


token

  • 創建token我們要用到

  • [x] 驗證token的網站

  • [x] 創建token中間件

  • 在koa2中新建文件夾token

  • token下新建一個addtoken.js用于創建token再新建一個proving.js用于驗證token

addtoken

const jwt = require('jsonwebtoken');
const serect = 'token';  //密鑰,不能丟
module.exports = (userinfo) => { //創建token并導出
  const token = jwt.sign({
    user: userinfo.user,
    id: userinfo.id
  }, serect, {expiresIn: '1h'});
  return token;
};

在router/login中引入

const router = require('koa-router')();
    const db = require('../sql/sql');
    const addtoken = require('../token/addtoken');
    
    router
      .post('/', async ctx => {
        let user = ctx.request.body.user;
        let pass = ctx.request.body.pass;
        // 將接收到的前臺數據和數據庫中的數據匹配
        // 如果匹配成功 返回status 200 code 1
        // 不成功返回status 1000 code 0
        await db.query('select * from login where user=? and pass=?;', [user, pass]).then(res => {
          if (res.length === 0) {   // 數據庫中沒有匹配到用戶
            ctx.body = {
              code: 0,
              status: 1000,
              msg: 'error'
            }
          } else {  //匹配到用戶
            let tk = addtoken({user:res[0].user,id:res[0].id})  //token中要攜帶的信息,自己定義
            ctx.body = {
              tk,  //返回給前端
              user: res[0].user,
              code: 1,
              status: 200
            }
          }
        })
    
      });
    module.exports = router.routes();

vuex

拿到了后臺的token,我們要做什么呢?

  1. 存到localStorage中
    • 在src/components/login.vue中將token和user存進localStorage中
  2. 存到vuex中
    • npm install --save vuex

這看自己的需求了
回到前端 我們改一下路由

沒改之前

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

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      name: 'login',
      component: resolve => require(['@/components/login'],resolve)
    },
    {
      path: '/homes',
      name: 'homes',
      component: resolve => require(['@/components/homes'],resolve)
    }
  ]
})

改過之后

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

Vue.use(Router);

const router = new Router({
  routes: [
    {
      path: '/',
      name: 'login',
      component: resolve => require(['@/components/login'], resolve)
    },
    {
      path: '/homes',
      name: 'homes',
      meta: {
        auth: true
      },
      component: resolve => require(['@/components/homes'], resolve)
    }
  ]
});

router.beforeEach((to, from, next) => {
  if (to.meta.auth) { //權限判斷
    if ('進行判斷') { //讀取token值
    //  成功
      next()
    } else {
      next({path:'/'})
    }
  } else {
    // 沒有meta.auth 不用管
    next()
  }
});

export default router;

在路由中要驗證的地方添加meta:{auth:true}

接下來就是創建vuex

  1. 在src下新建文件夾vuex

  2. 全局引入vuex

  3. 在vuex中新建store.js文件

     import Vue from 'vue';
     import Vuex from 'vuex'
     Vue.use(Vuex);
     
     const store = new Vuex.Store({
       state:{
         user:localStorage.getItem('user') || '',
         token:localStorage.getItem('token') || null
       }
     });
     export default store;
    
  4. 接下來改一下路由中的權限判斷

     router.beforeEach((to, from, next) => {
       if (to.meta.auth) { //權限判斷
         if (localStorage.getItem('token')) { //讀取token值
         //  成功
           next()
         } else {
           next({path:'/'})
         }
       } else {
         // 沒有meta.auth 不用管
         next()
       }
     });
    

在login.vue中接收到數據后添加

    localStorage.setItem('token', data.data.tk) //存儲token
    localStorage.setItem('user', data.data.user) //存儲用戶
    this.LOGIN({
      token:data.data.tk,
      user:data.data.user
    });
  1. 這樣就將token拿到了并存進localStorage中,接下來就是將token在發送的時候 添加進頭部中 發送給后臺

  2. 在axios/axios.js中

      axios.defaults.headers.common['Authorization'] = 'Bearer '+ localStorage.getItem('token');
    
  3. 在登陸的時候這樣就會將token發送給后臺了

  4. 后臺驗證前臺發送的token

     const jwt = require('jsonwebtoken');
     const serect = 'token';  //密鑰,不能丟
     module.exports =(tokens) => {
     
       if (tokens){
         let toke = tokens.split(' ')[1];
         // 解析
         let decoded = jwt.decode(toke, serect);
         return decoded;
       }
     };
    
  5. 在login.js中,添加

        router.get('/test',async (ctx,next) => {
     let token = ctx.request.header.authorization;
     if (token){
     //  獲取到token
       let res = proving(token);
         if (res && res.exp <= new Date()/1000){
           ctx.body = {
             message: 'token過期',
             code:3
           };
         } else {
           ctx.body = {
             message: '解析成功',
             code:1
           }
         }
     } else{  // 沒有取到token
       ctx.body = {
         msg:'沒有token',
         code:0
       }
     }
     });
    

項目至此算是告一段落,大家可以把我的項目clone到本地下運行
項目地址

  • 運行方式
    • 運行vue npm start
    • 在koa2下運行app.js node app.js

項目中也許有很多寫的不對的地方,或者不規范什么的 大家就引以為戒,

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,156評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,401評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,069評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,873評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,635評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,128評論 1 323
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,203評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,365評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,881評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,733評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,935評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,475評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,172評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,582評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,821評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,595評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,908評論 2 372

推薦閱讀更多精彩內容