TA的每日心情 | 衰 2021-2-2 11:21 |
---|
签到天数: 36 天 [LV.5]常住居民I
|
SSO (Single-Sign-On) 即单点登录,在互联网应用中是多个站点通过一次登录即可访问所有产品,如Google所有产品通过 http://accounts.google.com/,百度所有产品统一登录地点是 http://passport.baidu.com/ 等,也有些产品是提供自己的登录界面,然后到统一入口验证。总之,就是要实现一次登录,处处登录。
) y; P1 p; m! K6 P1 q+ M/ t% V L" K: n% q8 _4 R
如果所有产品都是在同一主域下,那么只要把登录的标识信息存放到主域的 cookie 中,即可实现访问任一产品的页面时把登录信息传递到服务器,然后服务器根据该信息判断是否需要用户再次登录。虽然大多数公司的产品都是在同一个域名下,但有些还是独立域名的,这时就涉及到跨域问题,也是 SSO 的难点所在。
! e+ d0 u9 A6 B$ ]. h$ r0 W$ v' w/ S$ X& @4 e& O# L6 s1 u1 ~
基本思路是在一个固定的入口登录,成功后返回一个 token,将这个 token 附带在跨域访问的某个文件上,该文件拿到这个 token 和服务器上存放的值比较,并获取对应的登录用户信息,然后设置登录标识 cookie,以此完成 SSO 登录。服务器上的 token 可以存在 memcache 等缓存中,或者通过 RPC 访问。
* b, J! h8 G+ Q- a' C, m5 l, t6 m* W; ^& O* P8 p0 }- B1 x8 S
通过查看现有网站,主要是百度和新浪的 SSO 实现方案(截至2013-7-31),来对 SSO 实现方式有一个详细的了解。! u( g s& o& H7 X
O, N! s! j8 j6 _百度的 SSO0 F. T+ l$ G' U, i9 ^ G
% m0 R; }* d5 Y. @4 g: p7 m& ? 百度的很多产品都是在 baidu.com 这个主域名下,纳入到 SSO 的其他独立域名目前只有 hao123.com(很讨厌这个网站,一不小心就会在装软件时将它设为默认首页,还好现在不怎么用 IE)。
# m9 {- c+ E" p: ?3 ?6 J点击百度产品的登录,一般会跳转到 passport.baidu.com,在这个页面完成登录,也有些是浮层,但登录实现方式一样:
2 i$ g% j( \7 x3 b1.填写完用户名密码后,点击“登录”按钮。, R2 }" `, `. }, I4 t; l& l
2.js 创建一个 div 容器,在这个容器中主要创建两个元素:form 表单和 iframe。
3 t( ~8 x2 u$ @' T+ C, `+ L1.from 中包含很多 type="hidden" 的 <input/> 标记,主要包含填写内容和其他相关内容,如要登录的产品标识和成功后的跳转地址等。form 的提交目标窗口指向之后的 iframe。8 f# J# P! L8 D+ R6 i4 r. M8 m/ M% e$ `
2.iframe 初始地址所一个 _blank.html 文件,会造成一次 http 请求。
; ~ n) \/ x, J3.这些内容都是拼成一个字符串,一次性写入的。' G% N; Q3 _" j" ^! {2 z
3.动态创建节点完成后,马上提交数据,指向 iframe 中 passport.baidu.com/v2/api/?login。: Z) e1 z* \4 z& n2 `
4.提交返回的结果内容在 iframe 中,通过 js 中的 'location.replace()' 跳转 iframe 到一个新的页面,这个页面是第2步中的表单项 'staticpage' 指定的,一般都叫 v3Jump.hmtl,不同产品只是路径不同。
9 ~& ]9 z4 K' M' B# l5.v3Jump.html 中的 js 的作用就是以形如 parent.someMethod({}) 的方式调用 iframe 父级窗口的 js 方法。涉及到不同域名调用主窗口 js 方法,因此一般 v3Jump.html 都是放在和主窗口同一域名下。" ?. p2 z/ L2 }1 s7 x2 Y4 n5 B/ ~. f/ C3 s
6.主窗口的 js 处理页面表现,同时为了实现跨域,会调用 https://user.hao123.com/static/crossdomain.php?bdu=...&t=3434312,这个 php 会根据 bdu 值验证登录状态,并设置 hao123.com 这个域名的 cookie 登录标识。比较巧妙的是,百度把这个地址作为一个 Image 对象的 src 属性,这样能完成请求,还不会渲染到页面上。/ k4 u, p3 n* W* o. ]3 f& }1 m8 q/ M( f
7.最后,主窗口的 js 跳转页面到指定的地址。
: A. |0 y; y3 E9 [% t) k
" Q* R: Q2 G; Y# K9 }' k5 _$ e新浪的 SSO+ ^; y" P4 B( d# b8 ~
新浪的独立域名好像只有一个 weibo.com,其他产品都是在 sina.com.cn 下。它的登录方式与百度基本相同,这里挑选不同的几点说明。
3 t: A2 ?/ A; |) s8 E在 weibo.com 登录
8 y ?$ u/ C( |% s1.同百度
% y2 @+ a/ |2 U* D0 U( k! [1 I1 l3 W4 F! ]2.同百度; f0 T" X: a% s0 t6 g8 t
3.提交数据到 iframe, 指向 login.sina.com.cn/sso/login.php,提交表单后,会立马删除 from 节点(百度只在登录失败再次提交时才替换这个 form 节点)
2 {, q. a/ f( U8 ]+ |4.如果登录失败,iframe 中的内容为 location.replace() 跳转到 weibo.com/ajaxlogin.php;如果登录成功,则跳转地址为 weibo.com/sso/login.php,该文件返回 302,跳转到 ajaxlogin.php。5 W% Z" s8 b$ p; Z6 q$ v: g9 e/ K
5.ajaxlogin.php 负责用形如 parent.someMethod({}) 方式调用父窗口 js,处理页面。1 V; ^1 ~ c& |
6.父窗口 js 删除 iframe 节点
8 C, H3 e2 k- _% n7.同百度
0 W+ I s& |/ K; M新浪其他 sina.com.cn 子域登录$ h8 J- ]' C1 b- O+ g; d1 S6 b4 Z
1.同 weibo
7 \7 W6 R8 g: X+ ]' e2 |! J9 S, j2.同 weibo
( I0 V! W& \7 g Z3.同 weibo,但不会删除 form 节点
9 h! ~& u, k- `0 j: E3 Z$ a4.这里有些不同,login.sina.com.cn 下,login.php 的内容用 location.replace() 指向 login.sina.com.cn/crossdomain2.php,由这个页面调用 parent.someMethod();而在新浪首页,login.php 中先设置 document.domain='sina.com.cn'(login.php 与页面域名不完全相同),然后再调用 parent.someMethod()。
" f) }0 b6 g/ \7 x- [' W, t5.父窗口的 js 处理页面表现,并用jsonp方式(放到script标记的src中)调用 weibo.com/sso/login.php 来完成跨域登录。5 ]$ Y4 P! c: R! s
6.结束
# Y ]/ Z: c# l- p8 Q新浪的登录 js 并不统一,明显 weibo 的 js 处理的更精细。
& t" R& {4 u# `8 d0 }weibo 登录中的第 4 步,iframe 中跳转方式实现对跨域的访问,显然有些局限。如果还有其他独立域名需要访问,这种跳转将无法兼顾。
: b# n4 \. M5 t8 ~总结
7 V5 O# [* u5 O3 C" M5 }8 C; U上面两个站点的实现方式基本相同,都是用 iframe 登录,然后在 iframe 中跳转来达到通过同一入口进行登录。难点在于跨域,特别需要注意的是:2 i5 B3 P5 T; ]: d! s) }7 G
•iframe 中的 js 如果要访问父窗口的方法,需要保证域名相同,或者主域相同并都设置domain属性为主域地址,否则浏览器会报安全警告。
% k, K. y% ^; w" B$ M1 U; f•跨域只要发起跨域的http请求即可,可以放到 script 标记的src中,也可已放到图片对象的 src 中,推荐后者,因为后者不用放到dom节点中。需要注意的是,这两种方式都要带一个每次都不同的参数,可以是时间戳,以防止浏览器的自动缓存。# @, P( Y- r, s* e
上面着重关注了访问的跳转顺序,还有一个关键点是如何标识登录状态。上面的方案中,都会在请求跨域文件时,带上登录返回的一个唯一字符串,将它作为一个 token,在后端验证登录,识别登录的用户。可以把这个 token 设置为很短的时间有效,如1分钟,并在访问一次后删除,可以保证一定的安全性,但是如果在使用前截取,那么可以拿到任何一个地方登录。因为上面两个网站对跨域文件的访问都是写在主窗口的js里,因此可以很容易设置断点获取之。
! @' {. q7 ]/ P7 w据说 Google 在这点上是安全的,可惜身边没法翻墙,留待以后吧。
# R' Y% T( b* \& N- T) _8 s- P8 i* H$ X; B
补记" _& o5 ]; q' ?. s% a7 s! G, ~
*2013-8-4
, t. h: d9 \2 h& K( }& @周末有空折腾了一下翻墙,找到个超级好东西:SmartHosts,Youtube/Facebook/twitter... 都可以上了。; ?* s$ e( \) H/ W2 u5 C ~
Google SSO 实现方式
0 _8 y! o% R& OGoogle 所有产品的登录都是通过 https://accounts.google.com/ 进行处理,基本流程如下:
1 V" n) t4 [9 X+ m1.在 Google 产品站点击“登录”,会跳转到 https://accounts.google.com/ServiceLogin 登录;
3 v# V; g) u( q" E. @- _* t2.表单 post 提交到 https://accounts.google.com/ServiceLoginAuth 验证;
, f* K! r( `7 T% R) b. b. ^( M# A: Z3.登录成功则直接通过 302 转到 https://accounts.google.com/CheckCookie,访问跨域产品的页面,一般是 accounts.hostname/accounts/SetSID,设置登录cookie;( {2 {+ l2 v/ |8 b7 R/ z9 X
4.页面跳转回登录来源页。2 Y' R0 D9 e' f6 f3 w
针对不同的来源,具体处理上在第3步有些差别:8 |' P+ R# {0 Y" ]8 f' i2 E/ a. ^
•如果登录来源是 *.google.com 或 youtube.com,则直接通过302指向 accounts.youtube.com/accounts/SetSID,之后该地址再转向到来源地址。
! O H5 z0 j# M) z5 A" ~$ v( p9 H•如果登录来源是 *.google.com.hk,则返回200,通过 jsonp 请求 accounts.google.com.hk/accounts/SetSID 和 accounts.youtube.com/accounts/SetSID
: q Q" x4 c! N7 }5 j- E可以看到,基本原理是一样的,都是登录后,访问一下跨域的页面,完成登录信息的cookie设置。0 L( \2 a# K" k
过程中通过修改 accounts.youtube.com 的 ip 指向,截取到了登录后的 /accounts/SetSID 链接,直接在一个新的浏览器中访问,是可以完成登录的。因此,Google 的 token 也不能保证这种截取的安全性。# |1 _7 t. t, n
原文转自:http://calefy.org/2013/07/31/how-to-achieve-sso-login.html8 U. X, r% c" C$ ?
, I5 h9 X# L; Q0 O2 c
|
|