REST 中身份验证方式选用 Token 的理由?

2015-05-18 09:56:06 +08:00
 cyl19910101

大家好,我最近试着把之前写的特别随便的网络请求写法(自己根据操作的要求针对每个服务写个响应的做法,自己瞎折腾的,有一点像soap但是肯定没遵守那么多的规范)调整一下,因为看REST风格针对资源而不是服务的做法比较有意思,所以试着做一下。但是很遗憾的是我看了一段时间,对REST风格下大家对身份验证的设计有点理解不能,所以斗胆请大家帮解决一下疑惑。
网上写REST的文章真是不少,一个个都说大家都乱用REST,只有像“我”这样那样地做才是真REST。
http://blog.csdn.net/ugg/article/details/9026649 这个文章说得就比较斩钉截铁,用session一定不是REST。
https://cnodejs.org/topic/527c7ab2d2b3893f2aeca794 这个回答就是最近查看文章里面用token做验证的一种常见做法
还有的就说session token爱叫什么叫什么,都是换汤不换药。
看斗嘴归看,活儿还是得干,我的疑惑就在于如果说服务器保存了session就不能称之为“无状态”的话,那保存token的做法,在本质上到底跟session差了什么就可以称之为“无状态”?个人瞎猜测一下,是因为session这个设计中数据结构里面存储了一些相对token来说“更不能称之为无状态”的数据?
另外还见到一种常见的是服务器不存token,每次发过来以后按照既定的算法在服务器算出一个token,看看两个能否匹配上。这个看起来就真的是啥都没存了,但是每次请求都读盘计算,似乎听着有点浪费。
所以如果大家在身份验证中采取了其他的特别高效又低资源消耗的做法,恳请赐教,因为我没想出什么特别好的做法,也没查到什么特别好的资料。。。。。。

7672 次点击
所在节点    HTTP
23 条回复
kslr
2015-05-18 10:31:33 +08:00
json web token ~~
kslr
2015-05-18 10:32:48 +08:00
这是以前的一个讨论 /t/148426
learnshare
2015-05-18 10:36:05 +08:00
Token 在用途上和 session 类似,具体做法可以灵活一些,每次计算确实浪费。
binux
2015-05-18 10:37:14 +08:00
难道你服务器保存了 session,客户端就不用发送 cookies 了吗?
如果客户端用了 cookies,cookies 就是 token。

记住 HTTP 总共就是 method,path,header(包括 cookies) 和 payload 四元素,无论「表明请求的人是谁」放在哪,本质上都是一样的。
而无论服务器保存的状态是在内存的还是在数据库(难道你数据库就不存 APIKEY 了吗?),本质上也是一样的。

你这是过分专注概念了。用 token 根本不是以上任何一种原因。
根本原因是,有的时候不方便操作 header 啊!
loading
2015-05-18 10:42:32 +08:00
您知道 token 底层如何实现吗?
web的无状态的,cookie和session你自己好好看看!
realityone
2015-05-18 10:47:00 +08:00
算出来匹配的那个应该叫做签名
cyl19910101
2015-05-18 11:20:54 +08:00
@realityone 感谢指出,这个确实是在授权中比较多见,我只是知道有这个做法,但是是否可以考虑应用在验证上面还没找到应用实例,所以不知道合适不合适用在验证上
cyl19910101
2015-05-18 11:26:18 +08:00
@binux token肯定是要带在请求上的,我上面其实没有说不用发。。。。。我是看不出在服务器存储上用session还是用token的方式在“是否无状态”上的差异。确实是有点纠结概念,主要是因为看REST一直坚持无状态才能叫REST,然后大家应用上面还是在服务器上存储了token这样一个记录,所以没看出来两者之间的本质区别,就不知道凭什么说不记录session而记录token的方式就能满足它所说的无状态
jokester
2015-05-18 11:51:16 +08:00
1 验证对象是终端设备或服务,而不是用户本身。一个设备被盗就撤销一个TOKEN而已
2 不需要维护一个cookiejar,方便在终端做持久化,更方便在服务中使用
"无状态"是相对cookie session来讲的。一个TOKEN从颁发到收回都一个样子。
cyl19910101
2015-05-18 11:59:05 +08:00
@kslr 嗯,说实话那也是一个让我产生疑惑的讨论,当初看那个讨论的时候,大家围绕几个点说,我大概揣摩的是这样几个意见:
第一个就是您说的那个,session设计是和cookie相结合的,现在我们不用session了,所以设计个token来解决这个需求,所以其实是应景而生的类似的东西。这里面让我疑惑的就是基于这个需求设计出来的token机制,为什么就可以说自己是stateless而session却不是。
另外一个感觉比较有针对性的观点就是akfish说的那个“Session的状态是存储在服务器端,客户端只有session id;而Token的状态是存储在客户端”,这个可以说是一个很有力的理由说明token是stateless的,只需要解析token就能进行验证,服务器不需要存,这一切看起来就特别顺理成章了,直到我看到上面提到的第二个链接里面说到验证之后还是需要存到缓存(他建议用redis)中去,等到请求过来的时候进行校验,那这个样子还是一样要存这些用户信息在服务器上,并没有感觉和session的做法有根本上的差异。
所以感觉就是不明白到底token体系这一系列流程中,哪个关键点和session体系是截然不同的而导致它可以被称之为stateless。akfish给的资料相当有用,但是感觉离说服大家“token是无状态而session是有状态”还差一个关键的说明,而这个说明也是我一直找不到的,网上也有不少人像王垠说的就给一句“ RTFM”,让自己去看cookie和session,而Manual中没有作出很强力的证明,需要一些关键提点的地方,他们也不愿意给~
非常感谢您的回答,感觉咱们对token的设计意图理解有点共识,我就是还没找出它和session机制之间一个敢说自己是无状态而另一个并不是的理由,您要是知道这里面的原因还望帮帮忙
cyl19910101
2015-05-18 12:08:10 +08:00
@jokester 感谢解答,感觉这个说法有点新奇,因为我上网络课的时候介绍的无状态特性是指出两个请求之间互相独立,一个请求不会对另一个请求产生影响,有一点像这篇的表达: http://blog.csdn.net/tennysonsky/article/details/44562435
您的意思是REST里面讨论的无状态是指Token的不可变更性,而session机制里面的随请求时时更新状态(过期时间,登入登出等)就违背了这个要求是吗?
jokester
2015-05-18 12:15:22 +08:00
我的理解是这样
TOKEN本身只是个凭据,即一个用来取或换东西的东西
你玩过魔兽世界的话。。换套装那些代币就叫TOKEN

