登录/扫码,背后用到了什么功能
最近也是看到一个需求,网站接入微信扫码登录,并且扫码同时还需要关注公众号,那么就乘此时机回顾下各类登录方式
Cookie+Session
经典的登录模式
由于http的无状态特性,服务端是不知道客户端是谁的,也就无法判断每次请求的用户是否相关联,所以不知道用户是否已经是登录态
cookie作用是服务端发送给客户端的字符串,以文本方式保存,再下次请求时携带
session是服务端对接收的信息进行验证,服务端会分配一个内存区域/文件/数据库,用于缓存session对象
流程
- 首次登录
- 用户访问页面,输入密码
- 验证成功,分配sessionId
- 响应头写入cookie,告知客户端登录成功
- 二次登录
- 用户发送请求携带cookie给服务端
- 验证有效,允许访问,表示cookie中解析出来的sessionId一致
- 验证失效,重新登录
问题
- 客户端数量上升,服务端需分配更大量的空间存放sessionId,增大服务端压力
- 分布式/集群,同步登录态需要每一台机器
- sessionId存放在cookie中,有CSRF攻击风险
- 这里简述跨站脚本攻击,中间人无法拿到/解析cookie,但是能通过真实cookie向服务端发送请求,改变发送的数据,所以攻击的是改POST,而非读GET
- 如果业务走安全审计流程么,一般会给出具体的解决方案(专业审计,价格老贵了,四大审计真的业务方向啥都审)
- 验证 HTTP Referer 字段
- 在请求地址中添加 token 并验证
- 在 HTTP 头中自定义属性并验证
token
token优化了传统cookie+session的服务端压力问题,之前我最常用的则是JWT
流程
- 首次登录
- 用户访问页面,输入密码
- 验证成功,生成token
- 返回token,告知客户端登录成功
- 二次登录
- 用户发送请求携带token给服务端
- 验证有效,允许访问
- 验证失效,重新登录
特点
- 服务端无需保存,利用客户端天然的分布式优势缓存token,每次请求时校验
- 不存在cookie中
- 登录态有效期由服务端决定
JWT
格式为header.playload.signature字符串
头部指定签名算法,消息体包含数据,签名对前两部base64url+对称加密
当然不一定要强制按格式,能够产生类似功能的字符串与服务端匹配就可以称为JWT
服务端拿到字符串后执行相同对称加密动作,判断签名一致
- 问题点在于对称加密,密钥是暴露的
- 但是前端安全的本质是防止中间人通过各种方式篡改/攻击数据库,执行改权限之前是经过其他权限验证的真实用户,不能防止黑客作为真实用户去进行请求
- 所以JWT也是有价值的,当然更大的价值在于减轻服务端压力
SSO单点登录
品牌内部的公共认证中心,所有产品一次登录,其他产品无需登录,常见比如腾讯的子域名游戏、综艺等
流程
- 首次登录
- 用户访问页面A,跳转到renz认证中心统一登录页B,并url带上redirect地址,发送请求并验证
- 输入密码,认证中心验证成功,创建全局会话&ticket
- 带上统一登录的登录态cookie,重定向跳转回页面A,此时url上含有ticket
- 页面A请求,认证中心验证ticket有效,带上页面A的登录态cookie
- 登录成功,客户端有2个cookie
- 二次登录页面A
- 验证ticket,cookie已存在,令牌有效,登录成功
- 二次登录页面B
- 通过认证中心统一登录页B,验证认证中心登录态
- 验证通过,带上ticket重定向回B
- 退出
- 在验证ticket时,请求为退出的api接口即可
- 清除c的登录态cookie
- 清除认证中心的cookie,执行退出方法
- 遍历下发过ticket的产品,执行的退出方法
Oauth
比如微信、qq、微博,授权机制,客户端携带令牌可以访问所有者的资源
- 接入的第三方应用获取appid,appsecret
- 用户进入时,跳转平台Oauth授权,平台发送请求用户确认
- 确认后重新进入第三方站点,并带上临时code
- 第三方应用根据code、id、secret向平台申请token
- 第三方应用拿到用户信息,保存登录态
Oauth2.0
获取token的过程,4种授权方式,都需要第三方有appid和appsecret,需要分发token和refresh
- 授权码,最复杂,安全高,如微信
- 隐藏式,客户端直接获取token
- 密码式,第三方拿用户账密登录平台,危险风险大
- 凭证式,客户端分配了id,secret标识身份
token放header中
令牌过期处理
token是有时效的,重新授权的流程体验不好,更优雅得处理过期问题
一个令牌请求API,一个令牌请求refresh_token,当一个失效时,下一次请求更新token,即可优化前端流程
扫码登录及关注
简述一下思路,扫码后&关注默认为已授权
- 嵌入网页的平台二维码展示,客户端存jwt用于验证
- 服务端生成微信临时带参二维码,每三分钟更新
- 客户端每隔3秒请求一次API获取最新状态,5次后每隔5秒,再往后时间间隔变长,优化请求,这里也可以用socket更简洁(简述三点接口性能,有空写一篇关于socket的)
- 大量链接的创建和关闭
- 长时间保持大量连接
- 大量推送消息
- 用户扫码后关注/直接进入公众号,服务端根据临时二维码区分渠道,得到授权状态,更新API、token、数据库
- 客户端切换页面内容A,刷新页面从缓存中取token值,验证成功后直接进入页面A,不再重新扫码
- 授权/关注流程结束,需求实现