開始一個koa2-(6)-前後端分離+vue-cli3+JWT生成token登錄校驗

token流程;

  • 前端使用用戶名、密碼來請求服務器
  • 服務器通過數據庫查詢等操作驗證用戶的信息
  • 服務器通過驗證發送給用戶一個token
  • 前端存儲token(cookie、sessionStorage、loaclStorage),並在每次請求時附送上這個token值
  • 後臺驗證token值,並返回數據
  • token會有過期,前端登出的時候直接清空本地token,服務端不需要任何操作

 

session VS  token:

  • session要求服務端存儲信息,並且根據id能夠檢索,而token不需要。在大規模系統中,對每個請求都檢索會話信息可能是一個複雜和耗時的過程。但另外一方面服務端要通過token來解析用戶身份也需要定義好相應的協議。
  • session一般通過cookie來交互,而token方式更加靈活,可以是cookie,也可以是其他header,也可以放在請求的內容中。不使用cookie可以帶來跨域上的便利性。
  • token的生成方式更加多樣化,可以由第三方服務來提供

詳細session:開始一個koa2 -(4)-session


那麼開始

本文前後端完全分離。前端通過ajax請求後端數據;不再使用模板引擎;

假設你已經用vue-cli3 製作了一個前端項目E:\myKun\yuntumap-web;這個項目的後臺語言可以是php、java、.net、還有c#等等;

在原有的前端項目中我們來嘗試寫一個koa2語言的後臺與之匹配; 

上圖;

 

 而後端koa2的目錄;結合前幾節課的知識點;

 好現在開始。

1運行你的前端項目;運行後瀏覽器自動打開 http://localhost:8080 

2運行後臺koa2-test ;因爲都在本地運行的;所以 確保後端和前端的端口不一致;比如3000;

3安裝  koa-cors 他可以解決跨域問題;

npm install koa-cors --save

在app.js 中

// CORS是一個W3C標準,全稱是"跨域資源共享"(Cross-origin resource sharing)。
// 下面以koa2-cors爲例,
const cors = require('koa-cors');
// 具體參數我們在後面進行解釋
app.use(cors({
  origin: function (ctx) {
	if (ctx.url === '/test') {
	  return "*"; // 允許來自所有域名請求
	}
	return 'http://localhost:8080'; // 這樣就能只允許 http://localhost:8080 這個域名的請求了
  },
  exposeHeaders: ['WWW-Authenticate', 'Server-Authorization'],
  maxAge: 5,
  credentials: true,
  allowMethods: ['GET', 'POST', 'DELETE'],
  allowHeaders: ['Content-Type', 'Authorization', 'Accept'],
}))

這裏插個題外話,koa2每次修改代碼都重啓一次太麻煩;我們安裝nodemon ,熱啓動;

npm install --save-dev nodemon

在package.json 中修改

 "scripts": {
    "start": "nodemon ./bin/www"
  },

現在我們回到前端;

將請求的根路徑改成

let rootUrl = 'http://localhost:3000'

ajax每次請求;

這個ajax我自己按照喜好封裝起來了。具體vue插件/公共方法屬性

所以登錄的ajax使用;

 login(){
		let data = {
		  account: this.account,
		  password: md5(this.password),

		};
		this.myAjax('/api/AlarmHandle/GetLogin', data).then(res=>{
		  this.toast(res.ReturnMsg);
		
		  this.config.setItem('token', res.Token)
		  this.config.setItem('account',this.account);
		 this.mytime= setTimeout(()=>{
			this.goHome();
		  },1000)
		})
	  }

好,回到後端;

 1安裝token相關中間件

jsonwebtoken,服務認證生成一個json對象;

koa-jwt 主要提供路由權限控制的功能,它會對需要限制的資源請求進行檢查;

在app.js中

const koajwt = require('koa-jwt');
//通過 app.use 來調用該中間件,並傳入密鑰 {secret: 'my_token'},unless 可以指定哪些 URL 不需要進行 token 驗證。
app.use(koajwt({
  secret:  config.secret
}).unless({
  path: [/\api\/AlarmHandle\/GetLogin/]

}));

新建目錄token/createToken.js

/**
 * Created by Administrator on 2018/12/4 0004.
 */
const jwt = require('jsonwebtoken');
const config=require('../config')

module.exports = function(name){
  //生成token
  //第一個參數是載荷,用於編碼後存儲在 token 中的數據
  //第二個是密鑰,自己定義的,驗證的時候也是要相同的密鑰才能解碼
  //第三個是options,可以設置 token 的過期時間
  const token = jwt.sign({name: name}, config.secret, {expiresIn: '10s'});
  console.log(token)
  return token;
};

新建目錄token/checkToken.js

const jwt = require('jsonwebtoken');
const util = require('util')
const verify = util.promisify(jwt.verify) // 解密
const config=require('../config')
//檢查token是否過期
module.exports = async (token) =>{
  if (token) {
	let payload
	try{
	  payload = await verify(token, config.secret)  // // 解密,獲取payload
	  console.log(payload,"payload")
	}catch (err){
	  return false
	}
	return true
  } else {
	return false;
  }
};

在 myrouter/login.js

const router = require('koa-router')();
const sql = require('../async-db/sql.js')
let createToken = require('../token/createToken.js')
let checkToken = require('../token/checkToken.js')

router.get('/api/AlarmHandle/GetLogin', async (ctx, next) => {

  let name = ctx.query.account;
  let pass = ctx.query.password;
  await sql.findUserData(name)
	  .then(res=> {
		if (res.length != 0) {
		  if (pass === res[0]['pass']) {
			console.log('登錄成功')
			
			ctx.response.body = {
			  ReturnCode: "SUCCESS",
			  ReturnMsg: '登錄成功',
			  Token: createToken(name)
			}
		  } else {
			ctx.response.body = {
			  ReturnCode: "FAIL",
			  ReturnMsg: '密碼錯誤',
			 
			}
		  }
		} else {
		  ctx.response.body = {
			ReturnCode: "FAIL",
			ReturnMsg: '賬號不存在',
			
		  }
		 
		  console.log('登錄失敗')
		}
		next();
		
	  })

})

假設MySQL中已經存在; 

 

登錄成功後,前端再次請求服務器,需要把token返回給後臺;

 所以。在myrouter/login.js中再加入前端請求的新路由/api/AlarmHandle/GetAlarmOrder

router.get('/api/AlarmHandle/GetAlarmOrder', async (ctx, next) => {
  let token = ctx.query.Token
  let istoken = await checkToken(token);
  
  ctx.response.body = {
	ReturnCode: istoken ? "SUCCESS" : 'FAIL',
	ReturnMsg: istoken ? '操作成功' : 'token失效',
	TokenInvalid: istoken
  }

})

前端響應;

用戶登出;在本地清空儲存的token即可;

 loginOut(){
		localStorage.clear();
		this.$router.push('/login')
	  }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章