1. 概述

http是一种无状态的协议,这就意味着每一次的数据交互,服务是没办法确定请求人身份,所以需要用到用户鉴权,保证服务接收到的每一次请求可以确定是哪一个用户发送的。

2. 鉴权方式

常见的鉴权方式有三种,session/cookietoken令牌oAuth

3. session/cookie

服务器在接受客户端首次访问时在服务器端创建session,然后保存session(session可以保存在内存中,也可以保存在redis中),对session生成一个唯一的标识字符串,在响应头中种下这个唯一标识字符串。为了安全可以通过密钥对sid进行签名处理,避免客户端修改sid。

浏览器中收到请求响应的时候会解析响应头,然后将sid保存在本地cookie中,在下次http请求的请求头中会带上这个cookie信息。

服务器在接受客户端请求时,解析请求头携带的cookie中的sid,然后根据这个sid去找服务器端保存的session断该请求是否合法。

cookie存在浏览器里,容量有限4k,一般不安全,最好进行加密处理。

session存在服务器,容量无限,是安全的并且session不能单独存在,因为他就是基于cookie的。

4. session使用

安装koa-session模块。

npm install koa-session -s;

注册session

app.keys = ['some secret', 'another secret'];
const SESS_CONFIG = {
    key: 'yd:sess',
    maxAge: 86400000,
    httpOnly: true,
    signed: true,
}
app.use(session(SESS_CONFIG, app));
app.use(ctx => {
    if (ctx.path === '/facicon.ico') {
        retrun;
    }
    let n = ctx.session.count || 0;
    ctx.session.count = ++n;
    ctx.body = `第${n}次`;
})

使用redis存储session

npm install koa-redis -s;
const redisStore = require('koa-redis');
const redis = require('redis');
const client = redis.createClient(6379, '127.0.0.1');
app.use(session({
    key: 'yd:sess',
    store: redisStore({ client })
}, app));
app.use(ctx => {
    client.keys('*', (err, keys) => {
        console.log(keys);
        client.get(key, (err, val) => {
            console.log(val);
        })
    })
})

前端登录代码

axios.defaults.withCredentials = true; // 跨域写到cookie
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('/users/login', {
                username: this.username,
                password: this.password
            })
        },
        logout: async function() {
            await axios.post('/users/logout');
        },
        getUser: async function() {
            await axios.get('/users/getUser');
        }
    }
})

登录注销接口

router.post('/login', async ctx => {
    const body = ctx.request;
    ctx.session.userinfo = body.username;
    ctx.body = {
        ok: 1,
        message: '成功'
    }
})
router.post('/logout', async ctx => {
    delete ctx.session.userinfo;
    ctx.body = {
        ok: 1,
        message: '退出'
    }
})
router.get('/getUser', async atx => {
    ctx.body = {
        ok: 1,
        message: '成功',
        userinfo: ctx.session.userinfo
    }
})

路由中间件, 判断用户是否存在

module.exports = async (ctx, next) => {
    if (!ctx.session.userinfo) {
        ctx.body = {
            ok: 0,
            message: '未登录'
        }
    } else {
        await next();
    }
}

// 应用守卫

router.get('/getUser', require(''), async ctx => {});

5. 存在风险

session是确认用户的唯一凭据,容易被劫持,如果把sid拿走,粘贴到别的网站上,服务也是无法识别的。所以最好定期更换sessionid,设置有效期

需要对cookieSession进行签名可以传入keys或者secret

6. token令牌

用户登录成功,服务器生成一个token令牌,可以通过jwt生成,然后将这个tokne返回给浏览器,浏览器取到token将其存在cookie中,再次发送请求时,服务器可以检验token是否合法,如果合法可以从token中解析用户信息,建议使用加密后的密码来做签名,确保每个人都不一样。

token的优点是服务端更加轻便可以实现很多可能,缺点也同样明显任何人拿到令牌都可以通过验证。

token的生成一般是通过base64编码的,所以不是很安全,因此不要存入敏感信息,密码之类的

7. token 演示

安装jwt生成token插件。

npm install jsonwebtoken koa-jwt -S;
const jwt = require('jsonwebtoken');
const jwtAuth = require('koa-jwt');
const secret = "it‘s a secret";

router.post('/login-token', 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 // 失效时间1小时
            },
            secret
        )
    }
})

router.get('/getUser-token', jwtAuth({
    secret
}), async ctx => {
    ctx.body = {
        message: '成功',
        userinfo: ctx.state.user.data
    }
})

jwt签名原理是HMAC SHA256,只是为了防篡改。前端并不知道服务器生成tokensecret,所以没办法准确的修改token,任何的改动都是不合法的,所以可以有效防止篡改,中间的数据部分,使用的是base64编码,所以可以被反解出来,因此不能存放敏感信息

8. oAuth开放授权

三方登入主要基于oAuth2.0oAuth协议为用户资源的授权提供了一个安全的,开放而又简单的标准,与以往的授权方式不同之处是oAuth的授权不会使第三方触及到用户的账号信息(如用户名和密码), 即第三方无需使用用户的用户名与密码就可以申请获得该用户资源的授权,因此oAuth是安全的。

流程:

  1. 选择授权方式,发送请求

  2. 接口响应02,重定向到第三方网站,传入一个callback回调地址

  3. 用户在第三方网站点击授权,接口返回302,重定向回来,url携带参数code

  4. 通过code获取token

  5. 通过token获取到需要的用户信息

9. 图形验证码

npm i trek-captcha -s
const captcha = require('trek-captcha');
const { token, buffer } = await captcha({size: 4})

token为验证码真实文案,buffer为验证码图片buffer,可以转换为base64用于前台展示。

const base64 = `data:image/png;base64,${buffer.toString('base64')}`

转载须知

如转载必须标明文章出处文章名称文章作者,格式如下:

转自:【致前端 - zhiqianduan.com】 鉴权的三种方式  "隐冬"
请输入评论...