情境
Google sign-in 是一種廣泛使用的 OAuth 認證,只需要透過 SDK 串接就可以輕易做好簡單認證,在 Android 可以透過 Firebase 更輕易完成 Google Sign-In 處理。
完整程式碼
如果你需要完整程式碼,可以到 GitHub 上觀看或下載。
說明
首先,透過以下流程操作。
- Android Studio 的 Tool -> Firebase -> Authentication -> Connect your app to Firebase & Add Firebase Authentication to your app
連結好了你的 app project 就會出現一個檔案叫做 google-service.json。
你也可以在 Firebase Console 看到相關資訊。
對以上流程想要知道更細節的描述,可以參考如何使用 Firebase - 用 Android Studio 建立帳戶篇 或者 官方教學。
連結好了以後,我們一開始就可以在 XML 上建立一個 Google Sign-In Button。
<com.google.android.gms.common.SignInButton
android:id="@+id/sign_in_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
這個神奇按鈕就幫我們包好了所有認證功能,只要你按下去,就會看到這樣的畫面。
讓使用者自己選擇要登入的帳號,只要這次登入以後,之後登入就不會再確認了。
接著我們來看一下怎麼使用這個按鈕,首先,先對這個按鈕設定事件。
sign_in_button.setOnClickListener {
signIn()
}
接著我們來看 signIn 這個方法內寫些什麼?
這邊我們可以要求多個東西,例如名字、email 或者 token,這邊我們故意設定兩個點,一個是 IdToken,另外一個是 Email,IdToken 相當於你的權限,如果你有自己的後台的話,就可以透過這個 IdToken 去跟 Google 要使用者的相關資料,因此,會牽扯到一些資安的問題,但是在我們這個範例內,只是單純示範拿一下 Token。
private fun signIn() {
val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken("google-service.json 內的 client_id")
.requestEmail()
.build()
//...
}
一開始透過 Builder 建立了一個 Option 的物件,透過這個物件就可以宣告以下的變數。
private fun signIn() {
//...
val mGoogleSignInClient = GoogleSignIn.getClient(this, gso)
val signInIntent = mGoogleSignInClient.signInIntent
startActivityForResult(signInIntent, RC_SIGN_IN)
}
是否有注意到?這邊有用到 startActivityForResult,這就代表著我們等下會透過 onActivityResult 來接東西,這邊就很單純的成功或失敗的判斷。
public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == RC_SIGN_IN) {
val task = GoogleSignIn.getSignedInAccountFromIntent(data)
try {
val account = task.getResult(ApiException::class.java)
val email = account?.email
val token = account?.idToken
Log.i("givemepass", "email:$email, token:$token")
Toast.makeText(this, getString(R.string.login_success), Toast.LENGTH_SHORT).show()
} catch (e: ApiException) {
Log.i("givemepass", "signInResult:failed code=" + e.statusCode)
Toast.makeText(this, getString(R.string.login_fail), Toast.LENGTH_SHORT).show()
}
} else{
Log.i("givemepass", "login fail")
Toast.makeText(this, getString(R.string.login_fail), Toast.LENGTH_SHORT).show()
}
}
這樣就大致上完成了登入的作業。
效果如下圖。
回到前面的 IdToken 能夠做什麼呢?
透過下面網址,再把 Id-Token 塞進去,就可以拿到個人資料。
https://www.googleapis.com/oauth2/v3/tokeninfo?id_token=拿到的token
把透過 Google Sign-In 拿到的 id_token 塞到上面網址列的 id_token 值,你就會發現可以拿到一堆相關資訊。
{
"iss": "https://accounts.google.com",
"azp": "878489384959-igk261ic4ut8u8fu8eu8f34dsjdjdjiw.apps.googleusercontent.com",
"aud": "878489384959-dgjcuehguhug434fji4jfijw4ifji494.apps.googleusercontent.com",
"sub": "859384953495934995943",
"email": "givemepassxd999@gmail.com",
"email_verified": "true",
"name": "givemepass",
"picture": "https://lh3.googleusercontent.com/a-/AAuE7mAS2z4RwoNTQlhtfjwet6ISdQ=s96-c",
"given_name": "givemepass",
"family_name": "givemepass",
"locale": "zh-TW",
"iat": "4990439504",
"exp": "49949690904",
"alg": "RS256",
"kid": "47456b8069e4365e517ca5e29434a9efa567ba",
"typ": "JWT"
}
是不是感到很危險呢?所以我們要很小心地保護好 Token,
這樣就是一個簡單的 Google Sign-In 的範例了。