你們都知道http請求是無狀態的,可是web應用中又須要記住登陸信息,方便後續的操做。 因而,程序員們想到了一個方法:請求的時候拿着一個令牌,服務器認證這個令牌,若是經過校驗纔會響應數據。html
const Koa = require('koa')
const app = new Koa()
app.use(async(ctx)=>{
if(ctx.url=== '/login'){//①①①①①①①①①
...
const { username, password } = ctx.body;
/** 數據庫查詢用戶,校驗成功後設置cookie * ...其餘操做 */
ctx.cookies.set( //②②②②②②②②②
'username',username,{
domain:'localhost', // 寫cookie所在的域名
path:'/index', // 寫cookie所在的路徑
maxAge:1000*60*60*24, // cookie有效時長
expires:new Date('2019-2-12'), // cookie失效時間
httpOnly:false, // 是否只用於http請求中獲取
overwrite:false // 是否容許重寫
}
)
ctx.body = {code:0,msg:'cookie is set'}
}else{
//③③③③③③③③③③③③
let hasCookies = ctx.cookies.get('username');
//④④④④④④④④④④④④
if( hasCookies ){
/** 處理請求返回結果 * let data = await database.table.find({}) * ctx.body = { * code:0, * data:data, * msg:'success' * } */
} else {
/** * 找不到cookies邏輯處理 * ctx.body = { * code:-1, * msg:'failed,has no cookies' * } */
}
}
})
app.listen(3000,()=>{
console.log('server is starting at port 3000')
})
複製代碼
上述cookie的方式能夠知足業務需求,可是存在明顯的缺點:程序員
httpOnly
,可是使用document.cookie
仍是能夠讀取到的,容易篡改泄露基於以上緣由,程序員們又想到了另外一種解決方案:sessionweb
具體流程和cookie同樣。不一樣的是,服務器校驗登陸信息正確後,一是將session存入數據庫(或者內存中),另外一個是將session對應的key即(externalKey)寫入到cookie。數據庫
const Koa = require('koa');
const Koa_Session = require('koa-session');
const session_signed_key = ["some secret hurr"]; // 這個是配合signed屬性的簽名key
const session_config = {
key: 'koa:sess', /** cookie的key。 (默認是 koa:sess) */
maxAge: 4000, /** session 過時時間,以毫秒ms爲單位計算 。*/
autoCommit: true, /** 自動提交到響應頭。(默認是 true) */
overwrite: true, /** 是否容許重寫 。(默認是 true) */
httpOnly: true, /** 是否設置HttpOnly,若是在Cookie中設置了"HttpOnly"屬性,那麼經過程序(JS腳本、Applet等)將沒法讀取到Cookie信息,這樣能有效的防止XSS攻擊。 (默認 true) */
signed: true, /** 是否簽名。(默認是 true) */
rolling: true, /** 是否每次響應時刷新Session的有效期。(默認是 false) */
renew: false, /** 是否在Session快過時時刷新Session的有效期。(默認是 false) */
};
// 實例化
const app = new Koa();
const session = Koa_Session(session_config, app)
app.keys = session_signed_key;
// 使用中間件,注意有前後順序
app.use(session);
app.use(ctx => {
const databaseUserName = "testSession";
const databaseUserPasswd = "noDatabaseTest";
// 對/favicon.ico網站圖標請求忽略
if (ctx.path === '/favicon.ico') return;
if (!ctx.session.logged) { // 若是登陸屬性爲undefined或者false,對應未登陸和登陸失敗
// 設置登陸屬性爲false
ctx.session.logged = false;
// 取請求url解析後的參數對象,方便比對
// 如?nickname=post修改&passwd=123解析爲{nickname:"post修改",passwd:"123"}
let query = ctx.request.query;
// 判斷用戶名密碼是否爲空
if (query.nickname && query.passwd) {
// 比對並分狀況返回結果
if (databaseUserName == query.nickname) { // 若是存在該用戶名
// 進行密碼比對並返回結果
ctx.body = (databaseUserPasswd == query.passwd) ? "登陸成功" : "用戶名或密碼錯誤";
ctx.session.logged = true;
} else { // 若是不存在該用戶名
ctx.body = "用戶名不存在";
}
} else {
ctx.body = "用戶名密碼不能爲空";
}
} else {
/**ctx.body = "已登陸" */
}
}
);
app.listen(3000);
複製代碼
用session方式鑑權,解決了部分問題,可是仍存在很多缺點:json
因而程序員們又想到了一個解決辦法:JWT(JSON Web Token)
JWT的原理是,服務器認證之後,生成一個 JSON 對象,發回給用戶,就像下面這樣:跨域
{
"姓名": "森林",
"角色": "搬磚工",
"到期時間": "2020年1月198日16點32分"
}
複製代碼
用戶與服務端通訊的時候,都要發回這個 JSON 對象。服務器徹底只靠這個對象認證用戶身份。爲了防止用戶篡改數據,服務器在生成這個對象的時候,會加上簽名。瀏覽器
服務器就不保存任何 session 數據了,也就是說,服務器變成無狀態了,從而比較容易實現擴展。安全
const Koa = require('koa')
const router = require('koa-router')
const jwt = require('jsonwebtoken')
const jwtAuth = require('koa-jwt')
const secret = 'itisvalue'
const bodyParser = require('koa-bodyparser')
const static = require('koa-static')
const app = new Koa()
app.use(static(__dirname +'/'))
app.use(bodyParser())
//配置session
router.post('/users/login-token', async ctx => {
const {body} = ctx.request
const userinfo = body.username
/** 登陸邏輯處理...*/
ctx.body = {
message:'login success',
user:userinfo,
token:jwt.sign({
data:userinfo,
exp:Math.floor(Date.now() / 1000) +60*60 //token過時時間,秒爲單位
},
secret)
}
})
//檢查token是否合法
router.get('/users/getUser-token',
jwtAuth({secret}), async ctx => {
//驗證經過
ctx.body = {
message:'get user datainfo success',
userinfo:ctx.state.user.data
}
})
複製代碼