应用鉴权

应用鉴权就是当一个用户进入APP时,我们需要判断他所拥有的权利,根据权力来判断他所能进行的一个行为,最为常见的就是购物网站的登录以及购物支付等操作。


一.鉴权的需求背景

Http的请求是无状态的,就是说在一个Http请求中的请求方和响应方都是无法维护状态,是一次性的,所以我们就不知道请求前后都发生了什么。所以我们需要标记的功能,而浏览器的sessionStorage,localStorage,全局变量等限制太多,就有了cookie,session,token等鉴权的操作。

二.cookie

cookie也是一种前端存储的方式,但是他和sessionStorage,localStorage等本地存储的不同在于,浏览器向服务端发起请求的时候,cooike是自动传过去的,可以做到前端无感知,出错的概率更低
过程:
1.浏览器向服务器发起请求并传送数据,由服务器接收数据然后设置cooike放进响应头(Set-Cookie),浏览器接收到响应之后就会自动存储进cookie
2.在之后的每一次请求中浏览器都会自动的在请求头之中设置cookie字段,发送给服务端
配置:
1.Domain/Path
cookie 是要限制空间范围的,通过 Domain(域)/ Path(路径)两级。

Domain属性指定浏览器发出 HTTP 请求时,哪些域名要附带这个 Cookie。如果没有指定该属性,浏览器会默认将其设为当前 URL 的一级域名,比如 www.example.com 会设为 example.com,而且以后如果访问example.com的任何子域名,HTTP 请求也会带上这个 Cookie。如果服务器在Set-Cookie字段指定的域名,不属于当前域名,浏览器会拒绝这个 Cookie。
Path属性指定浏览器发出 HTTP 请求时,哪些路径要附带这个 Cookie。只要浏览器发现,Path属性是 HTTP 请求路径的开头一部分,就会在头信息里面带上这个 Cookie。比如,PATH属性是/,那么请求/docs路径也会包含该 Cookie。当然,前提是域名必须一致。

2.Expires / Max-Age
cookie 还可以限制时间范围,通过 Expires、Max-Age 中的一种。

Expires属性指定一个具体的到期时间,到了指定时间以后,浏览器就不再保留这个 Cookie。它的值是 UTC 格式。如果不设置该属性,或者设为null,Cookie 只在当前会话(session)有效,浏览器窗口一旦关闭,当前 Session 结束,该 Cookie 就会被删除。另外,浏览器根据本地时间,决定 Cookie 是否过期,由于本地时间是不精确的,所以没有办法保证 Cookie 一定会在服务器指定的时间过期。
Max-Age属性指定从现在开始 Cookie 存在的秒数,比如60 * 60 * 24 * 365(即一年)。过了这个时间以后,浏览器就不再保留这个 Cookie。
如果同时指定了Expires和Max-Age,那么Max-Age的值将优先生效。
如果Set-Cookie字段没有指定Expires或Max-Age属性,那么这个 Cookie 就是 Session Cookie,即它只在本次对话存在,一旦用户关闭浏览器,浏览器就不会再保留这个 Cookie。

3.Secure / HttpOnly
cookie 可以限制使用方式。

Secure属性指定浏览器只有在加密协议 HTTPS 下,才能将这个 Cookie 发送到服务器。另一方面,如果当前协议是 HTTP,浏览器会自动忽略服务器发来的Secure属性。该属性只是一个开关,不需要指定值。如果通信是 HTTPS 协议,该开关自动打开。
HttpOnly属性指定该 Cookie 无法通过 JavaScript 脚本拿到,主要是Document.cookie属性、XMLHttpRequest对象和 Request API 都拿不到该属性。这样就防止了该 Cookie 被脚本读到,只有浏览器发出 HTTP 请求时,才会带上该 Cookie。

Http头对cookie的读写:
响应会携带一个Set-Cookie头,一个Set-Cookie只能设置一条cookie,格式为cookie键值+配置键值,如果想要一次设置多个cookie,我们可以多写几个Set-Cookie在头里面。

Set-Cookie: username=jimu; domain=jimu.com; path=/blog; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Secure; HttpOnly

而当浏览器请求服务器的时候,就不再需要发送配置内容了,只需要发送键值对就可以

Cookie: username=jimu; height=180; weight=80

前端对cookie的读写操作:
如果服务端设置的cookie并没有设置httpOnly,那么我们就可以调用document.cookie来对cookie进行读写操作,但一次调用document.cookie就只能操作一个cookie

三.session

在上面我们介绍了cookie,可以了解到cookie其实是浏览器存储的一种实现,可以看作应用鉴权的基石。但是它只是一个存储信息的工具,我们还需要判断其中的信息是不是安全的操作者,这时候我们就需要session了。
典型的session登录流程:

session登录

1.浏览器登录发送账号密码,服务端查用户库,校验用户
2.服务端把用户登录状态存为 Session,生成一个 sessionId
3.通过登录接口返回,把 sessionId set 到 cookie 上
此后浏览器再请求业务接口,sessionId 随 cookie 带上
4.服务端查 sessionId 校验 session
5.成功后正常做业务处理,返回结果

session的存储与过期销毁:
由于session是用来验证的,所以服务端仅仅只是给浏览器的cookie中添加一个sessionid,所以也需要自己保存一下,存储的方式:

1.Redis(推荐):内存型数据库,redis中文官方网站。以 key-value 的形式存,正合 sessionId-sessionData 的场景;且访问快。
2.内存:直接放到变量里。一旦服务重启就没了
3.数据库:普通数据库。性能不高。

而session也可以手动设置过期时间,一到过期时间就直接清空存储的内存就好了

