[关闭]
@42withyou 2015-02-28T06:51:52.000000Z 字数 5077 阅读 539

青基会单点登陆(SSO)设计及接口文档

文档


文档地址:https://www.zybuluo.com/42withyou/note/71092


修订记录

版本号 内容 制定人 制定时间
1.0 根据服务接口需求撰写文档 叶科忠 2015.2.10

需求

实现青基会下属网站一处登陆,其它接入SSO系统的网站都同步登陆。


实现方式

登陆成功后,前台从单点登陆服务器(passport.cydf.org.cn)获取接入的应用列表,通过 jsonp ajax 实现跨域重定向,向各个应用传递加密后的登陆信息,各个应用响应请求,设置加密cookie。
之后,各应用即可通过解析 cookie 获取到登陆信息。


技术要点

1. 跨主域同步登陆信息 cydf_sso.js

相关文件:(http://passport.cydf.org.cn/styles/js/cydf_sso.js
通过 jsonp ajax 实现跨域重定向,参考 https://api.jquery.com/jQuery.ajax/
用jquery ajax发起一次异步请求,server返回302,如果重定后url的域名跟ajax请求的域名是同一个域名的话,浏览器会再发起一次重定向后的http请求,请求成功会调用ajax的success函数,如果重定向后url的域名跟ajax请求的域名不是同一个域名,也就是跨域重定向(跨域redirect),这个时候浏览器看到返回的response的Location跨域了就不会再发起请求,请求被拦截了,ajax请求失败会调用error方法。
普通的ajax请求不行,我们需要通过 jsonp 的方式,而且需要设置crossDomain:true。

2. 加密 CydfSSO.class.php

相关文件 CydfSSO.class.php
该文件提供两个类 CydfSSOCipher 和 CydfSSO,前者提供加密,后者提供开发友好的接口。

  1. // CydfSSOCipher
  2. // 使用 AES-256 / CBC / ZeroBytePadding encrypt 加密,即 CBC 模式的 AES256 用于加密
  3. // 参考 PHP 手册 http://php.net/manual/en/function.mcrypt-encrypt.php
  4. function __construct($securekey); // 实例化,$securekey 接入SSO时提供
  5. public function encrypt($input); // 加密
  6. public function decrypt($input); // 解密
  1. // CydfSSO
  2. function __construct($securekey); // 实例化,$securekey 接入SSO时提供
  3. public function getUidFromCookie($cookie); // 从 cookie 获取 UserGUID
  4. public function getCookieFromUid($uid); // 从 UserGUID 获取 cookie

实现流程

登陆

  1. 前台引入 cydf_sso.js(生产环境提供 .min.js 版本)
  2. 登陆之后,通过加密类 CydfSSO,将登陆用户 UserGUID 加密,并赋值给前台JavaScript变量(_hellocydf)
  3. cydf_sso.js 执行 CydfSSO.login(_hellocydf);

  4. 通过Jquery.getJSON()方法发起 http://passport.qjh.com/index/hello?h=_hellocydf 请求,跨域获取需要跨域设置登陆cookie的应用列表,返回一个Json数据

    1. jQuery181025357960700057447_1423724693878(
    2. {"sso":[
    3. "http:\/\/passport.qjh.com\/index\/set_cookie?t=http:\/\/jlxd.qjh.com\/sso\/login&h=86KdN6Q2Kmu7s0s%2Fl%2BOb42qGSDkUwMHc10ZEo1vGycmmrmrObTtPB7ZZ7y8IbQOObdNgF19gLmIhT2KeqHCIh8wVmlq2iDJ4qH%2B3FVOdx6M%3D&callback=?",
    4. "http:\/\/passport.qjh.com\/index\/set_cookie?t=http:\/\/cart.q.com\/sso\/login&h=iNzlVBQP%2B%2F78Vg3RwyszA0Mf0JCy5ISgloIRmu6qHlnlybSMafQ9U5a%2BShfHJRcBZP%2Fd0ZJtVsMuYCAcBEvCyr817qI1teWEb0S7i2WsyZ0%3D&callback=?",
    5. "http:\/\/passport.qjh.com\/index\/set_cookie?t=http:\/\/xszz.qjh.com\/sso\/login&h=UfVYrNqjLlRQ1bjDdMbWpJZvyyMWk4nUlRhjong4kyaSUpCCiB9Kef9DHAOZ5Y7j1inunsATEBCSMMSe8bcQTOTYjSgkIE7q1mZGY0TJVEs%3D&callback=?"
    6. ],
    7. "status":"success"
    8. }
    9. );
  5. js遍历sso,通过jQuery.getJSON()方法对其中的每条数据发起跨域的jsonp请求,返回一个重定向的Response(302 Moved Temporarily),而且是跨域的重定向

    1. // Qequest Headers
    2. Request URL:http://passport.qjh.com/index/set_cookie?t=http://jlxd.qjh.com/sso/login&h=86KdN6Q2Kmu7s0s%2Fl%2BOb42qGSDkUwMHc10ZEo1vGycmmrmrObTtPB7ZZ7y8IbQOObdNgF19gLmIhT2KeqHCIh8wVmlq2iDJ4qH%2B3FVOdx6M%3D&callback=jQuery181025357960700057447_1423724693878&_=1423724699024
    3. Request Method:GET
    4. Status Code:302 Moved Temporarily
    5. // Response Headers
    6. Location:http://jlxd.qjh.com/sso/login?c=86KdN6Q2Kmu7s0s%2Fl%2BOb42qGSDkUwMHc10ZEo1vGycmmrmrObTtPB7ZZ7y8IbQOObdNgF19gLmIhT2KeqHCIh8wVmlq2iDJ4qH%2B3FVOdx6M%3D
  6. 由于发起的是跨域的jsonp请求,所以浏览器会根据返回的重定向url(Location)发起一次请求,也就是最后的跨域设置Cookie的请求
    其中 http://jlxd.qjh.com/sso/login 接口由接入方实现

    1. // Qequest Headers
    2. Request URL:http://jlxd.qjh.com/sso/login?c=86KdN6Q2Kmu7s0s%2Fl%2BOb42qGSDkUwMHc10ZEo1vGycmmrmrObTtPB7ZZ7y8IbQOObdNgF19gLmIhT2KeqHCIh8wVmlq2iDJ4qH%2B3FVOdx6M%3D
    3. Request Method:GET
    4. Status Code:200 OK
    5. // Response Headers
    6. Set-Cookie:hellocydf=86KdN6Q2Kmu7s0s%2Fl%2BOb42qGSDkUwMHc10ZEo1vGycmmrmrObTtPB7ZZ7y8IbQOObdNgF19gLmIhT2KeqHCIh8wVmlq2iDJ4qH%2B3FVOdx6M%3D; path=/; domain=jlxd.qjh.com; httponly
  7. 返回的Response header中含有Set-Cookie项,这样就在jlxd.qjh.com域名下设置了Cookie
  8. 应用检查 hellocydf cookie,如果存在则通过 加密类 CydfSSO 解析获取登陆用户的 UserGUID,登陆用户。

退出登陆

  1. 后台退出登陆后,设置前台JavaScript变量(_hellocydf_logout) 为 1
  2. cydf_sso.js 执行 CydfSSO.logout();
  3. 经过同上跨域流程后,302重定向到各应用退出登陆接口
    其中 http://jlxd.qjh.com/sso/logout 接口由接入方实现

具体实现方法

应用接入SSO时,需实现 login,和 logout 接口,供 cydf_cart.js 跨域调用传递加密的登陆信息

login接口

参数:c 加密后的登陆信息
http://jlxd.qjh.com/sso/login?c=86KdN6Q2Kmu7s0s%2Fl%2BOb42qGSDkUwMHc10ZEo1vGycmmrmrObTtPB7ZZ7y8IbQOObdNgF19gLmIhT2KeqHCIh8wVmlq2iDJ4qH%2B3FVOdx6M%3D

  1. public function login() {
  2. $c = I('c'); // 获取c参数
  3. if (!$c) {
  4. return false;
  5. }
  6. // 设置cookie,$this->_main_domain为应用域名,如: jlxd.cydf.org.cn
  7. // 为保证安全性,请将 cookie httponly 设置为 true
  8. setcookie('hellocydf', $c, 0, '/', $this->_main_domain, false, true);
  9. }

logout接口

http://jlxd.qjh.com/sso/logout

  1. public function logout() {
  2. session('login_user', null); // 退出当前登陆用户
  3. session('hellocydf', null); // 其它相关变量清理,请按应用自己逻辑处理
  4. // 删除 hellocydf cookie
  5. setcookie('hellocydf', null, 0, '/', $this->_main_domain);
  6. }

接入成功后,应用通过 hellocydf cookie。获取登陆信息

  1. // 各应用自己的登陆逻辑
  2. public function logOn($user) {
  3. session("login_user", $user);
  4. $this->_SSOLogOn($user['UserGUID']);
  5. return true;
  6. }
  7. // SSO 登陆逻辑
  8. protected function _SSOLogOn($uid) {
  9. $CydfSSO = new CydfSSO(C('SSO_SECURITY_KEY')); // 通过 SECURITY_KEY 实例化 CydfSSO类
  10. $hellocydf = $CydfSSO->getCookieFromUid($uid); // 获取加密串
  11. // 通过一定方式将加密串传递到前台 _hellocydf js 变量
  12. session('hellocydf', $hellocydf);
  13. // 前台js: var _hellocydf = "{:urlencode(session('hellocydf'))}";
  14. }
  15. // 同 logout接口
  16. protected function _SSOLogOut() {
  17. session('hellocydf', null);
  18. session('hellocydf_logout', 1);
  19. setcookie('hellocydf', null, 0, '/', C('MAIN_DOMAIN'));
  20. // 前台js: var _hellocydf_logout = "{:Session::get('hellocydf_logout', true)}";
  21. }
  22. public function logOut(){
  23. session("login_user", null);
  24. $this->_SSOLogOut();
  25. }

各应用需负责在登陆和退出登陆后设置对应JS变量,触发cydf_sso.js完成相应操作

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注