什么是单点登陆
单点登陆(Single Sign On),简称为 SSO,是目前比较流行的企业业务整合的解决方案之一。SSO的定义是在多个应用系统中,用户只须要登陆一次就能够访问全部相互信任的应用系统。javascript
SSO通常都须要一个独立的认证中心(passport),子系统的登陆均得经过passport,子系统自己将不参与登陆操做,当一个系统成功登陆之后,passport将会颁发一个令牌给各个子系统,子系统能够拿着令牌会获取各自的受保护资源,为了减小频繁认证,各个子系统在被passport受权之后,会创建一个局部会话,在必定时间内能够无需再次向passport发起认证。css
举个例子,好比淘宝、天猫都属于阿里旗下的产品,当用户登陆淘宝后,再打开天猫,系统便自动帮用户登陆了天猫,这种现象背后就是用单点登陆实现的。html
单点登陆流程
1.登陆

- 用户访问系统1的受保护资源,系统1发现用户未登陆,跳转至sso认证中心,并将本身的地址做为参数
- sso认证中心发现用户未登陆,将用户引导至登陆页面
- 用户输入用户名密码提交登陆申请
- sso认证中心校验用户信息,建立用户与sso认证中心之间的会话,称为全局会话,同时建立受权令牌
- sso认证中心带着令牌跳转会最初的请求地址(系统1)
- 系统1拿到令牌,去sso认证中心校验令牌是否有效
- sso认证中心校验令牌,返回有效,注册系统1
- 系统1使用该令牌建立与用户的会话,称为局部会话,返回受保护资源
- 用户访问系统2的受保护资源
- 系统2发现用户未登陆,跳转至sso认证中心,并将本身的地址做为参数
- sso认证中心发现用户已登陆,跳转回系统2的地址,并附上令牌
- 系统2拿到令牌,去sso认证中心校验令牌是否有效
- sso认证中心校验令牌,返回有效,注册系统2
- 系统2使用该令牌建立与用户的局部会话,返回受保护资源
用户登陆成功以后,会与sso认证中心及各个子系统创建会话,用户与sso认证中心创建的会话称为全局会话,用户与各个子系统创建的会话称为局部会话,局部会话创建以后,用户访问子系统受保护资源将再也不经过sso认证中心,全局会话与局部会话有以下约束关系前端
- 局部会话存在,全局会话必定存在
- 全局会话存在,局部会话不必定存在
- 全局会话销毁,局部会话必须销毁
2.注销

- 用户向系统1发起注销请求
- 系统1根据用户与系统1创建的会话id拿到令牌,向sso认证中心发起注销请求
- sso认证中心校验令牌有效,销毁全局会话,同时取出全部用此令牌注册的系统地址
- sso认证中心向全部注册系统发起注销请求
- 各注册系统接收sso认证中心的注销请求,销毁局部会话
- sso认证中心引导用户至登陆页面
什么是CAS
CAS是Central Authentication Service的缩写,中央认证服务,一种独立开放指令协议。CAS 是 Yale 大学发起的一个开源项目,旨在为 Web 应用系统提供一种可靠的单点登陆方法。CAS 包含两个部分: CAS Server 和 CAS Client。CAS Server 须要独立部署,主要负责对用户的认证工做;CAS Client 负责处理对客户端受保护资源的访问请求,须要登陆时,重定向到 CAS Server。java
CAS 最基本的协议过程:算法

