驗證使用者

為使用者建立登入流程,並使用 Firebase 驗證,用個人資料資訊為使用者提供個人化功能。

本頁與範例是簡易網誌應用程式之延伸學習範例的一部分,此網誌應用程式可讓使用者上傳貼文。您應該已經熟悉 Go 程式設計語言和基本的網路開發。如要從頭開始,請前往透過 Go 建構應用程式

費用

執行本教學課程不會產生相關費用。執行這個範例應用程式也不會超過您的免費配額

事前準備

如果您已經完成透過 Go 建構應用程式指南,請跳過本節。如否,請完成下列步驟:

  1. 完成設定您的專案和應用程式中的事前準備工作。

  2. 在本範例中,請將程式碼新增至 gophers-4 範例,也就是從儲存資料所產生的最終成果。

    下載 gophers-4 範例及其相依項到您的本機電腦:

    go get -u -d github.com/GoogleCloudPlatform/golang-samples/appengine/gophers/gophers-4/...
    
  3. 切換至 gophers-4 目錄:

    cd $GOPATH/src/github.com/GoogleCloudPlatform/golang-samples/appengine/gophers/gophers-4
    

結構化您的應用程式

本範例專案的結構如下:

  • go-app/:專案根目錄。

    • app.yaml:App Engine 應用程式的配置設定。
    • main.go:應用程式的程式碼。
    • index.html:用以顯示您首頁的 HTML 範本。
    • static/:儲存靜態檔案的目錄。
      • style.css:用以設定 HTML 檔案外觀格式的樣式表。
      • gcp-gopher.svg:Gopher 圖片。
      • index.js:設定 Firebase 驗證的使用者介面並處理驗證要求。

將 Firebase 新增到您的專案

如何設定 FirebaseUI 並啟用登入供應商:

  1. 將 Firebase 資料庫新增至 main.go 中的匯入作業清單:

    firebase "firebase.google.com/go"

  2. 完成將 Firebase 新增到您的應用程式,包括將初始化程式碼片段新增到 index.html

  3. Firebase 主控台中按一下 [驗證] > [登入方式],啟用您要提供給使用者進行驗證的供應商。然後,在「登入供應商」下方,將游標懸停在供應商上方,按一下鉛筆圖示。

    登入供應商

  4. 開啟 [啟用] 按鈕,然後針對第三方識別資訊提供者,輸入取自供應商開發人員網站的供應商 ID 和密鑰。Firebase 文件會提供 FacebookTwitterGitHub 指南「事前準備」小節中的特定操作說明。啟用供應商後,按一下 [儲存]

    開啟啟用按鈕

  5. 在 Firebase 主控台的同一頁面上,於「已授權網域」底下,按一下 [新增網域],並以下列格式輸入您的應用程式在 App Engine 上的網域:

    [PROJECT_ID].appspot.com
    

    在網域名稱前請勿加上 http://

  6. firebaseConfig 變數新增到 main.go 的變數清單中,然後從您在 Firebase 主控台中產生的初始化程式碼片段更新資料庫網址、專案 ID 和儲存值區資訊:

    var (
    	firebaseConfig = &firebase.Config{
    		DatabaseURL:   "https://console.firebase.google.com > Overview > Add Firebase to your web app",
    		ProjectID:     "https://console.firebase.google.com > Overview > Add Firebase to your web app",
    		StorageBucket: "https://console.firebase.google.com > Overview > Add Firebase to your web app",
    	}
    	indexTemplate = template.Must(template.ParseFiles("index.html"))
    )
    

    Config 類型代表用於初始化新 Firebase 應用程式的配置。

  7. index.html 中的自訂初始化程式碼片段下方,將下列指令碼和 CSS 檔案包含在您頁面的 <head> 標記中:

    <script src="https://cdn.firebase.com/libs/firebaseui/2.6.2/firebaseui.js"></script>
    <link type="text/css" rel="stylesheet" href="https://cdn.firebase.com/libs/firebaseui/2.6.2/firebaseui.css" />

  8. 將下列樣式新增到 style.css 檔案,以顯示使用者的登入進度:

    div.mdl-progress::after {
      display: block;
      content: 'Authenticating...';
      margin: 30px auto;
      text-align: center;
    }

  9. 在含有您針對驗證所選取之供應商的 index.html 內文中,新增一個空白的 <div> 標記:

    <div id="firebaseui-auth-container"></div>

  10. index.html 的內容中,再加入一個 <div> 標記,以顯示使用者的帳戶資訊和 [登出] 按鈕,此按鈕在使用者登入之前會隱藏起來。

    <div id="sign-in"></div>
    <div>
      <span id="account-details"></span>
      <button id="sign-out" hidden=true>Sign Out</button>
    </div>

  11. 將 ID、隱藏屬性和符記輸入新增到 <form> 元素:

    <form id="post-form" action="/" method="post" hidden=true>
      <div>Message: <input name="message" value="{{.Message}}"></div>
      <input type="hidden" name="token" id="token">
      <input type="submit">
    </form>

