使用Cookie、Session实现鉴权
- 客户端登录,发送账户、密码给服务器
- 服务器查询数据库,验证账户与密码
- 验证正确,服务器向客户端发送Cookie同时,生成Session管理Cookie信息(一般使用Redis统一全局管理Session)
- 客户端会自动接收Cookie,并在此后每次请求都会自动在请求头附带Cookie
- 服务器根据Session校验Cookie的信息,判断是否需要登录或者未授权访问
下载需要的组件
npm i koa koa-session redis koa-redis co-redis koa-static koa-bodyparser -S
app.js
// 引入Koaconst Koa = require('koa');const app = new Koa();// 引入 koa-sessionconst session = require('koa-session');// 引入redisconst redis = require('redis');const redisStore = require('koa-redis');const redisClient = redis.createClient(6379,'localhost');// 转换redisconst wrapper = require('co-redis');const client = wrapper(redisClient);// 引入静态资源储量const static = require('koa-static');app.use(static(__dirname+'/public'));// 引入解析 koa 上下文(body)const bodyParser = require('koa-bodyparser');app.use(bodyParser())// 秘钥app.keys = ['some secret'];const SESS_CONFIG = { key: 'kkkb:sess', // sessionKey maxAge: 86400000, // 有效期 httpOnly: true, // Cookie在服务器有效(客户端无法通过js获取Cookie) signed: true, // 是否签名 store: redisStore({client})}app.use(session(SESS_CONFIG,app));app.use(async (ctx, next) => { if(ctx.path === '/favicon.ico') return; // let n = await ctx.session.count || 0; // ctx.session.count = ++n; // ctx.body = '第' + n + '次访问'; //console.log(ctx.request.headers.cookie) await redisClient.keys('*', async (err,keys) => { // await console.log(keys); keys.forEach(async key => { redisClient.get(key, (err,val) => { console.log(val); }) }) }) await next();});const users = require('./routes/users');app.use(users.routes())app.listen(3000);
users.js
const Router = require('koa-router');const router = new Router({prefix: '/users'});router.post('/login', async ctx => { const { body } = ctx.request; // console.log('body',body); ctx.session.userInfo = body.username; ctx.body = { ok: 1, message: '登录成功' };});router.get('/getUser', require('../middleware/auth'), async ctx => { ctx.body = { ok: 1, message: '获取数据成功', userInfo: ctx.session.userInfo }})router.post('/logout', async ctx => { delete ctx.session.userInfo; ctx.body = { ok: 1, message: '登出系统' };});module.exports = router;
auth.js
module.exports = async (ctx, next) => { if(!ctx.session.userInfo){ ctx.body = { ok: 0, message: '用户未登录' }; } else { await next(); }}
使用token实现鉴权
- 客户端向服务器发送账户与密码
- 服务器查询数据库判断账户与密码正确性
- 服务器并向客户端发送令牌token
- 客户端收到token之后将其存储起来,放进Cookie或者LocalStorage
- 客户端每次向服务器请求资源会附带token
- 服务器验证token,验证通过则返回资源
下载相关中间件
npm i jsonwebtoken koa-jwt -S
使用jsonwebtoken加密
const jwt = require('jsonwebtoken');const jwtAuth = require('koa-jwt');const secret = 'it is a jwt secret'; // token加密秘钥router.post('/loginToken', async ctx => { const { body } = ctx.request; const userInfo = body.username; ctx.body = { message: '登录成功', user: userInfo, token: jwt.sign({ data: userInfo, exp: Math.floor(Date.now() / 1000) + 60 * 60 // 一小时后过期 }, secret) };});
客户端收到token使用LocalStorage存储
login: async function(){ const res = await axios.post('/users/loginToken', { username: this.username, password: this.password }) localStorage.setItem('token', res.data.token); }
客户端每次请求资源时将token附带在头部
axios.interceptors.request.use(config => { const token = window.localStorage.getItem('token'); if(token){ config.headers.common['Authorization'] = 'Bearer '+token; } return config; })
服务器验证token
router.get('/getUserToken', jwtAuth({secret}), async ctx => { /** * 通过jwtAuth验证之后,jwt会自动解析加密后data存入ctx.state里面 */ ctx.body = { message: '获取数据成功', userInfo: ctx.state.user.data }})