前言
本文记录了用户登录的鉴权方式,以及相关知识点的记录。
一、鉴权
- 鉴权:对用户访问系统进行权限控制
1. 什么是认证?
- 验证当前用户的身份
- 互联网常用认证:
1.用户名密码登录
2.邮箱发送登录链接
3.手机号接收验证码2. 什么是授权?
- 用户授予第三方应用访问该用户某些资源的权限
- 实现授权的方式:cookie、session、token、OAuth
3. 什么是凭证?
- 实现认证的授权的媒介
二、 Cookie与session
- cookie和session是来实现状态的记录,都是由服务器生成,用来存储特定的值。
- 一般情况下,在服务器端,session的存储方式:文件方式、数据库方式,用 sessionId 来识别。
- 客户端(浏览器)在发送请求的时候,会自动将存活、可用的cookie封装在请求头(headers)中和请求一起发送。
1.HTTP无状态
- HTTP 协议是无状态的,无状态意味着,服务器无法给不同的客户端响应不同的信息。这样一些交互业务就无法支撑。
2.cookie的重要属性
属性 | 说明 |
---|---|
name = value | 键值对,设置cookie的名称,字符串类型 |
domain | 指定cookie所属域名 |
path | 指定cookie在哪个路由下生效,默认’/’ |
maxAge | cookie失效时间,单位秒。整数:cookie在maxAge秒后失效;负数:关闭浏览器即失效,浏览器不保存该cookie;0:删除cookie;默认-1 |
expires | 过期时间 |
secure | cookie是否被使用安全协议(HTTPS,SSL)传输。 |
httpOnly | 一定程度上防止XSS攻击 |
3.cookie 和 session 的生命周期
3.1 cookie 生命周期影响因素
- cookie自身的存活时间:是服务器生成cookie时去设定的。
- 客户端是否保留cookie。对客户端自身有影响,对其它封包工具无影响。
3.2 session 生命周期影响因素
- 服务器对于session对象保存的最大时间设置。
- 客户端进程是否关闭。对客户端自身有影响,对其它封包工具无影响。
4.cookie 和 session 的区别
- 存储位置:cookie 是存在客户端,session是存在服务端。
- 安全性:session 比 cookie 更安全。
- 存储内容:Session中存储的是对象,而Cookie中存储的是字符串。
- 保持时间:Session随会话结束而关闭,而Cookie可以长期保存在客户端,除非被设置过期或者被删除。
- 对服务器压力:每个用户都会产生一个session,如果并发访问的用户过多,就会产生非常多的session,耗费大量的内存。
为什么session 比 cookie 更安全?
- cookie 是存储在客户端的,可见、可改变。
- session 存储在服务器端,不可见,不可改变。
5.工作原理
1、用户向服务器发送用户名和密码。
2、服务器验证通过后,在当前对话(session)里面保存相关数据,比如用户角色、登录时间等等。
3、服务器向用户返回一个 session_id,写入用户的 Cookie。
4、用户随后的每一次请求,都会通过 Cookie,将 session_id 传回服务器。
5、服务器收到 session_id,找到前期保存的数据,由此得知用户的身份。
3 用户登录Node.js和Express验证session
- express 引入会自动生成加密的 sessionId, 然后校验session
const express = require("express");
const session = requrie("express-session");
const MongoStore = require("connect-mongo")
const app = express();
//注册session
app.use(
session({
secret:"this is session",//服务器生成session
resave:true,
saveUninitialized:true,//强制将初始化的session 存储
cookie:{
maxAge:100 * 60 * 10, //过期时间
secure:false, //为true的时候只有 https 协议才能访问cookie
},
rolling:true, //true:超时前刷新,cookie会重新计时
//false:超时前刷新多次,按第一次刷新计时
store:MongoStore.create({
mongoUrl:'mongodb://127.0.0.1:27017/vv_session',
ttl: 1000 * 60 * 10, //过期时间
}),
})
);
//设置session
app.use((req,res,next)=>{
if(req.url === "/login"){
next()
return;
}
if(req.session.user){
req.session.garbage = Date();
next();
}else{
res.redirect("/login")
}
})
//注销session
三、JSON Web Token
1. JWT 介绍
- JSON Web Token(JWT),又称为JSON令牌,是一种用于在网络应用之间安全地传输信息的开放标准(RFC 7519)。它将用户信息加密到token里,服务器不保存任何用户信息;服务器通过使用保密的密钥验证token的正确性,正确 放行。(目前最流行的跨域认证解决方案)
2. JWT 组成部分
- Header (头部):是一个 JSON 对象,通常由 token 类型和签名算法名两部分组成。
{ "alg": "HS256", //示签名的算法(algorithm) "typ": "JWT" //表示这个令牌(token)的类型(type) }
- Payload(载荷):也是一个 JSON 对象,用来存放实际需要传递的数据,通常会被base64url编码
JWT 规定了7个官方字段
- iss (issuer):签发人
- exp (expiration time):过期时间
- sub (subject):主题
- aud (audience):受众
- nbf (Not Before):生效时间
- iat (Issued At):签发时间
- jti (JWT ID):编号
- Signature(签名):将Header和Payload部分组合起来,防止数据篡改。
3.JWT 的原理
- JWT认证流程
- 用户输入用户名/密码登录,服务端认证成功,返回给客户端一个JWT
- 客户端将 token 保存到本地
- 当用户访问一个受保护的路由或者资源的时候,需要请求头的Authorization字段中使用 Bearer 模式添加JWT
- 服务端的保护路由将会检查请求头Authorization中的JWT信息,合法,允许用户的行为。
为什么要使用JWT?
- 相比XML格式,JSON更加简洁,编码之后更小,使JWT更加适合在HTML和HTTP环境中传递。
- 因为JWT是自包含的(内部包含一些会话信息),减少了查询数据库的需要
- JWT 不使用cookie,在使用域名提供的API服务不需要担心跨域资源共享问题。
- JWT 是一种无状态的认证机制,用户状态不再存储在服务器的内存中。
安全性更好
4.用户登录Node.js和Express验证JWT
const express = require('express');
const jwt = require('jsonwebtoken');
const app = express();
const secretKey = 'your-secret-key';
// 中间件:验证JWT
const verifyToken = (req, res, next) => {
const token = req.headers.authorization;
if (!token) {
return res.status(401).json({ message: '无法验证身份' });
}
jwt.verify(token, secretKey, (err, decoded) => {
if (err) {
return res.status(401).json({ message: '身份验证失败' });
}
req.user = decoded;
next();
});
};
// 路由:受保护的资源
app.get('/protected', verifyToken, (req, res) => {
res.json({ message: '欢迎访问受保护的资源', user: req.user });
});
// 路由:生成JWT
app.post('/login', (req, res) => {
const user = { id: 1, username: 'user123' };
const token = jwt.sign(user, secretKey, { expiresIn: '1h' });
res.json({ token });
});
app.listen(3000, () => {
console.log('服务器运行在端口 3000');
});
四、补充token
什么是 token(令牌)?
Accesss Token
- 访问资源接口(API)时所需的资源凭证
token组成
- uid:用户唯一的身份标识
- time:当前时间的时间戳
- sign:签名
- token 的验证流程
- 客户端使用用户名、密码请求登录
- 服务端收到请求,验证用户名、密码
- 验证成功,服务端签发一个 token 并发送给客户端
- 客户端收到 token,将其存储在 cookie或者localStorage 中
- 客户端每次向服务端请求资源,带着服务签发的 token
- 服务端收到请求,验证客户端请求里的 token,成功,返回请求数据给客户端。
Refresh Token
- refresh token 是专用于刷新 accesss token的token,解决了每次刷新都需要用户输入用户名、密码的问题