06-鉴权
码路教育 7/25/2022
# 1. Session/Cookie
掌握三种常⻅鉴权⽅式:Session/Cookie、Token+jwt、OAuth
# cookie
Http协议是⼀个⽆状态的协议,服务器不会知道到底是哪⼀台浏览器访问了它,因此需要⼀个标识⽤来让服务器区分不同的浏览器。cookie就是这个管理服务器与客户端之间状态的标识。cookie的原理是,浏览器第⼀次向服务器发送请求时,服务器在response头部设置Set-Cookie字段,浏览器收到响应就会设置cookie并存储,在下⼀次该浏览器向服务器发送请求时,就会在request头部⾃动带上Cookie字段,服务器端收到该cookie⽤以区分不同的浏览器。当然,这个cookie与某个⽤户的对应关系应该在第⼀次访问时就存在服务器端,这时就需要session了。
cookie的基本使用:
const Koa = require('koa');
const app = new Koa();
app.use(async ctx => {
// 需要在服务端种植一个cookie,种到了浏览器的时面
// 后面,每一次请求,浏览器都会带上这个cookie
// 默认情况下,会话结束,cookie就死了
// ctx.cookies.set("usrename", "wangcai");
// 活7天 设置cookie的生存时间
ctx.cookies.set("usrename", "wangcai", {
maxAge: 60000 * 60 * 24 * 7
});
// 获取浏览器带过来的cookie
console.log("获取cookie:", ctx.cookies.get("usrename"));
ctx.body = 'Hello World';
});
app.listen(3000);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
使用cookie记录一次的访问时间,代码如下:
const Koa = require('koa');
const app = new Koa();
app.use(async ctx => {
// 获取cookie 第1次获取不到,值是und
let last = ctx.cookies.get("last")
// 第1次访问服务器 需要种植一个cookie
ctx.cookies.set("last", new Date().toLocaleString(), {
maxAge: 60000 * 60 * 24 * 356
});
if (last) {
ctx.body = `你上一次访问的时间是:${last}`
} else {
// 第1次访问
ctx.body = `这是你第1次访问本网站`
}
});
app.listen(3000);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# session
session是会话的意思,浏览器第⼀次访问服务端,服务端就会创建⼀次会话,在会话中保存标识该浏览器的信息。它与cookie的区别就是session是缓存在服务端的,cookie 则是缓存在客户端,他们都由服务端⽣成,为了弥补Http协议⽆状态的缺陷。
# 基于session-cookie的身份认证
原理
- 服务器在接受客户端⾸次访问时在服务器端创建seesion,然后保存seesion(我们可以将seesion保存在内存中,也可以保存在redis中,推荐使⽤后者),然后给这个session⽣成⼀个唯⼀的标识字符串,然后在响应头中种下这个唯⼀标识字符串。
- 签名。这⼀步通过秘钥对sid进⾏签名处理,避免客户端修改sid。(⾮必需步骤)
- 浏览器中收到请求响应的时候会解析响应头,然后将sid保存在本地cookie中,浏览器在下次http请求的 请求头中会带上该域名下的cookie信息。
- 服务器在接受客户端请求时会去解析请求头cookie中的sid,然后根据这个sid去找服务器端保存的该客户端的session,然后判断该请求是否合法
安装和应⽤
- 安装:npm i koa-session@6.2.0
- 快速搭建app应⽤
# 基于session实现网站访问次数统计
代码如下:
const Koa = require('koa')
const session = require("koa-session");
const app = new Koa()
// keys作用:用来对cookie进行签名
app.keys = ['session secret', 'anthor secret']
const SESSON_CONFIG = {
key: 'wc:xq', //设置cookie的key名字
maxAge: 86400000, //有效期,默认是一天
httpOnly: true, //仅服务端修改
signed: true, //签名cookie
}
app.use(session(SESSON_CONFIG, app));
app.use(async ctx => {
// ignore favicon
if (ctx.path === '/favicon.ico') return;
let n = ctx.session.count || 0;
ctx.session.count = ++n;
ctx.body = '第' + n + '次访问';
});
app.listen(3000, () => {
console.log('3000端口被监听了~~')
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
浏览器效果如下:
# 基于session实现⽤户鉴权
实现三个接口如下:
// router/user.js
const Router = require('@koa/router');
const router = new Router();
router.prefix('/user')
// 登录接口
router.post('/login', async (ctx, next) => {
const {
body
} = ctx.request;
console.log('body', body);
ctx.session.userinfo = body.user;
ctx.body = {
ok: 1,
message: '登录成功'
}
})
// 退出登录接口
router.post('/logout', async (ctx, next) => {
console.log(ctx.session.userinfo);
if (ctx.session.userinfo) {
delete ctx.session.userinfo;
}
ctx.body = {
ok: 1,
message: '退出系统'
}
})
// 获取用户信息接口
router.get('/getUser', async (ctx, next) => {
// console.log(ctx.session.userinfo);
ctx.body = {
ok: 1,
message: '获取数据成功',
a: 666,
userinfo: ctx.session.userinfo
}
})
module.exports = router;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
入口JS配置如下:
const Koa = require('koa')
const index = require('./router/index')
const users = require('./router/user')
const bodyParser = require('koa-bodyparser')
const session = require("koa-session");
const app = new Koa()
app.use(bodyParser());
// keys作用:用来对cookie进行签名
app.keys = ['session secret', 'anthor secret']
const SESSON_CONFIG = {
key: 'wc', //设置cookie的key名字
maxAge: 86400000, //有效期,默认是一天
httpOnly: true, //仅服务端修改
signed: true, //签名cookie
}
app.use(session(SESSON_CONFIG, app));
// 注册路由
app.use(index.routes())
index.allowedMethods()
app.use(users.routes())
users.allowedMethods()
app.listen(3000, () => {
console.log('3000端口被监听了~~')
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
postman测试如下:
当访问/getUser路由的时候需要守卫中间件 在项目根目录下,创建middleware/auth.js,代码如下:
module.exports = async (ctx, next) => {
if (ctx.session.userinfo) {
await next()
} else {
ctx.body = {
code: 401,
message: '未授权',
}
}
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
获取用户信息时,添加守卫,如下:
// 获取用户信息接口
router.get('/getUser', require('../middleware/auth'), async (ctx, next) => {
// console.log(ctx.session.userinfo);
ctx.body = {
ok: 1,
message: '获取数据成功',
a: 666,
userinfo: ctx.session.userinfo
}
})
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
postman测试如下:
# 2. Token+JWT认证
安装
- npm i koa-jwt@4.0.3 说明:jwt中间件
- npm i jsonwebtoken@8.5.1 说明:⽤于⽣成token下发给浏览器, 在koa2以后的版本不再提供jsonwebtoken的⽅法, 所以需要另外安装
在user.js中配置如下:
const Router = require('@koa/router');
const jwt = require('jsonwebtoken');
const jwtAuth = require('koa-jwt')
const router = new Router();
router.prefix('/user')
const secret = 'this is a scret';
router.post('/login-token', async (ctx, next) => {
const {
body
} = ctx.request;
const userinfo = body.user;
ctx.body = {
ok: 1,
message: '登录成功',
user: userinfo,
// 使用jwt模块签名一个令牌,生成 token 返回给客户端
token: jwt.sign({
data: userinfo, //由于签名不是加密,令牌不要存放敏感数据
exp: Math.floor(Date.now() / 1000) + 60 * 60 //过期时间一分钟
}, secret)
}
})
router.get('/getUser-token', jwtAuth({ //对传入令牌进行校验
secret
}), async (ctx, next) => {
ctx.body = {
message: '获取数据成功',
userinfo: ctx.state.user.data
}
})
module.exports = router;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
入口JS如下:
const Koa = require('koa')
const index = require('./router/index')
const users = require('./router/user')
const bodyParser = require('koa-bodyparser')
const app = new Koa()
app.use(bodyParser());
// 注册路由
app.use(index.routes())
index.allowedMethods()
app.use(users.routes())
users.allowedMethods()
app.listen(3000, () => {
console.log('3000端口被监听了~~')
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17