开放平台这个话题其实很大,涉及到多方面,比如平台搭建、安全、流量控制与计费、服务端性能优化等;这次QCon会议中,人人网介绍了开放平台授权与验证,飞信介绍了资源分配与控制策略,淘宝介绍了Web请求异步化处理,腾讯介绍了Open API的设计;下面是我之后的一些总结;
还是拿网上最流行的例子吧,网站A提供图片存储服务,网站B提供在线打印服务;现在用户想使用网站B提供的在线打印功能打印存储在网站A上的图片,怎么办呢?通常有两种做法:
两种做法对比一下,显然是第二种用户体验更好,但有更多的问题需要解决:
直接进入主题吧,关于安全性,即授权与验证,经历了三个阶段:
HTTP基本认证是一种用来允许Web浏览器,或其他客户端程序在请求时提供以用户名和口令形式的凭证,详细介绍可以看维基百科上的介绍;
其大致流程是:
比如在浏览器中访问链接:http://api.minicloud.com.cn/statuses/friends_timeline.xml
1 |
HTTP/ 1.1 401 Unauthorized |
2 |
Server: nginx/ 1.0 . 4 |
3 |
Date: Wed, 02 Nov 2011 02 : 26 : 23 GMT |
4 |
Content-Type: application/xml; charset=UTF- 8 |
5 |
Transfer-Encoding: chunked |
6 |
Connection: keep-alive |
7 |
WWW-Authenticate: Basic |
8 |
Vary: Accept-Charset, Accept-Encoding, Accept-Language, Accept |
9 |
Accept-Ranges: bytes |
1 |
GET /statuses/friends_timeline.xml HTTP/ 1.1 |
2 |
Host: api.minicloud.com.cn |
3 |
User-Agent: Mozilla/ 5.0 (Windows NT 5.1 ; rv: 5.0 . 1 ) Gecko/ 20100101 Firefox/ 5.0 . 1 |
4 |
Accept: text/html,application/xhtml+xml,application/xml;q= 0.9 ,*/*;q= 0.8 |
5 |
Accept-Language: zh-cn,zh;q= 0.5 |
6 |
Accept-Encoding: gzip, deflate |
7 |
Accept-Charset: GB2312,utf- 8 ;q= 0.7 ,*;q= 0.7 |
8 |
Connection: keep-alive |
9 |
Authorization: Basic emh1eW9uZzpoZWxsbw== |
HTTP BASIC虽然简单,但要求用户输入用户名和口令始终不安全,而且Base64加密很容易破解;另外加密后的串没有有效的失效机制,除非用户关闭客户端,但不排除有些客户端会把加密后的用户名和口令保存下来供下次使用,虽然很多都声称;
OAuth就是为了解决HTTP BASIC认证中的问题而来的,当你在豆瓣上想访问新浪微博的时候,不再需要在豆瓣中输入你的微博帐号和密码了,保证了信息的安全;
使用过Twitter的应该知道,Twitter API是多少的重要;下面这个图是新建一个Application时几个重要的数据,这些数据都和OAuth有关:
在认证和授权的过程中涉及的三方包括:
上图中几个字段的含义如下:
整个OAuth 1.x授权与认证的过程如下:
如上面的Twitter即注册一个即可;此时会得到Consumer key以及Consumer secret;
可以看到,整个过程中,客户端不会涉及到用户的帐号信息;
下面是我在豆瓣电影设置新浪微博同步时的一些数据
请求头如下:
1 |
GET /partner/sina/connect HTTP/ 1.1 |
2 |
Host: movie.douban.com |
3 |
... |
其响应头如下:
1 |
HTTP/ 1.1 302 Moved Temporarily |
2 |
... |
3 |
Location: http: //api.t.sina.com.cn/oauth/authorize?oauth_nonce=43101924&oauth_timestamp=1320229744& oauth_consumer_key=1038008035&oauth_signature_method=HMAC-SHA1& oauth_version=1.0&oauth_token=6abce644139028e58c4a4aca1e81df6c& oauth_signature=%2FcjvDr%2BSlMFfX4R43KB3GDvYC8Q%3D& oauth_callback=http%3A%2F%2Fmovie.douban.com%2Fpartner%2Fsina%2Fcallback |
4 |
... |
此时豆瓣服务端做了302,并带上了oauth_consumer_key,oauth_token,oauth_callback等参数;通过这个响应头可以看出,申请临时令牌的工作在豆瓣服务端就完成了;
1 |
GET /oauth/authorize?oauth_nonce= 43101924 &oauth_timestamp= 1320229744 & oauth_consumer_key= 1038008035 &oauth_signature_method=HMAC-SHA1& oauth_version= 1.0 &oauth_token=6abce644139028e58c4a4aca1e81df6c& oauth_signature=%2FcjvDr%2BSlMFfX4R43KB3GDvYC8Q%3D& oauth_callback=http%3A%2F%2Fmovie.douban.com%2Fpartner%2Fsina%2Fcallback HTTP/ 1.1 |
2 |
Host: api.t.sina.com.cn |
3 |
... |
在GET请求的URI后面,附加了很多参数,如oauth_consumer_key,oauth_version,oauth_callback等;此时界面如下:
当用户同意授权后,此进客户端还需要根据临时令牌去服务提供方(Access token URL)换取访问令牌;这个过程在豆瓣和新浪微博的HTTP请求中没有,应该是在豆瓣服务端完成,并将访问令牌保存下来,供以后使用;
PS:新浪微博貌似即将使用新的OAuth认证,即OAuth2.0;
OAuth 2.0相比OAuth 1.x有什么优点?
不管OAuth2.0流程如何简化,其最终是客户端能申请到访问令牌;
OAuth2.0中的四种角色:
比如Twitter用户,他在Twitter的数据就是资源,他自己就是这些资源的所有者;
保存资源的服务器,别人要访问受限制的资源就要出示访问令牌;
一个经过授权后,可以代表资源所有者访问资源服务器上受限制资源的一方。比如开发者开发的应用;
对资源所有者进行认证,认证通过后,向客户端发放访问令牌;
在OAuth2.0中,获取访问令牌有4种流程:
其大致流程是:客户端访问资源服务器上的资源,首先要引导用户到授权服务器进行授权,用户同意后客户端会获得授权码,客户端再根据授权码去换取访问令牌;
相比授权码,隐式授权少了第一步的取授权码的过程;该方式主要用于无服务端的应用,比如浏览器插件等;
此授权方式是客户端用用户的帐号信息去换取访问令牌;这种验证主要用于用户对客户端有极高的信任度的情况;
此授权是客户端使用自己的client证书(如client_id及client_secret组成的Http Basic验证码)来获取访问令牌;同样该授权主要用于对客户端信任的场景;
在OAuth2.0中,使用访问令牌来向资源服务器发出请求,取得资源;这里的资源服务器需要使用Https协议,否则访问令牌极可能被其它方获取;
飞信业务的特殊性:
资源分配:根据应用场景,将服务器资源分为:
每类服务器集群,其资源限流策略也不尽相同,主要根据应用、IP、时间几个维度综合考虑;但其总体策略是控制精度让位于响应时间和服务器资源开销;
以后遇到类似的需求时再研究吧
为什么会有这个概念,主要是因为容器线程的利用率不高;在前端高并发情况下,容器线程全部被占用,系统响应变慢,吞吐量下降;Web请求异步化中,两个关系要素:
异步化后,上下文环境如何保持;
在非异步化请求过程中,容器线程会一直Hold,直接后端服务返回结果,并直接输出Response到客户端;异步化后结果如何返回给客户端,也是个问题;
参考淘宝放翁的Web服务请求异步化介绍;
不管后端服务是否异步化,连接线程都是阻塞式等待其返回;当前端并发量增大时,容器的吞吐量会成为瓶颈;
增加工作者线程,工作都线程获得异步上下文后,释放容器线程;当后端服务完成时,由工作者线程根据异步上下文将结果直接返回给客户端;
连接线程将业务异步交给服务提供者,由服务提供者线程处理完后根据异步上下文将结果返回给客户端;
和前一个相比,是获取结果的方式不同;由另外工作者线程获取结果,并根据异步上下文返回给客户端;
相比3,结果是返回给调用者,即重入servlet由它返回结果给客户端;
新的Servlet 3.0规范中,3个新特性其中一个就是对异步处理的支持;在Servlet 3.0中,容器线程不再需要一直阻塞,直到后端服务处理完毕输出响应后才能释放,而是在接收到请求之后,容器线程将工作委派给另一个线程来完成,自己在不生成响应的情况下返回至容器;当工作者线程完成业务处理后,根据异步上下文环境直接commit响应到客户端;
针对业务处理较耗时的情况,这将大大减少服务器资源的占用,并且提高并发处理速度;
这次QCon收获还是蛮大的,会上听讲师演讲、会后看同事的总结分享、根据相关主题查阅资料,了解了很多以前没接触的技术,开扩了眼界;感谢部门、感谢公司~