koa + vue + session 實現一個簡單的登錄邏輯
/login component/login-session.html
<!DOCTYPE html> < head> < script src = " https://cdn.jsdelivr.net/npm/vue/dist/vue.js" > </ script> < script src = " https://unpkg.com/axios/dist/axios.min.js" > </ script>
</ head> < body> < div id = " app" > < div> < input v-model = " username" /> < input v-model = " password" /> </ div> < div> < button @click = " login" > Login</ button> < button @click = " logout" > Logout</ button> < button @click = " getUser" > GetUser</ button> </ div> < div> < button @click = " logs=[]" > Clear Log</ button> </ div> < ul> < li v-for = " (log, idx) in logs" :key = " idx" > {{log}}</ li> </ ul> </ div> < script> axios. defaults. withCredentials = true ; axios. interceptors. response. use ( response => { app. logs. push ( JSON . stringify ( response. data) ) ; return response; } ) ; var app = new Vue ( { el: '#app' , data: { username: "test" , password: "test" , logs: [ ] } , methods: { login: async function ( ) { await axios. post ( "http://localhost:3000/users/login" , JSON . stringify ( { username: this . username, password: this . password} ) ) } , logout: async function ( ) { await axios. post ( "http://localhost:3000/users/logout" , JSON . stringify ( { username: this . username} ) ) } , getUser: async function ( ) { await axios. get ( "http://localhost:3000/users/getUser" ) ; } } } ) ; </ script>
</ body> </ html>
axios.defaults.withCredentials = true
: 前端發出請求時,攜帶 cookieaxios.post(url,params)
時,params 一定要使用 JSON.stringify 轉換成 JSON 格式.否則會出現請求方法為 OPTION.axios.interceptors.response.use(cb)
: 對響應的信息進行攔截處理.
const Koa = require ( 'koa' )
const app = new Koa ( )
const Router = require ( 'koa-router' )
const router = new Router ( { prefix: '/users' } ) router. post ( '/login' , async ctx => { ctx. body = { ok: 1 , message: '登錄成功' }
} ) router. post ( '/logout' , async ctx => { ctx. body = { ok: 1 , message: '登出成功' }
} ) router. post ( '/getUser' , async ctx => { ctx. body = { ok: 1 , message: '獲取用戶成功' }
} ) app. use ( router. routes ( ) )
app. listen ( 3000 )
const router = new Router({ prefix: '/users' })
: 給路由添加一個前綴,即在后面 router.post(’/’,cb), 處理的是 http://localhost:3000/users 路由以上的 html 是運行在 file 協議下(vscode 下使用 alt + B 快捷打開),而服務端是 http 協議.當 html 上通過 axios.post 方法請求服務器時,會發生跨域.于是下面需要添加跨域 由于使用到了 POST 方法,因此,在服務端也添加上 bodyParser.(注: bodyParser 一定要放在 koa-router 前面加載)
const bodyParser = require ( 'koa-bodyparser' )
app. use ( bodyParser ( ) )
const cors = require ( 'koa2-cors' )
app. use ( cors ( ) )
如果您按照我的代碼一步一步的敲,那么當您敲到這里,代碼應該理所當然的不能運行.打開 google 瀏覽器,在控制臺可以看見以下的一段話 The value of the 'Access-Control-Allow-Credentials' header in the response is '' which must be 'true' when the request's credentials mode is 'include'.
:提示的很明顯,就是說需要在返回頭部加上一個 “Access-Control-Allow-Credentials”: true 字段根據 koa2 的洋蔥模型,只需在所有的路由前面加上如下代碼即可
router. post ( '*' , async ( ctx, next) => { ctx. set ( 'Access-Control-Allow-Credentials' , true ) await next ( )
} )
router. get ( '*' , async ( ctx, next) => { ctx. set ( 'Access-Control-Allow-Credentials' , true ) await next ( )
} )
如果您按照我的代碼一步一步的敲,那么當您敲到這里基本的前后端交互算是完成了,下一步需要使用 session 首先看如下代碼:
const session = require ( 'koa-session' )
app. kets = [ 'marron rain' ] const SESSION_CONFIG = { key: 'marron:session'
}
app. use ( session ( SESSION_CONFIG , app) )
router. post ( '/login' , async ctx => { ctx. session. userinfo = "marron" ; ctx. set ( "Content-Type" , "application/json" ) ; ctx. body = { ok: 1 , message: '登錄成功' , }
} )
router. post ( '/logout' , async ctx => { delete ctx. session. userinfo; ctx. body = { ok: 1 , message: '退出系統' } } ) router. get ( '/getUser' , async ctx => { ctx. body = { ok: 1 , message: '獲取用戶成功' , userinfo: ctx. session. userinfo}
} )
此時,后端可以處理 登錄、登出、以及獲取信息.(僅僅只是根據不同路由返回不同的信息,并未進行邏輯處理) 實現簡單的邏輯
在處理 getUser 路由請求時,先檢查一下session中是否有信息 使用router.post 的第二個參數, 傳入中間件. /login component/middleware/auth.js
module. exports = async ( ctx, next) => { if ( ! ctx. session. userinfo) { ctx. body = { ok: 0 , message: '用戶未登錄' } } else { await next ( ) ; }
}
將router.get('/getUser')
改寫如下:
router. get ( '/getUser' , require ( './middleware/auth' ) , async ctx => { ctx. body = { ok: 1 , message: '獲取用戶成功' , userinfo: ctx. session. userinfo}
} )
在執行回調函數之前,會先執行監測,檢查session中是否存在userinfo信息. 邏輯基本完成.但是此時的session信息只是存在內存中,并未真正實現持久化.