驗證使用者

在這個應用程式中,使用者將遵循下列流程來登入並張貼訊息:

  1. 使用者按一下以登入特定供應商。
  2. index.js 程式碼將登入要求傳送到 Firebase。
  3. Firebase 傳回使用者資訊和 ID 符記,以更新表單和網頁中的項目,以顯示目前已登入的使用者。
  4. 使用者接著建立訊息,並將貼文提交到您的應用程式,進而傳送到 App Engine 伺服器。
  5. 伺服器從表單提取 ID 符記,並傳送到 Firebase 以接收與 ID 符記關聯的使用者資訊。
  6. Firebase 將使用者資訊送回 App Engine 伺服器,藉此儲存含有使用者資訊的貼文到 Cloud Datastore 中。

從 Firebase 取得使用者資訊

前端 JavaScript 程式碼會從 Firebase 取得使用者電子郵件、名稱、照片及附加的符記。為確保惡意使用者無法更動附加至訊息的使用者資訊,符記只會隨同貼文傳送。符記是識別使用者身分的安全方式。應用程式伺服器則使用符記取得使用者資訊。

  1. 在您專案的 static 資料夾中建立 index.js

  2. 新增使用者載入頁面時的事件監聽器。所有的 JavaScript 程式碼會放置在這個事件監聽器的內部。

  3. 將處理常式新增到會呼叫 Firebase signOut 函式的 [登出] 按鈕。

  4. 選取您要提供給使用者的供應商,以設定 FirebaseUI 登入小工具。此提供者應與您之前在 Firebase 主控台指定的已啟用登入供應商清單一致:

    // FirebaseUI config.
    var uiConfig = {
      signInSuccessUrl: '/',
      signInOptions: [
        // Leave the lines as is for the providers you want to offer your users.
        firebase.auth.GoogleAuthProvider.PROVIDER_ID,
        firebase.auth.FacebookAuthProvider.PROVIDER_ID,
        firebase.auth.TwitterAuthProvider.PROVIDER_ID,
        firebase.auth.GithubAuthProvider.PROVIDER_ID,
        firebase.auth.EmailAuthProvider.PROVIDER_ID,
        firebase.auth.PhoneAuthProvider.PROVIDER_ID
      ],
      // Terms of service url.
      tosUrl: '<your-tos-url>'
    };

  5. 透過 onAuthStateChanged() 接聽器,從 Firebase 處理使用者登入或登出時會觸發的驗證要求:

    firebase.auth().onAuthStateChanged(function (user) {
      if (user) {
        // User is signed in.
        document.getElementById('sign-out').hidden = false;
        document.getElementById('post-form').hidden = false;
        document.getElementById('account-details').textContent =
            'Signed in as ' + user.displayName + ' (' + user.email + ')';
        user.getIdToken().then(function (accessToken) {
          // Add the token to the post form. The user info will be extracted
          // from the token by the server.
          document.getElementById('token').value = accessToken;
        });
      } else {
        // User is signed out.
        // Initialize the FirebaseUI Widget using Firebase.
        var ui = new firebaseui.auth.AuthUI(firebase.auth());
        // Show the Firebase login button.
        ui.start('#firebaseui-auth-container', uiConfig);
        // Update the login state indicators.
        document.getElementById('sign-out').hidden = true;
        document.getElementById('post-form').hidden = true;
        document.getElementById('account-details').textContent = '';
      }
    }, function (error) {
      console.log(error);
      alert('Unable to log in: ' + error)
    });

    當使用者成功登入時,Firebase 會隨之建立對應的 ID 符記,專用於識別該使用者。getIdToken 函式會從用戶端擷取 ID 符記,然後將它附加到 HTML 表單中。

  6. index.html 檔案中,於頁面的 <head> 標記中連結指令碼檔案:

    <script src="/static/index.js"></script>

在伺服器上驗證符記

在用戶端可以存取伺服器資料之前,伺服器必須先驗證該符記是否由 Firebase 簽署。每個登入識別資訊提供者都會傳送不同的一組宣告,但每組宣告都至少有含有唯一使用者 ID 的子宣告,以及用於提供某些個人資料資訊的宣告,如名稱或電子郵件,以對應用程式的使用者體驗進行個人化處理。

  1. UserID string 欄位新增至 main.goPost 資料結構中:

    type Post struct {
    	Author  string
    	UserID  string
    	Message string
    	Posted  time.Time
    }
    

  2. indexHandler 函式中確認 r.Method 要求為 POST 後,建立新的 Firebase 應用程式來提供諸如 Firebase 驗證等 Firebase 服務的存取權。接著驗證 Firebase ID 符記,並在 App Engine 伺服器上使用 HTTPS 來識別目前登入的使用者:

    message := r.FormValue("message")
    
    // Create a new Firebase App.
    app, err := firebase.NewApp(ctx, firebaseConfig)
    if err != nil {
    	params.Notice = "Couldn't authenticate. Try logging in again?"
    	params.Message = message // Preserve their message so they can try again.
    	indexTemplate.Execute(w, params)
    	return
    }
    // Create a new authenticator for the app.
    auth, err := app.Auth(ctx)
    if err != nil {
    	params.Notice = "Couldn't authenticate. Try logging in again?"
    	params.Message = message // Preserve their message so they can try again.
    	indexTemplate.Execute(w, params)
    	return
    }
    // Verify the token passed in by the user is valid.
    tok, err := auth.VerifyIDTokenAndCheckRevoked(ctx, r.FormValue("token"))
    if err != nil {
    	params.Notice = "Couldn't authenticate. Try logging in again?"
    	params.Message = message // Preserve their message so they can try again.
    	indexTemplate.Execute(w, params)
    	return
    }
    // Use the validated token to get the user's information.
    user, err := auth.GetUser(ctx, tok.UID)
    if err != nil {
    	params.Notice = "Couldn't authenticate. Try logging in again?"
    	params.Message = message // Preserve their message so they can try again.
    	indexTemplate.Execute(w, params)
    	return
    }
    

  3. 更新 post 變數,從使用者資訊填入新的 UserIDAuthor 欄位:

    post := Post{
    	UserID:  user.UID, // Include UserID in case Author isn't unique.
    	Author:  user.DisplayName,
    	Message: message,
    	Posted:  time.Now(),
    }

  4. 由於登入後才能張貼訊息,所以請從 main.go 刪除下列幾行:

    if post.Author == "" {
      post.Author = "Anonymous Gopher"
    }
    

在本機執行您的應用程式

使用 Cloud SDK 隨附的本機開發伺服器 (dev_appserver.py),執行並測試您的應用程式。

  1. 在應用程式 app.yaml 所在的專案根目錄中,使用以下指令來啟動本機開發伺服器:

    dev_appserver.py app.yaml
    

    本機開發伺服器現已開始執行並監聽 8080 連接埠的要求。發生問題了嗎?

  2. 使用網路瀏覽器前往 http://localhost:8080/ 查看應用程式。

    最終

執行本機開發伺服器 (dev_appserver.py)

如要執行本機開發伺服器,您可以指定完整的目錄路徑來執行 dev_appserver.py,或是將 dev_appserver.py 新增至 PATH 環境變數:

  • 如果您安裝了原始 App Engine SDK,該工具位於以下路徑:

    [PATH_TO_APP_ENGINE_SDK]/dev_appserver.py
    
  • 如果您安裝了 Google Cloud SDK,該工具位於以下路徑:

    [PATH_TO_CLOUD_SDK]/google-cloud-sdk/bin/dev_appserver.py
    

    提示:如要將 Google Cloud SDK 工具新增至您的 PATH 環境變數,並在殼層中啟用 command-completion,您可以執行以下指令:

    [PATH_TO_CLOUD_SDK]/google-cloud-sdk/install.sh
    

如要進一步瞭解如何執行本機開發伺服器 (包括如何變更通訊埠編號),請參閱本機開發伺服器參考資料。

變更程式碼

本機開發伺服器會監視您的專案檔案變更,所以會在您變更程式碼之後,重新編譯並重新啟動您的應用程式。

  1. 立即嘗試:讓本機開發伺服器維持執行的狀態,然後試著編輯 index.html,將「The Gopher Network」改成其他內容。

  2. 重新載入 http://localhost:8080/,查看您變更的內容。

部署您的應用程式

使用下列指令,從 app.yaml 所在的專案根目錄,將您的應用程式部署到 App Engine:

gcloud app deploy

查看應用程式

如要啟動瀏覽器並前往 http://[YOUR_PROJECT_ID].appspot.com 查看您的應用程式,請執行下列指令:

gcloud app browse

清理

您在本教學課程中使用的資源可能會產生費用。如要避免系統向您的 Google Cloud Platform 帳戶收取這筆費用,請完成刪除 App Engine 專案步驟。

相關資源

恭喜!您已經建構好應用程式,並能使用 Firebase 驗證與使用者的電子郵件和密碼來驗證使用者。請瀏覽下列頁面,瞭解如何在您的應用程式新增其他功能:

本頁內容對您是否有任何幫助?請提供意見:

傳送您對下列選項的寶貴意見...

這個網頁
Go 適用的 App Engine 標準環境