## oauth
一、OAUTH 产生的背景
典型案例:如果一个用户拥有两项服务:一项服务是图片在线存储服务A,另一个是图片在线打印服务B。如下图所示。由于服务A与服务B是由两家不同的服务提供商提供的,所以用户在这两家服务提供商的网站上各自注册了两个用户,假设这两个用户名各不相同,密码也各不相同。当用户要使用服务B打印存储在服务A上的图片时,用户该如何处理?法一:用户可能先将待打印的图片从服务A上下载下来并上传到服务B上打印,这种方式安全但处理比较繁琐,效率低下;法二:用户将在服务A上注册的用户名与密码提供给服务B,服务B使用用户的帐号再去服务A处下载待打印的图片,这种方式效率是提高了,但是安全性大大降低了,服务B可以使用用户的用户名与密码去服务A上查看甚至篡改用户的资源。
很多公司和个人都尝试解决这类问题,包括Google、Yahoo、Microsoft,这也促使OAUTH项目组的产生。OAuth是由Blaine Cook、Chris Messina、Larry Halff 及David Recordon共同发起的,目的在于为API访问授权提供一个开放的标准。OAuth规范的1.0版于2007年12月4日发布。通过官方网址: http://oauth.net 可以阅读更多的相关信息。
二、OAUTH 简介
在官方网站的首页,可以看到下面这段简介:
An open protocol to allow secure API authorization in a simple and standard method from desktop and web applications.
大概意思是说OAUTH是一种开放的协议,为桌面程序或者基于BS的web应用提供了一种简单的,标准的方式去访问需要用户授权的API服务。OAUTH类似于Flickr Auth、Google’s AuthSub、Yahoo’s BBAuth、 Facebook Auth等。OAUTH认证授权具有以下特点:
1. 简单:不管是OAUTH服务提供者还是应用开发者,都很容易于理解与使用;
2. 安全:没有涉及到用户密钥等信息,更安全更灵活;
3. 开放:任何服务提供商都可以实现OAUTH,任何软件开发商都可以使用OAUTH;
## 第三方登录的弊端
当前,许多应用都支持第三方登录。从用户的角度来说,他们可以不必填写他们以前多次填写过的信息;从应用的角度来说,它可能可以立即获取用户的好友列表。不过,第三方登录在拥有诸多好处的同时也有诸多弊端。近日,私人团体分享平台 Cluster 合伙创始人 Taylor Hughes 对此进行了 分析 。
首先,第三方登录会影响用户对产品的预期。例如,如果用户使用Facebook账户登录,那么他可能会认为该产品可以邀请Facebook好友。一旦产品没有此项功能,用户可能会因此对产品失望。
其次,第三方登录会引入不可预期的技术成本。虽然实现第三方登录看上去很简单,但这个过程中可能出现复杂的问题,并且可能会因为第三方登录提供程序的文档更新不及时而难以找到解决方案。在Cluster for iOS中,Google SDK当前是问题的最大根源。这是由该SDK代码中某个深层次的Bug引起的,虽然难以排查,但又不得不处理。
再者,应用一旦提供第三方登录方式,那它就不能只提供一种社会化登录方式,因为用户很自然地就会要求提供更多登录方式。Cluster最初只提供了“用Facebook登录”的功能,后来又相继增加了“用电子邮件登录”和“用Google登录”的功能。实际上,Cluster 45%的新用户选择了手动填写电子邮件和密码的方式。
最后,第三方登录方式选择过多可能会使用户忘记自己的注册方式。如果用错误的方式登录,那他可能会奇怪,为什么自己的信息都消失了。
此外,Taylor还指出,让用户注册并不会成为他们选择产品或服务的障碍。
以上观点来自<http://www.infoq.com/cn/news/2014/11/third-party-login-drawbacks>
## thinksdk
由于oauth是一种协议标准,然后互联网又有那么多知名平台,他们提供的oauth 支持通一叫第三方登录,登录授权后你可以使用我平台的部分接口。
然后由于程序员太多了,提供的每个oauth sdk都不一样。所以我们伟大的麦当苗儿发明了thinksdk 这个轮子,让我们方便的接入第三方登录。
### 类库引入
由于我们最新版用的是命名空间,所以我就下了一个命名空间版的thinksdk
<http://www.thinkphp.cn/code/1115.html>
然后 放入 Common模块里去。
用的时候命名空间调用。
### 配置并构造登录用的url
首先,修改Common模块 conf配置里第三方登录回调常量
`define('URL_CALLBACK', 'http://freelog.coding.io/user/callback?type=');`
自己申请了哪些应用,就改哪个sdk的配置,如我只申请了新浪微博的,qq由于审核比较严格,我们只做演示流程,新浪的够用了。
![2015-07-06/55995d2c409c9](http://box.kancloud.cn/2015-07-06_55995d2c409c9.png)
![2015-06-29/55911bce126c1](http://box.kancloud.cn/2015-06-29_55911bce126c1.png)
![2015-06-29/55911bfa5f3fe](http://box.kancloud.cn/2015-06-29_55911bfa5f3fe.png)
由于新浪提交要 备案,coding上只是个演示站,我也不想那么麻烦了,就用自己的账号测试就好了。可以添加多个测试微博账号滴。
~~~
//新浪微博配置
'THINK_SDK_SINA' => array(
'APP_KEY' => '3073201486', //应用注册成功后分配的 APP ID
'APP_SECRET' => 'b3a79ef47b060e58a7ac51dc7d8747ec', //应用注册成功后分配的KEY
'CALLBACK' => URL_CALLBACK . 'sina',
),
~~~
这里的type 参见OauthSDK sdk目录下类名 SDK.class.php前面的。
如SinaSDK.class.php 就是Sina。
~~~
//登录地址
public function oauth($type = null){
empty($type) && $this->error('参数错误');
//加载ThinkOauth类并实例化一个对象
$name = ucfirst(strtolower($type)) . 'SDK';
$names = "Common\OauthSDK\sdk"."\\".$name;
$oauth = new $names();
//跳转到授权页面
redirect($oauth->getRequestCodeURL());
}
~~~
### 处理回调
回调的参数都一样,如下图四个。
![2015-06-29/559020018d877](http://box.kancloud.cn/2015-06-29_559020018d877.png)
~~~
//授权回调地址
public function callback($type = null, $code = null){
(empty($type) || empty($code)) && $this->error('参数错误1');
//加载ThinkOauth类并实例化一个对象
$name = ucfirst(strtolower($type)) . 'SDK';
$names = "Common\OauthSDK\sdk"."\\".$name;
$oauth = new $names();
//腾讯微博需传递的额外参数
$extend = null;
// if($type == 'tencent'){
// $extend = array('openid' => $this->$_GET('openid'), 'openkey' => $this->$_GET('openkey'));
// }
//请妥善保管这里获取到的Token信息,方便以后API调用
//调用方法,实例化SDK对象的时候直接作为构造函数的第二个参数传入
//如: $qq = ThinkOauth::getInstance('qq', $token);
$token = $oauth->getAccessToken($code , $extend);
//获取当前登录用户信息
if(is_array($token)){
$uid = is_login();
$oauth = new \Common\Controller\TypeEvent();
$user_info = $oauth->$type($token);
$token['member_id'] = $uid;
$token['type'] = strtolower($user_info['type']);
$token['name'] = D('Sns')->default_oauths[$token['type']]['title'];
if($exist = M('Sns')->where("member_id={$uid} AND type='{$token['type']}'")->find()){
$token['update_time'] = NOW_TIME;
$token['id'] = $exist['id'];
}else{
$token['id'] = M('Sns')->count() + 1;
$token['create_time'] = $token['update_time'] = NOW_TIME;
}
$token['status'] = 1;
M('Sns')->add(M('Sns')->create($token), array(), true);
$this->success('绑定成功', '/user/profile');
}
}
~~~
我改了下回调,就是看sns里对应类型的登录信息有没有,有就更新token,没有就新增token信息。
然后是解除绑定
~~~
public function unbindOauth($id){
if($sns = M('Sns')->find($id)){
$data = array();
$name = ucfirst($sns['type']) . 'SDK';
$names = "Common\OauthSDK\sdk"."\\".$name;
$oauth = new $names($sns['access_token']);
switch ($sns['type']) {
case 'sina':
$data['ret'] = !$oauth->call('OAuth2/revokeoauth2');
break;
default:
$this->error('错误的第三方登录接口类型');
break;
}
if($data['ret'] == 0){
}else{
$this->error("解除{$sns['name']}授权失败");
}
M('Sns')->delete($id);
$this->success('解除绑定成功');
}else{
$this->error('尚未绑定,无需解绑');
}
}
~~~
其他类型的待自己做的时候查官方文档补充。
然后,前台用户资料里就是遍历根据有无输出显示绑定链接还是解除绑定。
至于第三方接口绑定过后的使用,留给你们想象了。
发布文章后发微博、qq空间之类的。都好用 `$oauth->call()`去实现。
只是个填空题。
## 第三方开放平台文档列表
- 新浪 <http://open.weibo.com>
- 腾讯 <http://open.qq.com>
- 百度 <http://developer.baidu.com>
- 豆瓣 <http://developers.douban.com>
- 人人网 <http://dev.renren.com>
- 淘宝网 <http://open.taobao.com>
- 微信 <https://mp.weixin.qq.com>
- 360开发平台已经变为360移动开放台了 <http://dev.360.cn/wiki/index/id/67>
- github <https://developer.github.com/v3/>
## 开发中使用第三方服务的流程
1. 注册第三方服务的应用、设置要开发应用的网址:回调等信息。
2. 熟悉第三方的sdk,将php版或者js版引入到项目中,然后设置注册应用的ak、sk。
3. 通过ak、sk生成服务提供的接口。参照官方文档,传入正确数量和正确值的参数。
4. 验证获取的结果格式是否和官方文档一致,如果不符合本身系统需要,还要进行格式转换。
5. 写获取第三方服务产生的数据以后自己业务的处理代码。
- 序
- 前言
- 内容简介
- 目录
- 基础知识
- 起步
- 控制器
- 模型
- 模板
- 命名空间
- 进阶知识
- 路由
- 配置
- 缓存
- 权限
- 扩展
- 国际化
- 安全
- 单元测试
- 拿来主义
- 调试方法
- 调试的步骤
- 调试工具
- 显示trace信息
- 开启调试和关闭调试的区别
- netbeans+xdebug
- Socketlog
- PHP常见错误
- 小黄鸭调试法,每个程序员都要知道的
- 应用场景
- 第三方登录
- 图片处理
- 博客
- SAE
- REST实践
- Cli
- ajax分页
- barcode条形码
- excel
- 发邮件
- 汉字转全拼和首字母,支持带声调
- 中文分词
- 浏览器useragent解析
- freelog项目实战
- 需求分析
- 数据库设计
- 编码实践
- 前端实现
- rest接口
- 文章发布
- 文件上传
- 视频播放
- 音乐播放
- 图片幻灯片展示
- 注册和登录
- 个人资料更新
- 第三方登录的使用
- 后台
- 微信的开发
- 首页及个人主页
- 列表
- 归档
- 搜索
- 分页
- 总结经验
- 自我提升
- 进行小项目的锻炼
- 对现有轮子的重构和移植
- 写技术博客
- 制作视频教程
- 学习PHP的知识和新特性
- 和同行直接沟通、交流
- 学好英语,走向国际
- 如何参与
- 浏览官网和极思维还有看云
- 回答ThinkPHP新手的问题
- 尝试发现ThinkPHP的bug,告诉官方人员或者push request
- 开发能提高效率的ThinkPHP工具
- 尝试翻译官方文档
- 帮新手入门
- 创造基于ThinkPHP的产品,进行连带推广
- 展望未来
- OneThink
- ThinkPHP4
- 附录