## 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由于審核比較嚴格,我們只做演示流程,新浪的夠用了。



由于新浪提交要 備案,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());
}
~~~
### 處理回調
回調的參數都一樣,如下圖四個。

~~~
//授權回調地址
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.#/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
- 附錄