session的分布式问题:
由于服务端是集群,而用户请求过来会走一次负载均衡,不一定会打到哪台机器上。一旦用户后续接口请求到的机器和他登录请求的机器不一样,或者登录请求的机器出问题了,那session就会失效。
常见的解决方式:

1.把session集中存储到独立的redis或者普通数据库中,就可以把session存储到一个库里(存储角度
2.让相同 IP 的请求在负载均衡时都打到同一台机器上。以 nginx 为例,可以配置 ip_hash 来实现。(分布角度

四.token

token

1.用户登录,服务端校验账号密码,获得用户信息
2.把用户信息、token 配置编码成 token,通过 cookie set 到浏览器
3.此后用户请求业务接口,通过 cookie 携带 token
4.接口校验 token 有效性,进行正常业务接口处理

目前主流的token存储还是在cookie中进行,但是为了防止伪造token造成的安全问题,我们还需要一些加密算法来生成签名,来保证数据安全性

token签名

JWT
由于以上的方法增加了cookie的数量,所以JSON web Token得以被使用。

JWT

refresh token
token,作为权限守护者,最重要的就是「安全」。

业务接口用来鉴权的 token,我们称之为 access token。越是权限敏感的业务,我们越希望 access token 有效期足够短,以避免被盗用。但过短的有效期会造成 access token 经常过期,过期后怎么办呢?

一种办法是,让用户重新登录获取新 token,显然不够友好,要知道有的 access token 过期时间可能只有几分钟。

另外一种办法是,再来一个 token,一个专门生成 access token 的 token,我们称为 refresh token。

1.access token 用来访问业务接口,由于有效期足够短,盗用风险小,也可以使请求方式更宽松灵活
2.refresh token 用来获取 access token,有效期可以长一些,通过独立服务和严格的请求方式增加安全性;由于不常验证,也可以如前面的 session 一样处理

refresh token

如果refresh token过期了,就只能重新登陆了。

五.session与token对比

客户端存cookie与存放于其他地方
1.出了浏览器环境之外就没有cookie了;
2.cookie是浏览器在域下自动携带的。很容易引发CSFR攻击
存放在别的地方可以解决部分问题
服务端存储数据于不存
1.存数据的话可以缩短认证字符串的长度,减小请求体积
2.不存数据就不会出现分布式处理的问题,降低硬件成本,避免查库带来的验证延迟

六.单点登录

前面我们已经知道了,在同域下的客户端/服务端认证系统中,通过客户端携带凭证,维持一段时间内的登录状态。

但当我们业务线越来越多,就会有更多业务系统分散到不同域名下,就需要「一次登录,全线通用」的能力,叫做「单点登录」。

主域名相同的情况下,就可以直接把cookie设置为主域名就可以实现了。

如果主域名不同,我们就需要独立的认证服务,称为SSO。

1.用户进入 A 系统,没有登录凭证(ticket),A 系统给他跳到 SSO
2.SSO 没登录过,也就没有 sso 系统下没有凭证(注意这个和前面 A ticket 是两回事),输入账号密码登录
3.SSO 账号密码验证成功,通过接口返回做两件事:一是种下 sso 系统下凭证(记录用户在 SSO 登录状态);二是下发一个 ticket
4.客户端拿到 ticket,保存起来,带着请求系统 A 接口
5.系统 A 校验 ticket,成功后正常处理业务请求
6.此时用户第一次进入系统 B,没有登录凭证(ticket),B 系统给他跳到 SSO
7.SSO 登录过,系统下有凭证,不用再次登录,只需要下发 ticket
8.客户端拿到 ticket,保存起来,带着请求系统 B 接口

如果是在浏览器之下实现,我们需要考虑其他的东西


对浏览器来说,SSO 域下返回的数据要怎么存,才能在访问 A 的时候带上?浏览器对跨域有严格限制,cookie、localStorage 等方式都是有域限制的。

这就需要也只能由 A 提供 A 域下存储凭证的能力。一般我们是这么做的:



图中我们通过颜色把浏览器当前所处的域名标记出来。注意图中灰底文字说明部分的变化。

1.在 SSO 域下,SSO 不是通过接口把 ticket 直接返回,而是通过一个带 code 的 URL 重定向到系统 A 的接口上,这个接口通常在 A 向 SSO 注册时约定
2.浏览器被重定向到 A 域下,带着 code 访问了 A 的 callback 接口,callback 接口通过 code 换取 ticket
3.这个 code 不同于 ticket,code 是一次性的,暴露在 URL 中,只为了传一下换 ticket,换完就失效
4.callback 接口拿到 ticket 后,在自己的域下 set cookie 成功
5.在后续请求中,只需要把 cookie 中的 ticket 解析出来,去 SSO 验证就好
6.访问 B 系统也是一样

七.总结

1.HTTP 是无状态的,为了维持前后请求,需要前端存储标记
2.cookie 是一种完善的标记方式,通过 HTTP 头或 js 操作,有对应的安全策略,是大多数状态管理方案的基石
3.session 是一种状态管理方案,前端通过 cookie 存储 id,后端存储数据,但后端要处理分布式问题
4.token 是另一种状态管理方案,相比于 session 不需要后端存储,数据全部存在前端,解放后端,释放灵活性
5.token 的编码技术,通常基于 base64,或增加加密算法防篡改,jwt 是一种成熟的编码方案
6.在复杂系统中,token 可通过 service token、refresh token 的分权,同时满足安全性和用户体验
7.session 和 token 的对比就是「用不用cookie」和「后端存不存」的对比
8.单点登录要求不同域下的系统「一次登录,全线通用」,通常由独立的 SSO 系统记录登录状态、下发 ticket,各业务系统配合存储和认证 ticket


阅读知乎文章:鉴权必须了解的5个兄弟:cookie、session、token、jwt、单点登录 - 知乎 (zhihu.com)

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容