編輯:Android開發實例
為了能安全地訪問在線服務,必須要驗證用戶的身份,即需要用戶提供證明自己身份的認證信息。 如果一個應用程序要訪問第三方服務提供商的數據,那麼安全驗證問題更加復雜,此時不僅需要驗證用戶的身份信息,還要驗證應用程序的信息,以此來保證應用程序只能訪問獲得了用戶授權的那部分服務和數據。
目前用來解決應用程序和第三方服務提供商授權認證的標准協議是 OAuth2,它本身只提供了一個值,即授權令牌(auth token)。 它代表了用戶的授權和應用程序按照用戶授權的范圍能夠進行的數據訪問與操作。 本節課展示了怎樣通過 OAuth2 協議來認證和訪問 Google 的一個服務(服務方必須支持 OAuth2 協議), 雖然本節課的例子只是針對 Google Service,其他的任何第三方服務提供商只要支持 OAuth2 協議, 本文中提到的技術解決方案也同樣適用。
使用 OAuth2 的優勢:
開始進行 OAuth2 認證之前,您首先需要獲得服務方提供的 API 信息,具體包括:
獲得訪問令牌的步驟參照下圖:
在要獲取訪問令牌之前,您首先要做的是在 manifest 文件中加入賬戶管理 ACCOUNT_MANAGER 權限。 如果要利用該令牌來訪問在線服務,您還需要網絡 INTERNET 權限。
加入的方法參見示例代碼:
<manifest ... > <uses-permission android:name="android.permission.ACCOUNT_MANAGER" /> <uses-permission android:name="android.permission.INTERNET" /> ... </manifest>
當權限加入完畢的時候,接下來的工作就是申請令牌了,通過調用方法 AccountManager.getAuthToken() 來獲取令牌。
特別注意,因為 AccountManager 中的很多方法都涉及到網絡連接,所以大部分方法都是異步調用,那麼也就意著,您不能只在一個方法中簡單按照 OAuth2 的認證流程來編寫程序,而是要拆分成一系列的回調函數(callbacks)來實現。
示例代碼:
AccountManager am = AccountManager.get(this); Bundle options = new Bundle(); am.getAuthToken( myAccount_, // Account retrieved using getAccountsByType() "Manage your tasks", // Auth scope options, // Authenticator-specific options this, // Your activity new OnTokenAcquired(), // Callback called when a token is successfully acquired new Handler(new OnError())); // Callback called if an error occurs
在上面的例子中,OnTokenAcquired 類實現了 AccountManagerCallback 接口。 AccountManager 會回調 OnTokenAcquired 類的 run() 方法,並傳遞一個包含 Bundle 的參數 AccountManagerFuture ,如果成功獲取到令牌,那麼該令牌信息就會保存在 Bundle 中。
示例代碼展示了如何從 Bundle 中取得已申請的令牌:
private class OnTokenAcquired implements AccountManagerCallback<Bundle> { @Override public void run(AccountManagerFuture<Bundle> result) { // Get the result of the operation from the AccountManagerFuture. Bundle bundle = result.getResult(); // The token is a named value in the bundle. The name of the value // is stored in the constant AccountManager.KEY_AUTHTOKEN. token = bundle.getString(AccountManager.KEY_AUTHTOKEN); ... } }
如果一切進展順利,那麼 Bundle 中就包含了合法的令牌值,您可以通過鍵值 KEY_AUTHTOKEN 直接拿到。不過,有時事情也沒有那麼順利,那麼需要我們多做如下工作。
第一次申請令牌失敗的原因可能有很多,比如:
對於前兩條錯誤,您可以通過簡單地顯示一條失敗信息通知用戶來優雅的解決。因為如果是網絡掉線或者是用戶不同意授權,您的應用程序也對此無能為力,所以也不必過多關注。對於後面的兩種情況,處理的時候比較復雜,設計良好的應用程序應當能夠自動處理此類錯誤。
第三種錯誤是缺少足夠的賬戶憑據信息(insufficient credentials),當這種錯誤出現的時候,AccountManagerCallback (前面示例代碼中實現的 OnTokenAcquired 類) 中的 Bundle 包含了 一個鍵值為 KEY_INTENT 的 Intent ,您可以通過查詢 Bundle 中是有沒有包含此鍵值來判斷是否出現了該錯誤,如果包含了,那麼也就意味著 OAuth2 認證過程還需要用戶的賬戶憑據信息(account credentials)才能繼續接下來的令牌獲取過程。
出現這種情況可能的原因有很多,或許是用戶第一次登陸該賬戶,也可能是用戶的賬戶登錄超時了,需要重新登錄, 也有可能是用戶的賬戶憑據信息(account credentials)錯誤,又或者是用戶賬戶啟用了兩因素認證(two-factor authentication)機制, 也有可能是需要啟動照相機來進行視網膜掃描認證。但是不管是哪種具體類型的失敗原因,如果您的應用程序需要獲得一個合法的訪問令牌,那就必須將該 Intent 通知給系統,並且捕獲它的返回結果。
示例代碼:
private class OnTokenAcquired implements AccountManagerCallback<Bundle> { @Override public void run(AccountManagerFuture<Bundle> result) { ... Intent launch = (Intent) result.get(AccountManager.KEY_INTENT); if (launch != null) { startActivityForResult(launch, 0); return; } } }
請注意在上例中使用的是 startActivityForResult(),那麼您就可以在自己的 Activity 中通過實現 onActivityResult() 方法來獲得該 Intent 的處理結果。 這一點非常重要,如果您不捕獲該 Intent 的處理結果,就不能知道用戶是否進行正常認證了。 假如返回的結果為 RESULT_OK, 那麼賬戶憑據(account credentials)信息已經更新,現在有足夠的憑據信息來進行接下來的獲取訪問令牌的過程了,您可以通過再次調用 AccountManager.getAuthToken() 方法來獲取新的令牌。
對於最後一種情況令牌的過期,准確來說,這並不算是一種 AccountManager 的錯誤。 出現此種錯誤的唯一地方是利用該令牌訪問在線服務。 如果要通過利用 AccountManager 來依次訪問所有的在線服務,並循環檢查所有已存儲的令牌是否過期的方法是浪費時間的,代價也比較大。所以,好的解決方法是,當您的應用程序在訪問在線服務的時候,捕獲這個錯誤,如果發現令牌過期了,重新申請一個新的即可。 具體的申請流程可以參見上面講解。
下面的示例展示了如何訪問 google 在線服務。因為 Google 服務的認證是基於標准的 OAuth2 機制,所以這裡討論的技術是廣泛適用的。請記住,雖然每個服務提供方可能各不相同,但只要您按照自己的具體情況略作修改即可。
利用 Google APIs 訪問 Google 服務,每一次的Http請求,您都需要提供四個值,分別是 API key, client ID, client secret, 和 auth key. 前三個值可以從Google API Console 獲得,最後一個值,即訪問令牌,通過 AccountManager.getAuthToken() 獲得。
You pass these to the Google Server as part of an HTTP request.
示例代碼:
URL url = new URL("<a href="https:[email protected]/lists?key">https:[email protected]/lists?key</a>=" + your_api_key); URLConnection conn = (HttpURLConnection) url.openConnection(); conn.addRequestProperty("client_id", your client id); conn.addRequestProperty("client_secret", your client secret); conn.setRequestProperty("Authorization", "OAuth " + token);
如果上面的請求結果返回 401 錯誤,那麼表明您的訪問令牌(Token)是無效的。 像上面提到的第四種錯誤類型,很可能是令牌過期了。解決這個問題非常簡單,首先調用AccountManager.invalidateAuthToken() 刪除本地緩存的無效令牌,然後調用 AccountManager.getAuthToken() 獲取一個新的令牌即可。
因為令牌過期是一個很普遍的情況,解決它也比較容易,很多應用程序只是在每次獲取新令牌之前都先將本地令牌設置為過期並清除。對於服務提供商來說,如果申請一個令牌的操作代價比較小,那麼您的應用程序可以在第一次調用獲取令牌的方法 AccountManager.getAuthToken() 之前,也先調用清除無效令牌的方法 AccountManager.invalidateAuthToken() 。
參考文摘:
http://developer.android.com/training/id-auth/authenticate.html
原文:http://blog.zhourunsheng.com/2012/01/android-%e7%94%a8%e6%88%b7%e7%ae%a1%e7%90%86%e4%b8%93%e9%a2%98%e4%b9%8b%e5%9f%ba%e4%ba%8eoauth2%e5%8d%8f%e8%ae%ae%e7%9a%84%e6%9c%8d%e5%8a%a1%e8%ae%a4%e8%af%81/ | 潤物無聲
學習目的: 1、掌握在Android中如何建立RadioGroup和RadioButton 2、掌握RadioGroup的常用屬性 3、理解RadioButton
在軟件開發過程中,程序代碼的復用,是非常重要的概念。我們總是需要使用一些現有的模塊、包、框架,或開發自己的模塊、包、框架,來實現對程序代碼的復用。比如在JavaW
Android提供了許多方法來控制播放的音頻/視頻文件和流。其中該方法是通過一類稱為MediaPlayer。Android是提供MediaPlayer類訪問內置的媒體播放
在5.2.1節和5.2.2節介紹了<a>標簽以及TextView自動識別的特殊文本(網址、電話號、Email等),這些都可以通過單擊來觸發不同的動作。