本身轉載一下本身吧,省得被盜了,貼過來樣式都亂了,歡迎你們看原文http://trinea.iteye.com/blog/1290627javascript
本文主要介紹OAuth的用處、OAuth的流程、騰訊微博OAuth認證示例(新浪、人人相似)以及一些認證的異常。php
一、OAuth介紹java
目前不少主流的用戶權限認證都是用OAuth,像google、microsoft、yahoo、人人、新浪微博、騰訊微博。只不過各自使用的OAuth版本可能略有不一樣。android
使用OAuth的一個好處就是在用戶向服務器數據請求時,避免了每次都須要傳輸用戶名和密碼,經過access token和secret使得用戶在正常訪問數據的同時保證了用戶賬號的安全性。web
OAuth比較適合的web應用程序和提供服務器端api或者二者混合的場景,OAuth支持目前大部分的主流語言。數據庫
更多關於OAuth見:http://www.oauth.netapi
二、OAuth流程安全
OAuth的流程最終的結果是爲了獲得能夠訪問數據的access token和ccess secret(可能沒有),之後就經過此access token和access secret和服務器進行交互。服務器
大體的流程分爲三步(OAuth1.0和2.0可能有點差別):app
a 先得到一個未受權的request token,或者叫request code
b 以上步的未受權的token換取受權的request token和request secret(可能沒有),這一步以後通常會提示輸入用戶名、密碼
c 使用上步受權後的request token換取access token和access secret(可能沒有)
如今就獲得了access token和ccess secret(可能沒有),使用它們就能夠同服務器交互訪問數據,而不用每次傳遞用戶名和密碼
三、騰訊微博OAuth api介紹
目前騰訊微博使用的是OAuth1.0、新浪微博使用的是OAuth2.0、人人網使用的是OAuth2.0,這裏只介紹騰訊微博,關於人人和新浪相似,你們能夠本身修改。
因本身寫的騰訊微博sdk中默認不帶oauth認證過程,很多朋友問到如何進行認證,這裏就大體貼代碼介紹下,有點長,可看下大概明白意思,本身再根據須要精簡。主要分爲三個部分:
第一部分:調用認證函數,跳轉到認證頁面
認證函數以下
- private static QqTSdkService qqTSdkService = new QqTSdkServiceImpl();
-
- /**
- * OAuth部分參見http://wiki.open.t.qq.com/index.php/API%E6%96%87%E6%A1%A3#category_1
- */
- @Override
- public Intent auth(Context context, String callBackUrl) {
- Intent intent = new Intent();
- Bundle bundle = new Bundle();
- QqTAppAndToken qqTAppAndToken = new QqTAppAndToken();
- qqTAppAndToken.setAppKey(APP_KEY);
- qqTAppAndToken.setAppSecret(APP_SECRET);
- qqTSdkService.setQqTAppAndToken(qqTAppAndToken);
- Map<String, String> requestTokenMap = qqTSdkService.getUnAuthorizedRequestToken(callBackUrl);
- if (!MapUtils.isEmpty(requestTokenMap) && requestTokenMap.containsKey(QqTConstant.PARA_OAUTH_TOKEN)) {
- Map<String, String> parasMap = new HashMap<String, String>();
- parasMap.put(QqTConstant.PARA_OAUTH_TOKEN, requestTokenMap.get(QqTConstant.PARA_OAUTH_TOKEN));
- bundle.putString(SnsConstant.OAUTH_URL,
- HttpUtils.getUrlWithParas(QqTConstant.GET_AUTHORIZATION_URL, parasMap));
- bundle.putString(SnsConstant.CALL_BACK_URL, callBackUrl);
- bundle.putString(SnsConstant.REQUEST_TOKEN_SECRET, requestTokenMap.get(SnsConstant.REQUEST_TOKEN_SECRET));
- intent.putExtras(bundle);
- intent.setClass(context, OAuthWebViewActivity.class);
- }
- return intent;
- }
a. 兩個參數第一個爲activity中getApplicationContext();獲得的context
第二個爲認證成功返回的url,對於android的activity格式爲"appName://activityClassName",其中appname
爲應用名,activityClassName爲activity的類名。爲了認證後能正確跳轉到activity,須要在AndroidManifest.xml中添加相應的activity的intent-filter以下,至關於host配置
- <intent-filter>
- <data android:scheme="appName" android:host="activityClassName" />
- </intent-filter>
b. QqTSdkService、MapUtils、QqTConstant、HttpUtils的引用見騰訊微博java(android) api
c. SnsContant 中的一些常量定義以下
- /** 程序中用到的一些字符串常量 **/
- public static final String WEBSITE_TYPE = "websiteType";
- public static final String OAUTH_URL = "oAuthUrl";
- public static final String CALL_BACK_URL = "callBackUrl";
- public static final String REQUEST_TOKEN_SECRET = "oauth_token_secret";
- public static final String STATUS_ID = "statusId";
- public static final String COMMENT_TYPE = "commentType";
- public static final String COMMENT_ID = "commentId";
d. OAuthWebViewActivity的就是認證頁面,代碼見第二部分
activity中調用認證函數
- Intent intent = auth(context, "appName://activityClassName");
- if (intent == null || intent.getExtras() == null
- || !intent.getExtras().containsKey(SnsConstant.CALL_BACK_URL)) {
- // Toast.makeText(this, "進入認證頁面失敗", Toast.LENGTH_SHORT).show();
- return;
- } else {
- startActivity(intent);
- }
第二部分:進入認證頁面
OAuthWebViewActivity的代碼以下,就是一個webview加載受權頁面
a. R.layout.web_view爲
- <?xml version="1.0" encoding="utf-8"?>
- <ScrollView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
- <WebView
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:id="@+id/authWebView">
- </WebView>
- </ScrollView>
b. CodeRules.getActivityClass(CodeRules.getActivityNameFromUrl(callBackUrl));做用是從url中得到到activity對應的類,方便在跳轉回activity,即根據"appName://activityClassName"獲得activityClassName的Class
c. public void onPageStarted(WebView webView, String url, Bitmap favicon)表示監聽webView頁面開始加載事件
if (url != null && url.startsWith(callBackUrl)) 表示認證已經成功,開始加載callBackUrl("appName://activityClassName"),這個時候咱們讓它跳轉到對應的activity,這個時候的url中已經包含了accessToken和accessSecret
在第一部分startActivity後跳轉到認證頁面,填入賬號和密碼並點擊受權即可進入上面c的onPageStarted,這個時候咱們已經獲得了accessToken和accessSecret
第三部分 認證返回處理
在返回的activity中添加OnNewIntent函數,須要在AndroidManifest.xml中添加相應的activity的屬性android:launchMode="singleTask"
- @Override
- protected void onNewIntent(Intent intent) {
- super.onNewIntent(intent);
-
- Bundle bundle = intent.getExtras();
- if (bundle != null) {
- UserInfo userInfo = authBack(intent.getData(), bundle.getString(SnsConstant.REQUEST_TOKEN_SECRET));
- if (userInfo != null) {
- Toast.makeText(this, "獲取用戶信息失敗,請從新驗證", Toast.LENGTH_SHORT).show();
- OAuthWebViewActivity.webInstance.finish();
- } else {
- Toast.makeText(this, "獲取用戶信息失敗,請從新驗證", Toast.LENGTH_SHORT).show();
- }
- }
- }
其中authBack函數以下
- @Override
- public UserInfo authBack(Uri uri, String requestTokenSecret) {
- if (uri == null) {
- return null;
- }
-
- QqTAppAndToken qqTAppAndToken = new QqTAppAndToken();
- qqTAppAndToken.setAppKey(SnsConstant.QQT_APP_KEY);
- qqTAppAndToken.setAppSecret(SnsConstant.QQT_APP_SECRET);
- qqTSdkService.setQqTAppAndToken(qqTAppAndToken);
- Map<String, String> requestTokenMap = qqTSdkService.getAuthorizedRequestToken(uri.getQuery());
- if (MapUtils.isEmpty(requestTokenMap) || !requestTokenMap.containsKey(QqTConstant.PARA_OAUTH_TOKEN)
- || !requestTokenMap.containsKey(QqTConstant.PARA_OAUTH_VERIFIER)) {
- return null;
- }
- Map<String, String> accessTokenMap = qqTSdkService.getAccessToken(requestTokenMap.get(QqTConstant.PARA_OAUTH_TOKEN),
- requestTokenMap.get(QqTConstant.PARA_OAUTH_VERIFIER),
- requestTokenSecret);
- if (!MapUtils.isEmpty(accessTokenMap) || accessTokenMap.containsKey(QqTConstant.PARA_OAUTH_TOKEN)
- || accessTokenMap.containsKey(QqTConstant.PARA_OAUTH_TOKEN_SECRET)) {
- return UserInfoUtils.createUserInfo(websiteType, null, accessTokenMap.get(QqTConstant.PARA_OAUTH_TOKEN),
- accessTokenMap.get(QqTConstant.PARA_OAUTH_TOKEN_SECRET));
- }
-
- return null;
- }
a. UserInfo類代碼以下
b. createUserInfo代碼以下
- public static UserInfo createUserInfo(String websiteType, String... userInfo) {
- if (ArrayUtils.isEmpty(userInfo)) {
- return null;
- }
-
- UserInfo user = new UserInfo();
- user.setUserId((userInfo.length > 0 && userInfo[0] != null) ? userInfo[0] : websiteType);
- user.setAccessToken(userInfo.length > 1 ? userInfo[1] : null);
- user.setAccessSecret((userInfo.length > 2 && userInfo[2] != null) ? userInfo[2] : websiteType);
- user.setWebsiteType(websiteType);
- return user;
- }
到此大功告成,若是想使用騰訊微博android sdk,請見http://trinea.iteye.com/blog/1299505
四、其餘
騰訊微博認證異常
向https://open.t.qq.com/cgi-bin/request_token獲取未受權的access token出現以下異常
- java.lang.Exception: javax.net.ssl.SSLHandshakeException: org.bouncycastle.jce.exception.ExtCertPathValidatorException: Could not validate certificate signature.
緣由應該是以上請求的ssl證書已經不可用,將https改成http便可,如http://open.t.qq.com/cgi-bin/request_token