网站认证方法 December 22, 2006
参考资料:
http://www.yupoo.com/apidoc/
http://code.google.com/apis/accounts/Authentication.html
网站的登录认证方式从单一网站到认证系统基本可以分为三种形式:
- 单网站单服务器登录
- 单网站多服务器登录
- 以及多网站多服务器认证
传统网站由于其体系相对的封闭特性,通常都只采用前两种登录方式,但随着Web2.0对网站的开发性要求,很久以来本地软件就已经成熟的API体系也逐渐被网站应用采用。
而网站应用最重要解决的问题就是安全认证,在保证网站内部关键数据不外泄的前提下提供信息。认证登陆则是解决这个问题的门锁。
★ 单网站单服务器登录
这是最简单的认证形态,登录信息不存在共享,只被一个应用服务器使用。因此,无论采用何种方式记录登录信息都可以,session数据可以放在服务器内存中,或者服务器数据库。用户在浏览器中输入帐号密码,发送到服务器后,由服务端通过用户数据库进行认证后将用户标识记录在服务器内的SessionData中。而客户端只记录Session的标识。
Account&Password <==|==>Session<==|==>KeyData
(Client) (Server) (BackDB)
用数据库记录Session数据有两个目的,其一是为了实现永久性登录,需要在Client端利用Cookie记录SessionID,以便服务器恢复登录状态(Session)。所以对于CookieDisable的浏览器是无法实现永久登录的。这就需要在数据库中保留Session数据。Django的Session数据库字段非常简单(SessionID,Data,Expire),通常Session数据都很简单,只记录标识,不记录大数据内容。
数据库维持Session另一个原因就是下面的多服务器登录。
★ 单网站多服务器登录
由于内存数据无法跨进程共享,更不可能做到跨服务器共享。但是现在大部分网站都由多台主机同时提供服务,用户在前后多个页面时,很有可能是有分别不同的主机提供的内容。如果内容和具体用户无关还好,但如果提供的个性化页面情况就不同了,这些服务器必须保存状态数据。
现在的互联网应用基本遵从“无状态服务”架构,这也是现在互联网能够服务海量服务请求的一个重要前提,所以SessionData应该尽量简单,其根本目的就是为了标识,而不是存储。
现在越来越多的网站都不再遵守这个框架原则,这主要是现在互联网对个性化服务的追求带来的变化,因此在设计具体网站时,要认真把握好有无状态的平衡。
状态数据必须利用数据库实现跨服务器访问,通常内容服务器只需要读取Session数据,而需专门的认证服务器来创建(或恢复)登录信息到Session中。
Account@Psw <==|==> LoginServer <==|==> UserDatabase
|
Session
|
Browser <==|==> ContentServer(s) <==|==> ContentDatabase
由于大型网站对登录的需求多种多样,主要是登录完成后的处理方式的不同:
A)单独登录页面
这种方式需要在登录成功后进行重定向,比如网站首页,登录前的页面。最简单的方式就是通过Url传递返回地址,如:
前段时间微软发布了一种“PageFunction”概念,这样就可以把登录页面作为一个函数来调用,这样可以想函数调用一样更方便的解决返回地址问题。
Caller Page Func
—— ———
Call page =>
login page
Call page <=
B)嵌入式登录页面
在网站中对于登录需求有两点很强烈:第一就是返回登录前地点,第二就是随时随处登录。嵌入式登录页面可以很好的解决这个问题,甚至可以做到登录时不跳转当前页面。
+————+——————–+
| | login page(frame) |
| +——————–+
| 内容页面 |
|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|
通过Frame嵌入登录服务器提供的登录页面,登录页面通过对当前用户状态的判断,决定显示登录内容还是注销、用户信息。而内容页面可以通过Session或DOM对登录进行控制。这种方式其实本质就是利用frame解决了前种方案的跳转问题,而且实行方式不需要内容页面做特殊处理,甚至可以通过master page将登录小页面实现到所有内容页面上,解决随时随处登录的问题。
但是随着网络应用的复杂度增加,内容服务器不可能都用同一个平台开发,甚至不可能运行在一个局域网内,更谈不上访问Session数据库。解决这个问题,就必须采用开放式的认证系统。
★ 多网站多服务器认证
对于不能运行在同一个局域网的服务器组,我们可以认为这些服务器是互不信任,甚至真的就是第三方的服务器,比如我要做一个专题图片展览,而应用的图片都来自于Flickr或者Yupoo,这就需要获取Flickr和Yupoo的认证。当然,Flickr不可能公开他的UserDatabase,其实我也不需要,我只要能让Flickr知道我能访问权限即可。
Client 专题展览应用 Flickr
—— ———- ——
–图片请求–> —请求登录—>
<——————登录页面—
–输入账户密码—————->
<–SessionId– <–认证标识—
–SessionId–> —认证标识–>
<——————图片数据—
从这个交互图,我们可以看出“认证标识”其实可以认为就是Flickr的SessionId,但实际并不是这么简单。原因有几个:
A)账户和密码只能由Client直接在Flickr上输入(不能让专题应用知道用户隐私)
B)flickr的SessionId只能保留在Client中,专题应用是拿不到的
C)不可能应用每做一次flickr调用之前都让用户输入密码
因此上图中的认证标识必然是一个“登录用户标识”和“应用标识”的对应体,而且是稳定存在的。因此登录流程改变成:
Client 应用 Flickr
—— — ——
–登录–> –登录(+key)–>
<–SessionId- <–Token—–(根据账户,应用Key创建Token)
key就是一个第三方应用的标识,而Token则对应了唯一的UserAccount+AppKey。Token是一个比session更持久的认证标识,为了使过程更可控,这个过程会优化为:
Client 应用 Flickr
—— — ——
–登录–> –请求frob—>
<–frob(一段时间内有效)–
–登录(+key+frob)–>
<–frob—–(根据账户,应用Key创建临时Token)
–获取token—->
<–SessionId- <–Token—-(将临时Token转化为正式Token)
frob就是一个请求token的临时入场券,token生成后必须在要求的时间内确认获取才会生效。
Token是一个很可怕的东西,他会通过Http的Uri或者Form明文传递,而且始终有效,一旦被别人掌握,这实在太可怕了!解决方法很简单,只需为每个创建的AppKey都同时随机创建一个ShareSecret,这个secret只被“应用”和“flickr”掌握,需要传递Token的时候,只需要把secret和调用参数合在一起,利用md5等不可逆算法计算出“签名”一并发送即可。
Leave a Reply