服务端鉴权之Session/Cookie

Cookie

cookie原理
服务端在Header Set-Cookie,然后客户端会自动存取下来(cookie中可以看到)
下次请求,请求头会携带cookie传给后端

const http = require('http')
http
    .createServer((req,res)=>{
        if(req.url === '/favicon.ico'){
            res.end('')
            return
        }
        //观察cookie存在
        console.log('cookie:',req.headers.cookie)
        //设置cookie
        res.setHeader('Set-Cookie','cookie1=aaa')
        res.end('hello cookie')
    })
    .listen(3000)

存储在客户端
在这里插入图片描述
传送到服务端
在这里插入图片描述

cookie缺点

  1. 不安全,能在客户端看到(明文),可能被篡改(document.cookie = …)
  2. 容量限制,只能存很小的数据
  3. 不能存实例

因为有上面的缺点,不适合做鉴权,需要用session来配合

Session

session原理
浏览器首次访问,生成uid保存在服务端session中,且将uid存储于cookie
下次访问,根据uid对请求进行认证

const http = require('http')
const session = {}
http
    .createServer((req,res)=>{
        //观察cookie是否存在
        console.log('cookie',req.headers.cookie)
        //存储一对键值对
        const sessionKey = 'uid'
        const cookie = req.headers.cookie
        if(cookie&&cookie.indexOf(sessionKey)!=-1){
            //下次访问
            res.end('Come Back')
            //使用正则解析是否存在之前的cookie
            const pattern = new RegExp(`${sessionKey}=([^;]+);?\s*`)
            const uid = pattern.exec(cookie)[1]
            console.log('session',uid,session,session[uid])
        }else{
            //第一次访问
            //设置键值对的值,用你需要的规则,这儿用随机数代替
            const uid = (Math.random()*9999999999).toFixed()
            res.setHeader('Set-Cookie',`${sessionKey}=${uid};`)
            //真正的数据
            session[uid] = {name:'admin'}
            res.end('hello admin')
        }
        res.end('hello session') 
    })
    .listen(3000)

在这里插入图片描述
在这里插入图片描述

session优点

  1. 浏览器只存了一个编号或加密串,很难推定
  2. 真正的数据,存储于服务端,安全可存实例又无容量限制,可进行鉴权

Koa中实现Session

通过koa-session中间件来实现

const koa = require('koa')
const app = new koa()
const session = require('koa-session')
//签名key keys作用 用来对cookie进行签名
app.keys = ['some secret']
//配置项
const SESS_CONFIG = {
    key: "sess", //cookie链名
    maxAge: 86400000, // 有效期,默认一天
    httpOnly: true, // 只能用于http传输,仅服务器修改,提高安全性
    signed: true // 签名cookie,如秘钥
}
//注册
app.use(session(SESS_CONFIG, app))
//测试
app.use(ctx => {
    if(ctx.path === '/favicon.ico') return
    //获取
    let n = ctx.session.count || 0
    //设置
    ctx.session.count = ++n
    ctx.body = '第'+n+'次访问'
})
app.listen(3000)

在这里插入图片描述

上面的session存储于变量(内存)中,可能会遇到下面的一些问题

  1. 内存容量不足
  2. 无法满足横向扩展(node配置于多台服务器,无法保证下次进来还是上一台服务器)

所以通常情况下需要将session进行全局存储,一般将其存在redis中

redis存储session

redis介绍
一个高性能的key-value数据库
redis缓存产品的三个特点

  • 支持数据持久化,可以将内存中的数据保存在磁盘中,重启的适合可以再次加载进行使用
  • 不仅支持简单的key-value类型的数据,同时还提供list、set、zset、hash等数据结构的存储
  • 支持数据的备份,即master-slave模式的数据备份
    redis优势
  • 性能极高,由C语言编写,能读的速度是110000次/s,写的速度是81000次/s
  • 丰富的数据类型,支持二进制案例的Strings、Lists、Hashes、Sets及Ordered Sets数据类型操作
  • 所有操作都是原子性的,即要么成功执行要么失败完全不执行。单个操作是原子性的,多个操作也支持事务,通过MULTI和EXEC指令包起来
  • 丰富的特性,支持publish/subscribe,通知,key过期等特性
    redis使用
    1、github下载
    2、解压改名为redis
    3、reids-server启动
    redis测试
const redis = require('redis')
//连接redis
const client = redis.createClient(6379,'localhost')
//使用事件发射器,检测错误
client.on("error", function (err) {
    console.log("Error " + err);
});
//设置
client.set('key','value')
//拿取
client.get('key',(err,v)=>{
    if(err) throw err;
    console.log('redis get ', v)
})

如果报下面的错误,则表示reids-server未启动
Error Error: Redis connection to localhost:6379 failed - connect ECONNREFUSED 127.0.0.1:6379

koa-redis使用
安装
npm i -S koa-redis

const koa = require('koa')
const app = new koa()
const session = require('koa-session')
const redisStore = require('koa-redis')
const redis = require('redis')
const redisClient = redis.createClient(6379,'localhost')
const wrapper = require('co-redis')
const client = wrapper(redisClient)
//签名key keys作用 用来对cookie进行签名
app.keys = ['some secret']
//配置项
const SESS_CONFIG = {
    key: "sess", //cookie链名
    maxAge: 86400000, // 有效期,默认一天
    httpOnly: true, // 仅服务器修改
    signed: true, // 签名cookie
    store: redisStore({client}) // 指定存储则会按照你要求的去存储,否则会默认存储到内存中
}
//注册
app.use(session(SESS_CONFIG, app))
app.use(async (ctx,next) => {
    const keys = await client.keys('*')
    keys.forEach(async key => console.log(await client.get(key)))
    await next()
})
//测试
app.use(ctx => {
    if(ctx.path === '/favicon.ico') return
    //获取
    let n = ctx.session.count || 0
    //设置
    ctx.session.count = ++n
    ctx.body = '第'+n+'次访问'
})
app.listen(3000)

在这里插入图片描述

session/cookie鉴权的缺点

1、服务端有状态,需要去进行相关存储,若服务器断了,就会刷新内存,重连之后下次请求就会出现问题
2、基于cookie传送,cookie是基于浏览器的,不够灵活。如APP、跨域等其他情况会受限

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值