分布式系统 和 服务器集群中是如何进行用户鉴权的?
答:使用token的非对称加密。
为什么需要登录凭证?
web开发中,绝大数都是基于 http请求。而http请求是一个无状态的协议。服务器无法知道客户端的操作。
Cookie
cookie的特性
浏览器会在特定的情况下携带上cookie来发送请求,我们可以通过cookie来获取一些信息;
Cookie总是保存在客户端中,按在客户端中的存储位置,Cookie可以分为内存Cookie和硬盘Cookie。
-
内存Cookie由浏览器维护,保存在内存中,浏览器关闭时Cookie就会消失,其存在时间是短暂的;
-
盘Cookie保存在硬盘中,有一个过期时间,用户手动清理或者过期时间到时,才会被清理;
cookie的存储位置
-
没有设置过期时间,默认情况下cookie是内存cookie,在关闭浏览器时会自动删除;
-
有设置过期时间,并且过期时间不为0或者负数的cookie,是硬盘cookie,需要手动或者到期时,才会删除;
cookie的生命周期
默认情况下的cookie是内存cookie,也称之为会话cookie,也就是在浏览器关闭时会自动被删除;
我们可以通过设置expires或者max-age来设置过期的时间;
➢ expires:设置的是Date.toUTCString(),设置格式是;expires=date-in-GMTString-format;
➢ max-age:设置过期的秒钟,;max-age=max-age-in-seconds (例如一年为606024*365);
cookie的作用域
(允许cookie发送给哪些URL)
Domain:指定哪些主机可以接受cookie
➢ 如果不指定,那么默认是 origin,不包括子域名。
➢ 如果指定Domain,则包含子域名。例如,如果设置 Domain=mozilla.org,则 Cookie 也包含在子域名中(如developer.mozilla.org)。
Path:指定主机下哪些路径可以接受cookie
➢ 例如,设置 Path=/docs,则以下地址都会匹配:
/docs
/docs/Web/
/docs/Web/HTTP
sessionId
一句话,对cookie进行加密处理。
const session = koaSession({
key: 'sessionid',
signed: true,
maxAge: 60 * 1000 * 5,
// httpOnly: true
}, app)
// 加盐操作
app.keys = ['aaa', 'bbb', 'why', 'kobe']
token
与cookie和session的对比
Cookie会被附加在每个HTTP请求中,所以无形中增加了流量(事实上某些请求是不需要的);
Cookie是明文传递的,所以存在安全性的问题;
Cookie的大小限制是4KB,对于复杂的需求来说是不够的;
对于浏览器外的其他客户端(比如iOS、Android),必须手动的设置cookie和session; 对于分布式系统和服务器集群中如何可以保证其他系统也可以正确的解析session?
1、移动端 需要手动设置 cookie 和 session
2、分布式系统 和 集群中。
如果每个系统都保存一份解析的key,那么鉴权将失去作用
jwt实现token
header + playload + signture
◼ JWT生成的Token由三部分组成:
◼ header
alg:采用的加密算法,默认是 HMAC SHA256(HS256),采用同一个密钥进行加密和解密;
typ:JWT,固定值,通常都写成JWT即可;
会通过base64Url算法进行编码;
◼ payload
携带的数据,比如我们可以将用户的id和name放到payload中;
默认也会携带iat(issued at),令牌的签发时间;
我们也可以设置过期时间:exp(expiration time);
会通过base64Url算法进行编码
◼ signature
设置一个secretKey,通过将前两个的结果合并后进行HMACSHA256的算法;
HMACSHA256(base64Url(header)+.+base64Url(payload), secretKey);
但是如果secretKey暴露是一件非常危险的事情,因为之后就可以模拟颁发token,也可以解密token;
非对称加载 rs256
以使用openssl来生成一对私钥和公钥:
-
Mac直接使用terminal终端即可;
-
Windows默认的cmd终端是不能直接使用的,建议直接使用git bash终端;
openssl
genrsa -out private.key 1024
rsa -in private.key -pubout -out public.key
私钥
公钥
可以通过fs读取出来
const privateKey = fs.readFileSync('./keys/private.key')
const publicKey = fs.readFileSync('./keys/public.key')
// 1.颁发token
const payload = { id: 111, name: 'why' }
const token = jwt.sign(payload, privateKey, {
expiresIn: 60,
algorithm: 'RS256'
})
验证token
// 1.获取客户端携带过来的token
const authorization = ctx.headers.authorization
const token = authorization.replace('Bearer ', '')
console.log(token)
// 2.验证token
const result = jwt.verify(token, publicKey, {
algorithms: ['RS256']
})