本文實作 Android 應用中使用 WebView 載入 OAuth 2.0 Implicit Grant 授權頁面,攔截重導向 URL 以提取 access_token,並處理 HTTPS 憑證錯誤。注意:行動裝置不建議使用 Authorization Code Grant,Implicit Grant 更適合無法安全儲存 Client Secret 的客戶端。
Activity,內嵌 WebView 載入授權 URLSerializable 供 Activity 傳遞public class OAuthV2AuthorizeWebView extends Activity {
public final static int RESULT_CODE = 2;
private OAuthV2 oAuth;
private WebView mWebView;
@SuppressLint("NewApi")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.webview_qq);
mWebView = findViewById(R.id.qq_mywebview);
mWebView.setVerticalScrollBarEnabled(false);
mWebView.setHorizontalScrollBarEnabled(false);
Intent intent = getIntent();
oAuth = (OAuthV2) intent.getSerializableExtra("oauth");
String urlStr = OAuthV2Client.generateImplicitGrantUrl(oAuth);
WebSettings settings = mWebView.getSettings();
settings.setJavaScriptEnabled(true);
settings.setSupportZoom(true);
mWebView.requestFocus();
mWebView.loadUrl(urlStr);
mWebView.setWebViewClient(new WebViewClient() {
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
if (url.contains("access_token=")) {
int start = url.indexOf("access_token=");
String responseData = url.substring(start);
OAuthV2Client.parseAccessTokenAndOpenId(responseData, oAuth);
Intent resultIntent = new Intent();
resultIntent.putExtra("oauth", oAuth);
setResult(RESULT_CODE, resultIntent);
finish();
}
super.onPageStarted(view, url, favicon);
}
// 處理 HTTPS 憑證錯誤(僅針對特定域名)
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
if (view.getUrl() != null && view.getUrl().startsWith("https://open.t.qq.com")) {
handler.proceed(); // 接受憑證
} else {
handler.cancel(); // 預設行為:取消載入
}
}
});
}
}
// 在呼叫端 Activity
Intent intent = new Intent(this, OAuthV2AuthorizeWebView.class);
intent.putExtra("oauth", oAuthInstance); // OAuthV2 實例
startActivityForResult(intent, MY_REQUEST_CODE);
// 接收結果
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == MY_REQUEST_CODE && resultCode == OAuthV2AuthorizeWebView.RESULT_CODE) {
OAuthV2 oAuth = (OAuthV2) data.getSerializableExtra("oauth");
// 取得 oAuth 中的 access_token、openid 等
}
}
| 項目 | 說明 |
|---|---|
| Implicit Grant 流程 | 授權伺服器直接在重導向 URL 片段(#access_token=...)中返回 token,無需後端換發 |
| URL 解析 | 在 onPageStarted 中檢查 URL 是否包含 access_token=,提取片段資料 |
| SSL 錯誤處理 | 僅對信任域名(open.t.qq.com)呼叫 handler.proceed(),其餘取消,避免中間人攻擊風險 |
| Activity 結果傳遞 | 使用 setResult() 將填充好 token 的 OAuthV2 物件回傳給呼叫端 |
state,回調時驗證防止 CSRF 攻擊。access_token 後應加密儲存(如 EncryptedSharedPreferences),避免明文寫入 SharedPreferences。原文標題錯誤提示:原標題為「java中應用DES加密解密實例」,但實際內容為 Android WebView OAuth 實作。本文已依實際內容重寫標題與內文。