一个TOKEN怎样生成不重要,重要的是客户端用它可以换东西
而且只要不被撤销就一直不变

在里面编码东西不是必须的,服务器端完全可以生成一个UUID给你,并自己管理UUID和权限的对应关系
真的编码了东西反而不容易做到无状态

这个概念甚至不依赖HTTP,不用强行朝一起想
binux
2015-05-18 12:30:50 +08:00
@cyl19910101 无状态是说前后请求之间没有关联,而不是服务器什么都不存。什么都不存,POST,PUT 还玩个毛线啊。
realityone
2015-05-18 12:38:47 +08:00
@cyl19910101 有一种方法是在认证后把用户 id 和 expire 通过一个 secret_key 加密出来的结果作为 token,之后通信中服务端要做的就是解码 token 取对应资源并验证 expire 等等
好处就是服务端不用保存什么数据,缺点就是 token 会很长
binux
2015-05-18 12:43:57 +08:00
@cyl19910101 换种说法是,状态指的是客户端的状态(例如它之前做了什么,是否登录了),而不是 API 操作的资源。

当然了,这取决于看这个问题的角度
即使是使用 cookies+session,用户是否登录了,这个可以视为客户端的状态。
反过来也可以说,这是给这个 cookies 串(你也可以叫 token)进行了授权。
前者就是有状态的,而后者不是。

虽然它们看起来根本就是一样的(我看 HTTP 协议里面各个字段还一样呢),毕竟 HTTP 协议上能用的就那么几种。
但是实际上,由于思考的角度不一样,后端设计实际上很可能是不一样。
huijiewei
2015-05-18 13:06:02 +08:00
虽然 Session 也是通过 Cookie(通过 Http Header 传输)或者 Url 传输,但是各种 Web 语言和框架为了会给 Session 加锁,这样的话,同样的 Session 请求只能按顺序执行,会引起并发问题。

ASP.NET 肯定是这样的,PHP 的没测试过,谁有空测试下就知道了。
kslr
2015-05-18 13:12:23 +08:00
cyl19910101
2015-05-18 15:11:16 +08:00
@binux
嗯,感谢解释,确实还是以两个请求之间是否相互影响为根本判别。从两个角度看客户端登录这个说法比较有意思,玩味一下。
cyl19910101
2015-05-18 15:13:12 +08:00
@kslr 感谢感谢,新浪那篇提了一些历史上http这么设计的原因和应用中我们对这种设计结合自己的需求做出的解决方案还是比较扩充知识的,感谢!
cyl19910101
2015-05-18 15:26:23 +08:00
@realityone 见识过,130个字符一行的iterm2居然一行放不下。。。。。。但是我还没做过大的有压力测试的东西,心里面对于一个请求的耗费容忍度没太大概念,之前总是感觉字符串的东西,撑死了也大不到哪儿去。。。。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/191813

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX