在這個充滿SSO(Single Sign-On)的時代,社交登錄已經成為我們網路日常的一部分。隨著互聯網和應用程式的快速發展,我們需要在各種網站和應用上創建帳戶並記住一長串的帳號和密碼已經變得非常繁瑣和不便。而SSO和OpenID Connect的出現,為我們帶來了一種更便捷、更安全的登入方式,因此SSO和OpenID Connect似乎變成每個網頁和應用所必備的功能呢!在這篇文章將會記錄我是如何在Ionic&Capacitor上實現Social Login的功能,讓我們開始吧!



專案準備

首先當然是要先有個Ionic&Capacitor的專案,專案的建置之前的文章有示範如何建立可以【點我前往】參考,範例程式碼的css都會使用Tailwind有需要的人可以自行前往安裝【點我前往】接著下面所有的OAuth2.0流程我會使用第三方的開源套件作為示範【點我前往Github】,使用以下指令安裝套件
npm i @byteowls/capacitor-oauth2
再來就是準備一個可以互動的畫面和社交登入按鈕
<button
  class="mt-5 w-full bg-white text-gray-700 hover:bg-gradient-to-r hover:from-blue-600 hover:to-indigo-600 hover:text-white focus:outline-none focus:shadow-outline"
  type="button" (click)="onGoogleLoginClick()">
  <div class="rounded border border-gray-300 flex flex-row items-center justify-center py-2 px-4">
    <img src="assets/icon/google-login-icon.svg" width="24" height="24" class="mr-2" />
    <span class="text-sm font-bold">使用 Google 帳戶登入</span>
  </div>
</button>
<button
  class="mt-5 w-full bg-white text-gray-700 hover:bg-gradient-to-r hover:from-blue-600 hover:to-indigo-600 hover:text-white focus:outline-none focus:shadow-outline"
  type="button" (click)="onMicrosoftLoginClick()">
  <div class="rounded border border-gray-300 flex flex-row items-center justify-center py-2 px-4">
    <img src="assets/icon/microsoft-login-icon.svg" width="24" height="24" class="mr-2" />
    <span class="text-sm font-bold">使用 Microsoft 帳戶登入</span>
  </div>
</button>



OAuth設定 - Google

首先到Google Cloud API登入後點擊「控制台」進入

第一次進入時先建立一個新的專案,在「選取專案」的地方打開後即可看到「新增專案」的按鈕


建立完成後在左側的選單中找到「API和服務」,接著一樣左邊選單會看到「OAuth同意畫面」,進去後在User Type的設定選擇「外部」後按下「建立」

在Step 1. OAuth同意畫面中,由於這個應用程式是Demo用的,因此我只會填寫必要的欄位,填寫完畢後就可以「儲存並繼續」

在Step 2. 範圍中,將會設定一些需要使用者授權的權限,這裡我們添加三個權限「email」「profile」「openid」即可

在Step 3.測試使用者中,在你的應用程式未發佈前可以設定特定的測試人員提供使用

在Step 4.摘要就設定完成了!接著來到左側選單「憑證」的地方,在上方點擊「建立憑證」「OAuth用戶端ID」

在應用程式類型中,我們要建立兩個,一個是「網頁應用程式」,另一個是「Android」,這兩個設定的方式不一樣因此我會分開來介紹。
💡 由於我多數時間還是會用Web的方式去開發Ionic&Capacitor的應用程式,因此才會把網頁應用程式也納入設定的範圍內


網頁應用程式

網頁應用程式需要設定「已授權的JavaScript來源」和「已授權的重新導向URL」,這裡我們就直接加入開發時的http://localhost即可

建立完成後就可以看到Client Id和Client Secret了!

Android

建立Android時需要填入「套件名稱」以及「SHA-1憑證指紋」

套件名稱可以在Ionic專案的capacitor.config.ts裡面找到,或是AndroidManifest.xml裡面也有

而SHA-1憑證指紋則是需要從keystore計算得來的,我們可以使用以下指令找到SHA-1
keytool -list -v -keystore %HOMEPATH%/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android
💡 keytool工具只要安裝Java JDK就會有
💡 這裡我們使用keystore是開發環境的debug.keystore,生產環境下記得替換成正確的keystore哦!
💡 如果在Windows上,這段指令不適合執行在PowerShell上哦!

把SHA-1帶入後按下建立即可完成,Google的設定到這邊就全部完成!



OAuth設定 - Microsoft

微軟的應用程式設定可以參考我之前寫的文章【點我前往】,這裡我會直接針對不一樣的地方做說明。
首先在「API權限」的地方點擊「新增權限」

「Microfost Graph」「委派的權限」,跟Google一樣把「email」「profile」「openid」都打勾後儲存,權限的部分完成了

接著到找到左側選單「驗證」「平台設定」「新增平台」,這裡一樣新增兩個平台「單頁應用程式」「Android」

單頁應用程式

單頁應用程式(SPA)通常使用隱式授權流程(Implicit Grant Flow)或授權代碼流程與 PKCE (Proof Key for Code Exchange)。這些流程都是在前端JavaScript代碼中執行的,並且直接返回到應用程式的安全令牌,我們專案是Ionic基於Angular因此也是一個SPA。相反,Web應用程式通常使用授權代碼流程(Authorization Code Grant Flow),該流程涉及到後端伺服器,並且會將授權代碼返回到後端,然後後端會換取安全令牌,所以這兩個在授權的流程上會有點不同哦!