什么是OAuth2
OAuth(开放受权)是一个开放标准,容许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用。json
通俗说,OAuth就是一种受权的协议,只要受权方和被受权方遵照这个协议去写代码提供服务,那双方就是实现了OAuth模式。跨域
详细说就是,OAuth在"客户端"与"服务提供商"之间,设置了一个受权层(authorization layer)。"客户端"不能直接登陆"服务提供商",只能登陆受权层,以此将用户与客户端区分开来。"客户端"登陆受权层所用的令牌(token),与用户的密码不一样。用户能够在登陆的时候,指定受权层令牌的权限范围和有效期。"客户端"登陆受权层之后,"服务提供商"根据令牌的权限范围和有效期,向"客户端"开放用户储存的资料。浏览器
OAuth2是OAuth1.0的下一个版本,OAuth2关注客户端开发者的简易性,同时为Web应用,桌面应用和手机,和起居室设备提供专门的认证流程。原先的OAuth,会发行一个 有效期很是长的token(典型的是一年有效期或者无有效期限制),在OAuth 2.0中,server将发行一个短有效期的access token和长生命期的refresh token。这将容许客户端无需用户再次操做而获取一个新的access token,而且也限制了access token的有效期。缓存
CAS和OAuth2区别
- CAS的单点登陆时保障客户端的用户资源的安全,OAuth2则是保障服务端的用户资源的安全;
- CAS客户端要获取的最终信息是,这个用户到底有没有权限访问我(CAS客户端)的资源;oauth2获取的最终信息是,我(oauth2服务提供方)的用户的资源到底能不能让你(oauth2的客户端)访问;
- CAS的单点登陆,资源都在客户端这边,不在CAS的服务器那一方。用户在给CAS服务端提供了用户名密码后,做为CAS客户端并不知道这件事。随便给客户端个ST,那么客户端是不能肯定这个ST是用户伪造仍是真的有效,因此要拿着这个ST去服务端再问一下,这个用户给个人是有效的ST仍是无效的ST,是有效的我才能让这个用户访问。
- OAuth2认证,资源都在OAuth2服务提供者那一方,客户端是想索取用户的资源。因此在最安全的模式下,用户受权以后,服务端并不能直接返回token,经过重定向送给客户端,由于这个token有可能被黑客截获,若是黑客截获了这个token,那用户的资源也就暴露在这个黑客之下了。因而聪明的服务端发送了一个认证code给客户端(经过重定向),客户端在后台,经过https的方式,用这个code,以及另外一串客户端和服务端预先商量好的密码,才能获取到token和刷新token,这个过程是很是安全的。若是黑客截获了code,他没有那串预先商量好的密码,他也是没法获取token的。这样oauth2就能保证请求资源这件事,是用户赞成的,客户端也是被承认的,能够放心的把资源发给这个客户端了。
- CAS登陆和OAuth2在流程上的最大区别就是,经过ST或者code去认证的时候,需不须要预先商量好的密码。
总结:
CAS:受权服务器,被受权客户端
- 受权服务器(一个)保存了全局的一份session,客户端(多个)各自保存本身的session;
- 客户端登陆时判断本身的session是否已登陆,若未登陆,则(告诉浏览器)重定向到受权服务器(参数带上本身的地址,用于回调);
- 受权服务器判断全局的session是否已登陆,若未登陆则定向到登陆页面,提示用户登陆,登陆成功后,受权服务器重定向到客户端(参数带上ticket【一个凭证号】);
- 客户端收到ticket后,请求服务器获取用户信息;
- 服务器赞成客户端受权后,服务端保存用户信息至全局session,客户端将用户保存至本地session
OAuth2:主系统,受权系统(给主系统受权用的,也能够跟主系统是同一个系统),第三方系统
- 第三方系统须要使用主系统的资源,第三方重定向到受权系统;
- 根据不一样的受权方式,受权系统提示用户受权;
- 用户受权后,受权系统返回一个受权凭证(accessToken)给第三方系统【accessToken是有有效期的】;
- 第三方使用accessToken访问主系统资源【accessToken失效后,第三方需从新请求受权系统,以获取新的accessToken】。
什么是JWT
JSON Web Token(JWT)是一个开放标准(RFC 7519),它定义了一种紧凑且独立的方式,能够在各方之间做为JSON对象安全地传输信息。此信息能够经过数字签名进行验证和信任。JWT可使用秘密(使用HMAC算法)或使用RSA或ECDSA的公钥/私钥对进行签名。
JSON WEB令牌结构由三部分组成:
- Header(头部):包括令牌的类型及正在使用的散列算法。
- Payload(负载):声明是关于实体(一般是用户)和其余数据的声明。索赔有三种类型:标准注册声明,公共的声明和私有的声明。
- Signature(签名):必须采用编码标头,编码的有效负载,秘密,标头中指定的算法,并对其进行签名。
- 负载-标准的声明:
- iss:JWT签发者
- sub:JWT所面向的用户
- aud:接收JWT的一方
- exp:JWT的过时时间,这个过时时间必需要大于签发时间,这是一个秒数
- nbf:定义在什么时间以前,该JWT都是不可用的
- iat:JWT的签发时间
- 负载-公共的声明:能够添加任何信息,通常添加用户的相关信息或其余业务须要的必要信息,但不建议添加敏感信息,由于该部分在客户端可解密。
- 负载-私有声明:提供者和消费者所共同定义的声明,通常不建议存放敏感信息,由于base64是对称解密的,意味着该部分信息能够归类为明文信息。
建立签名须要使用编码后的
header
和payload
以及一个秘钥,使用header
中指定签名算法进行签名。例如若是但愿使用HMAC SHA256
算法,那么签名应该使用下列方式建立HMACSHA256(base64UrlEncode(header)+"."+base64UrlEncode(payload), secret)
签名用于验证消息的发送者以及消息是没有通过篡改的。完整的JWT格式输出是以.
分隔的三段Base64编码, 密钥secret是保存在服务端的,服务端会根据这个密钥进行生成token
和验证,因此须要保护好,更多信息请移步官网
单点登陆关于前端的部分
此代码采用OAuth2。关于token
存储问题,参考了网上许多教程,大部分都是将token
存储在cookie
中,而后将cookie
设为顶级域来解决跨域问题,但我司业务需求是某些产品顶级域也各不相同。故实现思路是将token
存储在localStorage
中,而后经过H5的新属性postMessage
来实现跨域共享,对跨域不了解的能够看我这篇文章。
实现思路:当用户访问公司某系统(如product.html)时,在product中会首先加载一个iframe,iframe中能够获取存储在localStorage中的token,若是没有取到或token过时,iframe中内部将把用户将重定向到登陆页,用户在此页面登陆,仍将去认证系统取得token并保存在iframe页面的localStorage
<!--product.html-->
<head>
<script src="auth_1.0.0.js"></script>
</head>
<body>
<h2>产品页面</h2>
<a onClick="login()" id="login">登陆</a>
<h3 id="txt"></h3>
</body>
<script> var opts = { origin: 'http://localhost:8080', login_path: '/login.html', path: '/cross_domain.html' } // 加载iframe,将src值为cross_domain.html的iframe加载到本页 var auth = new ssoAuth(opts); function getTokenCallback(data) { //若是没有token则跳到登陆页 if(!data.value){ auth.doWebLogin(); } //若是有token,直接在页面显示,而后作其它操做 document.getElementById('txt').innerText = 'token=' + data.value; } // 获取存储在名为cross_domain的iframe中的token auth.getToken(getTokenCallback); </script>
复制代码复制代码
讲解:在product.html中实例化了ssoAuth后,此页面便将iframe引入了当前页,名为opts.path的值,即cross_domain.html。auth.getToken()是获取此iframe页面中的localStorage值。
//auth_1.0.0.js
function ssoAuth(opts) {
this._origin = opts.origin,
this._iframe_path = opts.path,
this._iframe = null,
this._iframe_ready = false,
this._queue = [],
this._auth = {},
this._access_token_msg = { type: "get", key: "access_token" },
this._callback = undefined,
that = this;
<span class="hljs-comment">//判断是否支持postMessage及localStorage</span>
复制代码
var supported = (function () { try { return window.postMessage && window.JSON && 'localStorage' in window && window['localStorage'] !== null; } catch (e) { return false; } })();
_iframeLoaded = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
that._iframe_ready = <span class="hljs-literal">true</span>
<span class="hljs-keyword">if</span> (that._queue.length) {
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i = <span class="hljs-number">0</span>, len = that._queue.length; i < len; i++) {
_sendMessage(that._queue[i]);
}
that._queue = [];
}
}
_sendMessage = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">data</span>) </span>{
<span class="hljs-comment">// 经过contentWindow属性,脚本能够访问iframe元素所包含的HTML页面的window对象。</span>
that._iframe.contentWindow.postMessage(<span class="hljs-built_in">JSON</span>.stringify(data), that._origin);
}
<span class="hljs-comment">//获取token,但由于此时iframe尚未加载完成,先将消息存储在队列_queue中</span>
<span class="hljs-keyword">this</span>._auth.getToken = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">callback</span>) </span>{
that._callback = callback
<span class="hljs-keyword">if</span> (that._access_token_msg && that._iframe_ready) {
<span class="hljs-comment">//当iframe加载完成,给iframe所在的页面发送消息</span>
_sendMessage(that._access_token_msg);
} <span class="hljs-keyword">else</span> {
that._queue.push(that._access_token_msg);
}
}
<span class="hljs-keyword">var</span> _handleMessage = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">event</span>) </span>{
<span class="hljs-keyword">if</span> (event.origin === that._origin) {
<span class="hljs-keyword">var</span> data = <span class="hljs-built_in">JSON</span>.parse(event.data);
<span class="hljs-keyword">if</span> (data.error) {
<span class="hljs-built_in">console</span>.error(event.data)
that._callback({ <span class="hljs-attr">value</span>: <span class="hljs-literal">null</span> });
<span class="hljs-keyword">return</span>;
}
<span class="hljs-keyword">if</span> (that._callback && <span class="hljs-keyword">typeof</span> that._callback === <span class="hljs-string">'function'</span>) {
that._callback(data);
} <span class="hljs-keyword">else</span> {
<span class="hljs-built_in">console</span>.error(<span class="hljs-string">"callback is null or not a function, please "</span>);
}
}
}
<span class="hljs-keyword">this</span>._auth.doWebLogin = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
<span class="hljs-built_in">window</span>.location.href = opts.origin + opts.login_path + <span class="hljs-string">"?redirect_url="</span> + <span class="hljs-built_in">window</span>.location.href
}
<span class="hljs-comment">//初始化了一个iframe,并追加到父页面的底部</span>
<span class="hljs-keyword">if</span> (!<span class="hljs-keyword">this</span>._iframe && supported) {
<span class="hljs-keyword">this</span>._iframe = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">"iframe"</span>);
<span class="hljs-keyword">this</span>._iframe.style.cssText = <span class="hljs-string">"position:absolute;width:1px;height:1px;left:-9999px;"</span>;
<span class="hljs-built_in">document</span>.body.appendChild(<span class="hljs-keyword">this</span>._iframe);
<span class="hljs-keyword">if</span> (<span class="hljs-built_in">window</span>.addEventListener) {
<span class="hljs-keyword">this</span>._iframe.addEventListener(<span class="hljs-string">"load"</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
_iframeLoaded();
}, <span class="hljs-literal">false</span>);
<span class="hljs-built_in">window</span>.addEventListener(<span class="hljs-string">"message"</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">event</span>) </span>{
_handleMessage(event)
}, <span class="hljs-literal">false</span>);
} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>._iframe.attachEvent) {
<span class="hljs-keyword">this</span>._iframe.attachEvent(<span class="hljs-string">"onload"</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
_iframeLoaded();
}, <span class="hljs-literal">false</span>);
<span class="hljs-built_in">window</span>.attachEvent(<span class="hljs-string">"onmessage"</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">event</span>) </span>{
_handleMessage(event)
});
}
<span class="hljs-keyword">this</span>._iframe.src = <span class="hljs-keyword">this</span>._origin + <span class="hljs-keyword">this</span>._iframe_path;
}
<span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>._auth;
复制代码
复制代码<span class="hljs-comment">//判断是否支持postMessage及localStorage</span>
复制代码_iframeLoaded = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
that._iframe_ready = <span class="hljs-literal">true</span>
<span class="hljs-keyword">if</span> (that._queue.length) {
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i = <span class="hljs-number">0</span>, len = that._queue.length; i < len; i++) {
_sendMessage(that._queue[i]);
}
that._queue = [];
}
}
_sendMessage = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">data</span>) </span>{
<span class="hljs-comment">// 经过contentWindow属性,脚本能够访问iframe元素所包含的HTML页面的window对象。</span>
that._iframe.contentWindow.postMessage(<span class="hljs-built_in">JSON</span>.stringify(data), that._origin);
}
<span class="hljs-comment">//获取token,但由于此时iframe尚未加载完成,先将消息存储在队列_queue中</span>
<span class="hljs-keyword">this</span>._auth.getToken = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">callback</span>) </span>{
that._callback = callback
<span class="hljs-keyword">if</span> (that._access_token_msg && that._iframe_ready) {
<span class="hljs-comment">//当iframe加载完成,给iframe所在的页面发送消息</span>
_sendMessage(that._access_token_msg);
} <span class="hljs-keyword">else</span> {
that._queue.push(that._access_token_msg);
}
}
<span class="hljs-keyword">var</span> _handleMessage = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">event</span>) </span>{
<span class="hljs-keyword">if</span> (event.origin === that._origin) {
<span class="hljs-keyword">var</span> data = <span class="hljs-built_in">JSON</span>.parse(event.data);
<span class="hljs-keyword">if</span> (data.error) {
<span class="hljs-built_in">console</span>.error(event.data)
that._callback({ <span class="hljs-attr">value</span>: <span class="hljs-literal">null</span> });
<span class="hljs-keyword">return</span>;
}
<span class="hljs-keyword">if</span> (that._callback && <span class="hljs-keyword">typeof</span> that._callback === <span class="hljs-string">'function'</span>) {
that._callback(data);
} <span class="hljs-keyword">else</span> {
<span class="hljs-built_in">console</span>.error(<span class="hljs-string">"callback is null or not a function, please "</span>);
}
}
}
<span class="hljs-keyword">this</span>._auth.doWebLogin = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
<span class="hljs-built_in">window</span>.location.href = opts.origin + opts.login_path + <span class="hljs-string">"?redirect_url="</span> + <span class="hljs-built_in">window</span>.location.href
}
<span class="hljs-comment">//初始化了一个iframe,并追加到父页面的底部</span>
<span class="hljs-keyword">if</span> (!<span class="hljs-keyword">this</span>._iframe && supported) {
<span class="hljs-keyword">this</span>._iframe = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">"iframe"</span>);
<span class="hljs-keyword">this</span>._iframe.style.cssText = <span class="hljs-string">"position:absolute;width:1px;height:1px;left:-9999px;"</span>;
<span class="hljs-built_in">document</span>.body.appendChild(<span class="hljs-keyword">this</span>._iframe);
<span class="hljs-keyword">if</span> (<span class="hljs-built_in">window</span>.addEventListener) {
<span class="hljs-keyword">this</span>._iframe.addEventListener(<span class="hljs-string">"load"</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
_iframeLoaded();
}, <span class="hljs-literal">false</span>);
<span class="hljs-built_in">window</span>.addEventListener(<span class="hljs-string">"message"</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">event</span>) </span>{
_handleMessage(event)
}, <span class="hljs-literal">false</span>);
} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>._iframe.attachEvent) {
<span class="hljs-keyword">this</span>._iframe.attachEvent(<span class="hljs-string">"onload"</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
_iframeLoaded();
}, <span class="hljs-literal">false</span>);
<span class="hljs-built_in">window</span>.attachEvent(<span class="hljs-string">"onmessage"</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">event</span>) </span>{
_handleMessage(event)
});
}
<span class="hljs-keyword">this</span>._iframe.src = <span class="hljs-keyword">this</span>._origin + <span class="hljs-keyword">this</span>._iframe_path;
}
<span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>._auth;
复制代码} 复制代码复制代码
<!--cross_domain.html-->
<script type="text/javascript"> (function () { <span class="hljs-comment">//白名单</span>
<span class="hljs-keyword">var</span> whitelist = [<span class="hljs-string">"localhost"</span>, <span class="hljs-string">"127.0.0.1"</span>, <span class="hljs-string">"^.*\.domain\.com"</span>];
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">verifyOrigin</span>(<span class="hljs-params">origin</span>) </span>{
<span class="hljs-keyword">var</span> domain = origin.replace(<span class="hljs-regexp">/^https?:\/\/|:\d{1,4}$/g</span>, <span class="hljs-string">""</span>).toLowerCase(),
i = <span class="hljs-number">0</span>,
len = whitelist.length;
<span class="hljs-keyword">while</span> (i < len) {
<span class="hljs-keyword">if</span> (domain.match(<span class="hljs-keyword">new</span> <span class="hljs-built_in">RegExp</span>(whitelist[i]))) {
<span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
}
i++;
}
<span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
}
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handleRequest</span>(<span class="hljs-params">event</span>) </span>{
<span class="hljs-comment">// 白名单较验</span>
<span class="hljs-keyword">if</span> (verifyOrigin(event.origin)) {
<span class="hljs-keyword">var</span> request = <span class="hljs-built_in">JSON</span>.parse(event.data);
<span class="hljs-keyword">if</span> (request.type == <span class="hljs-string">'get'</span>) {
<span class="hljs-keyword">var</span> idi = sessionStorage.getItem(<span class="hljs-string">"idi"</span>);
<span class="hljs-keyword">if</span> (!idi) {
<span class="hljs-comment">// source:对发送消息的窗口对象的引用</span>
event.source.postMessage(<span class="hljs-built_in">JSON</span>.stringify({ <span class="hljs-attr">key</span>: request.key, <span class="hljs-attr">value</span>: <span class="hljs-literal">null</span> }), event.origin);
<span class="hljs-keyword">return</span>;
}
value = <span class="hljs-built_in">JSON</span>.parse(idi)[request.key];
event.source.postMessage(<span class="hljs-built_in">JSON</span>.stringify({ <span class="hljs-attr">key</span>: request.key, <span class="hljs-attr">value</span>: value }), event.origin);
} <span class="hljs-keyword">else</span> {
event.source.postMessage(<span class="hljs-built_in">JSON</span>.stringify({ <span class="hljs-attr">error</span>: <span class="hljs-string">"Not supported"</span>, <span class="hljs-attr">error_description</span>: <span class="hljs-string">"Not supported message type"</span> }), event.origin);
}
}
}
<span class="hljs-comment">// 接收iframe传来的消息</span>
<span class="hljs-keyword">if</span> (<span class="hljs-built_in">window</span>.addEventListener) {
<span class="hljs-built_in">window</span>.addEventListener(<span class="hljs-string">"message"</span>, handleRequest, <span class="hljs-literal">false</span>);
} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (<span class="hljs-built_in">window</span>.attachEvent) {
<span class="hljs-built_in">window</span>.attachEvent(<span class="hljs-string">"onmessage"</span>, handleRequest);
}
})();
复制代码
复制代码<span class="hljs-comment">//白名单</span>
<span class="hljs-keyword">var</span> whitelist = [<span class="hljs-string">"localhost"</span>, <span class="hljs-string">"127.0.0.1"</span>, <span class="hljs-string">"^.*\.domain\.com"</span>];
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">verifyOrigin</span>(<span class="hljs-params">origin</span>) </span>{
<span class="hljs-keyword">var</span> domain = origin.replace(<span class="hljs-regexp">/^https?:\/\/|:\d{1,4}$/g</span>, <span class="hljs-string">""</span>).toLowerCase(),
i = <span class="hljs-number">0</span>,
len = whitelist.length;
<span class="hljs-keyword">while</span> (i < len) {
<span class="hljs-keyword">if</span> (domain.match(<span class="hljs-keyword">new</span> <span class="hljs-built_in">RegExp</span>(whitelist[i]))) {
<span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
}
i++;
}
<span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
}
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handleRequest</span>(<span class="hljs-params">event</span>) </span>{
<span class="hljs-comment">// 白名单较验</span>
<span class="hljs-keyword">if</span> (verifyOrigin(event.origin)) {
<span class="hljs-keyword">var</span> request = <span class="hljs-built_in">JSON</span>.parse(event.data);
<span class="hljs-keyword">if</span> (request.type == <span class="hljs-string">'get'</span>) {
<span class="hljs-keyword">var</span> idi = sessionStorage.getItem(<span class="hljs-string">"idi"</span>);
<span class="hljs-keyword">if</span> (!idi) {
<span class="hljs-comment">// source:对发送消息的窗口对象的引用</span>
event.source.postMessage(<span class="hljs-built_in">JSON</span>.stringify({ <span class="hljs-attr">key</span>: request.key, <span class="hljs-attr">value</span>: <span class="hljs-literal">null</span> }), event.origin);
<span class="hljs-keyword">return</span>;
}
value = <span class="hljs-built_in">JSON</span>.parse(idi)[request.key];
event.source.postMessage(<span class="hljs-built_in">JSON</span>.stringify({ <span class="hljs-attr">key</span>: request.key, <span class="hljs-attr">value</span>: value }), event.origin);
} <span class="hljs-keyword">else</span> {
event.source.postMessage(<span class="hljs-built_in">JSON</span>.stringify({ <span class="hljs-attr">error</span>: <span class="hljs-string">"Not supported"</span>, <span class="hljs-attr">error_description</span>: <span class="hljs-string">"Not supported message type"</span> }), event.origin);
}
}
}
<span class="hljs-comment">// 接收iframe传来的消息</span>
<span class="hljs-keyword">if</span> (<span class="hljs-built_in">window</span>.addEventListener) {
<span class="hljs-built_in">window</span>.addEventListener(<span class="hljs-string">"message"</span>, handleRequest, <span class="hljs-literal">false</span>);
} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (<span class="hljs-built_in">window</span>.attachEvent) {
<span class="hljs-built_in">window</span>.attachEvent(<span class="hljs-string">"onmessage"</span>, handleRequest);
}
})();
复制代码</script> 复制代码复制代码
<!--login.html-->
<head>
<script src="auth_1.0.0.js"></script>
</head>
<body>
<form>
<input type="text" placeholder="用户名" id="user">
<input type="password" placeholder="密码" id="pwd">
</form>
<button onClick="login()">登 录</button>
</body>
<script> function login() { var name = document.getElementById('user') var pwd = document.getElementById('pwd') <span class="hljs-keyword">var</span> expires_in = <span class="hljs-number">7200</span>
<span class="hljs-comment">//假如这是登陆成功后,后台开发人员返回的json数据</span>
<span class="hljs-keyword">var</span> res = {
<span class="hljs-attr">access_token</span>: <span class="hljs-string">"xxxxx.yyyyy.zzzzz"</span>,
<span class="hljs-attr">expires_at</span>: expires_in * <span class="hljs-number">1000</span> + <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().getTime(),
<span class="hljs-attr">refresh_token</span>: <span class="hljs-string">"yyyyyyyyyyyyyyyyyyyyyyyyyyyy"</span>
};
localStorage.setItem(<span class="hljs-string">"idi"</span>, <span class="hljs-built_in">JSON</span>.stringify(res))
<span class="hljs-comment">//登陆成功后再返回原页面</span>
<span class="hljs-built_in">window</span>.location.href = getQueryString(<span class="hljs-string">"redirect_url"</span>)
}
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getQueryString</span>(<span class="hljs-params">name</span>) </span>{
<span class="hljs-keyword">var</span> reg = <span class="hljs-keyword">new</span> <span class="hljs-built_in">RegExp</span>(<span class="hljs-string">"(^|&)"</span> + name + <span class="hljs-string">"=([^&]*)(&|$)"</span>);
<span class="hljs-keyword">var</span> r = <span class="hljs-built_in">window</span>.location.search.substr(<span class="hljs-number">1</span>).match(reg);
<span class="hljs-keyword">if</span> (r != <span class="hljs-literal">null</span>) <span class="hljs-keyword">return</span> <span class="hljs-built_in">unescape</span>(r[<span class="hljs-number">2</span>]); <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
}
复制代码
复制代码<span class="hljs-keyword">var</span> expires_in = <span class="hljs-number">7200</span>
<span class="hljs-comment">//假如这是登陆成功后,后台开发人员返回的json数据</span>
<span class="hljs-keyword">var</span> res = {
<span class="hljs-attr">access_token</span>: <span class="hljs-string">"xxxxx.yyyyy.zzzzz"</span>,
<span class="hljs-attr">expires_at</span>: expires_in * <span class="hljs-number">1000</span> + <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().getTime(),
<span class="hljs-attr">refresh_token</span>: <span class="hljs-string">"yyyyyyyyyyyyyyyyyyyyyyyyyyyy"</span>
};
localStorage.setItem(<span class="hljs-string">"idi"</span>, <span class="hljs-built_in">JSON</span>.stringify(res))
<span class="hljs-comment">//登陆成功后再返回原页面</span>
<span class="hljs-built_in">window</span>.location.href = getQueryString(<span class="hljs-string">"redirect_url"</span>)
}
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getQueryString</span>(<span class="hljs-params">name</span>) </span>{
<span class="hljs-keyword">var</span> reg = <span class="hljs-keyword">new</span> <span class="hljs-built_in">RegExp</span>(<span class="hljs-string">"(^|&)"</span> + name + <span class="hljs-string">"=([^&]*)(&|$)"</span>);
<span class="hljs-keyword">var</span> r = <span class="hljs-built_in">window</span>.location.search.substr(<span class="hljs-number">1</span>).match(reg);
<span class="hljs-keyword">if</span> (r != <span class="hljs-literal">null</span>) <span class="hljs-keyword">return</span> <span class="hljs-built_in">unescape</span>(r[<span class="hljs-number">2</span>]); <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
}
复制代码</script> 复制代码复制代码
PS:注销暂时没作。另外postMessage有兼容性问题,若是其它小伙伴有更好的方法,望分享一下,谢谢~