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信息只是存在内存中,并未真正实现持久化.