Android

而Android上的設定跟Google一樣需要提供「套件名稱」,而這裡的簽章雜湊就不同於Google,它是把SHA-1轉成二進制後再Base64編碼,因此指令上也會有些許不同,我們使用以下命令
keytool -exportcert -alias androiddebugkey -keystore %HOMEPATH%\.android\debug.keystore | openssl sha1 -binary | openssl base64
💡 這裡需要OpenSSL的工具,可以【點我前往】安裝

產生完雜湊後貼上,Microsoft的設定就結束了!



Social Login

講了這麼多終於來到這篇的主題了XD,接下來就照著Github上面寫的建立Google和Microsoft的「OAuth2AuthenticateOptions」的物件吧!

Google

在Github提供的Google OAuth2AuthenticateOptions設定中的Scope需要加入「openid」,另外在web屬性下的responseType的地方我們需要多加一個「id_Token」 才可以正確取得OpenID哦!
private getGoogleOAuth2Options(): OAuth2AuthenticateOptions {
  return {
    authorizationBaseUrl: 'https://accounts.google.com/o/oauth2/auth',
    accessTokenEndpoint: "https://www.googleapis.com/oauth2/v4/token",
    scope: "email profile openid",
    resourceUrl: "https://www.googleapis.com/userinfo/v2/me",
    logsEnabled: true,
    web: {
      appId: 'Your Google Client Id',
      responseType: 'id_token token', // implicit flow
      accessTokenEndpoint: '', // clear the tokenEndpoint as we know that implicit flow gets the accessToken from the authorizationRequest
      redirectUrl: "http://localhost:8100",
      windowOptions: "width=500,height=600"
    },
    android: {
      appId: 'Your Google Client Id',
      responseType: "code", // if you configured a android app in google dev console the value must be "code"
      redirectUrl: "sociallogin.test.app:/" // package name from google dev console
    },
    ios: {
      appId: 'Your Google Client Id',
      responseType: "code", // if you configured a ios app in google dev console the value must be "code"
      redirectUrl: "sociallogin.test.app:/" // Bundle ID from google dev console
    }
  };
}
💡 在google的web屬性中請不要使用responseType=code,由於web的驗證流程都在前端Javascript上執行,code流程本身是需要Client Secret(你也不會希望把你的Client Secret放到JavaScrip上吧XD),OAuth2AuthenticateOptions物件本身也沒有地方給你設定Client Secret,另外就算打開PKCE的驗證方式也是無法通過Token驗證(可能是Google不提供PKCE的流程)哦!
💡 開發階段可以把logsEnabled打開,可以在Console看到跑了哪些流程,有助於自己理解OAuth的過程哦!


Microsoft

而Github提供的Microsoft OAuth2AuthenticateOptions設定也是在Scope屬性多加「openid」,其餘的都不用改哦!
private getAzureB2cOAuth2Options(): OAuth2AuthenticateOptions {
  return {
    appId: 'Your Microsoft Client Id',
    authorizationBaseUrl: 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize',
    scope: 'https://graph.microsoft.com/.default openid',
    accessTokenEndpoint: 'https://login.microsoftonline.com/common/oauth2/v2.0/token',
    resourceUrl: "https://graph.microsoft.com/v1.0/me/",
    responseType: "code",
    pkceEnabled: true,
    logsEnabled: true,
    web: {
      redirectUrl: 'http://localhost:8100',
      windowOptions: "width=500,height=600",
    },
    android: {
      redirectUrl: "msauth://sociallogin.test.app/URKPrDTU8V1MeU...." // See Azure Portal -> Authentication -> Android Configuration "Redirect URI"
    },
    ios: {
      pkceEnabled: true, // workaround for bug #111
      redirectUrl: "msauth.{package-name}://auth"
    }
  };
}
💡 Microsoft只能設定responseType=code,並且搭配PKCE做驗證哦!

最後在ButtonOnClick的地方呼叫OAuth2Client.authenticate就完成囉!
onMicrosoftLoginClick() {
  OAuth2Client.authenticate(
    this.getAzureB2cOAuth2Options()
  ).then(result => console.log(result));
}

onGoogleLoginClick() {
  OAuth2Client.authenticate(
    this.getGoogleOAuth2Options()
  ).then(result => console.log(result));
}
設定完後就可以執行SSO,完成OAuth流程後就可以從Console看到取得的id_Token

來到Android上編譯完後在模擬器上執行後也在Logcat上看到取得的id_Token!



最後gif動畫展示一下


總結

在這篇我們利用開源的第三方套件Capacitor OAuth2.0實作了OpenID Connect的SSO登入,實際上OpenID Connect本身也是從OAuth2.0去做設計的,因此實作時就跟OAuth幾乎一模一樣呢XD,另外OpenID Connect還有其它的流程可以參考,每一個流程在執行上都有些微的不同,在Github有提供一個網址介紹這些流程我覺得講的很清楚,有興趣的可以【點我前往】參考看看哦!