เพิ่มการลงชื่อเข้าใช้ด้วย Google ลงในแอป iOS

1. ก่อนเริ่มต้น

Codelab นี้จะแนะนําวิธีสร้างแอปพลิเคชัน iOS ที่ใช้ฟีเจอร์ลงชื่อเข้าใช้ด้วย Google และทํางานในโปรแกรมจำลอง เราได้จัดเตรียมการติดตั้งใช้งานโดยใช้ทั้ง SwiftUI และ UIKit

SwiftUI เป็นเฟรมเวิร์ก UI ที่ทันสมัยของ Apple สำหรับการพัฒนาแอปใหม่ ซึ่งช่วยให้สร้างอินเทอร์เฟซผู้ใช้สำหรับแพลตฟอร์ม Apple ทั้งหมดจากฐานของโค้ดที่แชร์เดียวได้ โดยต้องใช้ iOS เวอร์ชัน 13 ขึ้นไป

UIKit เป็นเฟรมเวิร์ก UI ดั้งเดิมและพื้นฐานของ Apple สำหรับ iOS โดยจะมีความเข้ากันได้แบบย้อนหลังสำหรับ iOS เวอร์ชันเก่า จึงเป็นตัวเลือกที่ดีสำหรับแอปที่สร้างขึ้นแล้วซึ่งต้องรองรับอุปกรณ์รุ่นเก่าที่หลากหลาย

คุณสามารถทำตามเส้นทางสำหรับเฟรมเวิร์กที่สอดคล้องกับความต้องการในการพัฒนาของคุณมากที่สุด

ข้อกำหนดเบื้องต้น

  • ความรู้พื้นฐานเกี่ยวกับ Swift
  • ความรู้พื้นฐานเกี่ยวกับ SwiftUI หรือ UIKit

สิ่งที่คุณจะได้เรียนรู้

  • วิธีสร้างโปรเจ็กต์ Google Cloud
  • วิธีสร้างไคลเอ็นต์ OAuth ใน Google Cloud Console
  • วิธีติดตั้งใช้งานฟีเจอร์ลงชื่อเข้าใช้ด้วย Google สำหรับแอป iOS
  • วิธีปรับแต่งปุ่มลงชื่อเข้าใช้ด้วย Google
  • วิธีถอดรหัสโทเค็นรหัส
  • วิธีเปิดใช้ App Check สำหรับแอป iOS

สิ่งที่คุณต้องมี

  • Xcode เวอร์ชันล่าสุด
  • คอมพิวเตอร์ที่ใช้ macOS ซึ่งตรงตามข้อกำหนดของระบบสำหรับ Xcode เวอร์ชันที่คุณติดตั้ง

Codelab นี้สร้างขึ้นโดยใช้ Xcode 16.3 กับโปรแกรมจำลอง iOS 18.3 คุณควรใช้ Xcode เวอร์ชันล่าสุดในการพัฒนา

2. สร้างโปรเจ็กต์ Xcode ใหม่

  1. เปิด Xcode แล้วเลือกสร้างโปรเจ็กต์ Xcode ใหม่
  2. เลือกแท็บ iOS เลือกเทมเพลตแอป แล้วคลิกถัดไป

หน้าเทมเพลตการสร้างโปรเจ็กต์ Xcode

  1. ในตัวเลือกโปรเจ็กต์
    • ป้อนชื่อผลิตภัณฑ์
    • เลือกทีม (ไม่บังคับ)
    • ป้อนตัวระบุองค์กร
    • จดบันทึกตัวระบุชุดที่สร้างขึ้น เนื่องจากต้องใช้ในภายหลัง
    • สำหรับอินเทอร์เฟซ ให้เลือกตัวเลือกใดตัวเลือกหนึ่งต่อไปนี้
      • SwiftUI สำหรับแอปที่ใช้ SwiftUI
      • สตอรีบอร์ดสำหรับแอปที่ใช้ UIKit
    • เลือก Swift สำหรับภาษา
    • คลิกถัดไป แล้วเลือกตำแหน่งที่จะบันทึกโปรเจ็กต์

หน้าตัวเลือกโปรเจ็กต์ Xcode

3. สร้างไคลเอ็นต์ OAuth

หากต้องการอนุญาตให้แอปสื่อสารกับบริการตรวจสอบสิทธิ์ของ Google คุณต้องสร้างรหัสไคลเอ็นต์ OAuth ซึ่งต้องใช้โปรเจ็กต์ Google Cloud ขั้นตอนต่อไปนี้จะแนะนำกระบวนการสร้างโปรเจ็กต์และรหัสไคลเอ็นต์ OAuth

เลือกหรือสร้างโปรเจ็กต์ Google Cloud

  1. ไปที่ Google Cloud Console แล้วเลือกหรือสร้างโปรเจ็กต์ หากเลือกโปรเจ็กต์ที่มีอยู่แล้ว คอนโซลจะนำคุณไปยังขั้นตอนถัดไปที่จำเป็นโดยอัตโนมัติ

หน้าตัวเลือกโปรเจ็กต์ของ Google Cloud Console

  1. ป้อนชื่อโปรเจ็กต์ Google Cloud ใหม่
  2. เลือกสร้าง

หน้าตัวเลือกโปรเจ็กต์ของ Google Cloud Console

หากกำหนดค่าหน้าจอขอความยินยอมสำหรับโปรเจ็กต์ที่เลือกไว้แล้ว คุณจะไม่ได้รับแจ้งให้กำหนดค่าในตอนนี้ ในกรณีนี้ คุณสามารถข้ามส่วนนี้และไปที่สร้างไคลเอ็นต์ OAuth 2.0 ได้

  1. เลือกกำหนดค่าหน้าจอขอความยินยอม

หน้าสร้างไคลเอ็นต์ OAuth ของ Google Cloud Console พร้อมข้อกำหนดในการกำหนดค่าหน้าจอขอความยินยอม

  1. เลือกเริ่มต้นใช้งานในหน้าการสร้างแบรนด์

หน้าเริ่มต้นใช้งานการสร้างแบรนด์ Google Cloud Console

  1. ในหน้าการกำหนดค่าโปรเจ็กต์ ให้กรอกข้อมูลในช่องต่อไปนี้
    • ข้อมูลแอป: ป้อนชื่อและอีเมลสนับสนุนสำหรับผู้ใช้ของแอป อีเมลสนับสนุนนี้จะแสดงต่อสาธารณะเพื่อให้ผู้ใช้ติดต่อคุณได้ในกรณีที่มีคำถามเกี่ยวกับการยินยอม
    • ผู้ชม: เลือกภายนอก
    • ข้อมูลติดต่อ: ป้อนอีเมลเพื่อให้ Google ติดต่อคุณเกี่ยวกับโปรเจ็กต์
    • อ่านบริการ Google API: นโยบายข้อมูลผู้ใช้
    • คลิกสร้าง

หน้าการกำหนดค่าการสร้างแบรนด์ไคลเอ็นต์ของ Google Cloud Console

  1. เลือกหน้าไคลเอ็นต์ในเมนูการนำทาง
  2. คลิกสร้างไคลเอ็นต์

หน้าไคลเอ็นต์โปรเจ็กต์ Google Cloud

สร้างไคลเอ็นต์ OAuth 2.0

  1. เลือก iOS สำหรับประเภทแอปพลิเคชัน
  2. ป้อนชื่อไคลเอ็นต์
  3. ป้อนตัวระบุแพ็กเกจที่สร้างในขั้นตอนสุดท้าย
  4. ป้อนรหัสทีมที่ Apple กำหนดให้กับทีมของคุณ ตอนนี้ขั้นตอนนี้เป็นแบบไม่บังคับ แต่คุณต้องระบุรหัสทีมเพื่อเปิดใช้ App Check ในภายหลังใน Codelab นี้
  5. เลือกสร้าง

หน้าป้อนรายละเอียดไคลเอ็นต์ OAuth

  1. คัดลอกรหัสไคลเอ็นต์จากหน้าต่างกล่องโต้ตอบ คุณจะต้องใช้รหัสนี้ในภายหลัง
  2. ดาวน์โหลดไฟล์ plist เพื่อใช้อ้างอิงในภายหลัง

กล่องโต้ตอบ "สร้างรหัสไคลเอ็นต์ OAuth แล้ว"

4. กำหนดค่าโปรเจ็กต์ Xcode

ขั้นตอนถัดไปคือการตั้งค่าโปรเจ็กต์ Xcode ให้ทำงานกับ SDK การลงชื่อเข้าใช้ด้วย Google กระบวนการนี้เกี่ยวข้องกับการเพิ่ม SDK ลงในโปรเจ็กต์เป็นทรัพยากร Dependency และการกำหนดค่าการตั้งค่าโปรเจ็กต์ด้วยรหัสลูกค้าที่ไม่ซ้ำกัน รหัสนี้ช่วยให้ SDK สื่อสารกับบริการตรวจสอบสิทธิ์ของ Google ได้อย่างปลอดภัยในระหว่างกระบวนการลงชื่อเข้าใช้

ติดตั้งการอ้างอิงของฟีเจอร์ลงชื่อเข้าใช้ด้วย Google

  1. เปิดโปรเจ็กต์ Xcode
  2. ไปที่ File > Add Package Dependencies
  3. ในแถบค้นหา ให้ป้อน URL ของที่เก็บข้อมูลการลงชื่อเข้าใช้ด้วย Google: https://github.com/google/GoogleSignIn-iOS

ค้นหาทรัพยากร Dependency ของการลงชื่อเข้าใช้ด้วย Google ใน Swift Package Manager

  1. เลือกเพิ่มแพ็กเกจ
  2. เลือกเป้าหมายแอปพลิเคชันหลักสำหรับแพ็กเกจ GoogleSignIn
  3. หากใช้ SwiftUI ให้เลือกเป้าหมายแอปพลิเคชันหลักสำหรับแพ็กเกจ GoogleSignInSwift หากวางแผนที่จะใช้ UIKit อย่าเลือกเป้าหมายสำหรับแพ็กเกจนี้
  4. เลือกเพิ่มแพ็กเกจ

เพิ่มทรัพยากร Dependency ของการลงชื่อเข้าใช้ด้วย Google ลงในโปรเจ็กต์

กำหนดค่าข้อมูลเข้าสู่ระบบของแอป

  1. ในแถบนำทางของโปรเจ็กต์ ให้คลิกรูทของโปรเจ็กต์
  2. ในพื้นที่แก้ไขหลัก ให้เลือกเป้าหมายแอปพลิเคชันหลักจากรายการเป้าหมาย
  3. เลือกแท็บข้อมูลที่ด้านบนของพื้นที่แก้ไข
  4. วางเมาส์เหนือแถวสุดท้ายในส่วนพร็อพเพอร์ตี้เป้าหมาย iOS ที่กำหนดเอง แล้วคลิกปุ่ม + ที่ปรากฏขึ้น

เพิ่มคีย์เป้าหมายใหม่ลงในพร็อพเพอร์ตี้เป้าหมาย iOS

  1. ในคอลัมน์คีย์ ให้พิมพ์ GIDClientID
  2. ในคอลัมน์ค่า ให้วางรหัสไคลเอ็นต์ที่คัดลอกจาก Google Cloud Console

เพิ่ม GIDClientID ไปยังเป้าหมายแอปหลัก

  1. เปิดไฟล์ plist ที่ดาวน์โหลดจาก Google Cloud Console
  2. คัดลอกค่าสำหรับรหัสไคลเอ็นต์แบบย้อนกลับ

ไฟล์ plist ของ Google Cloud Console

  1. ขยายประเภท URL ที่ด้านล่างของแท็บข้อมูล
  2. เลือกปุ่ม +
  3. ป้อนรหัสไคลเอ็นต์แบบย้อนกลับในช่องรูปแบบ URL

เพิ่มคีย์ URLSchemes ลงในเป้าหมายแอปพลิเคชันหลัก

ตอนนี้เราพร้อมที่จะเริ่มเพิ่มปุ่มลงชื่อเข้าใช้ในแอปแล้ว

5. เพิ่มปุ่มลงชื่อเข้าใช้

เมื่อกำหนดค่าโปรเจ็กต์ Xcode แล้ว ก็ถึงเวลาเริ่มเพิ่มปุ่มลงชื่อเข้าใช้ด้วย Google ลงในแอป

ตรรกะหลักสำหรับขั้นตอนนี้คือการเรียกใช้ GIDSignIn.sharedInstance.signIn เมธอดนี้จะเริ่มกระบวนการตรวจสอบสิทธิ์ โดยส่งต่อการควบคุมไปยัง SDK ของการลงชื่อเข้าใช้ด้วย Google เพื่อแสดงขั้นตอนการลงชื่อเข้าใช้ด้วย Google แก่ผู้ใช้

SwiftUI

  1. ค้นหาไฟล์ ContentView.swift ในแถบนำทางของโปรเจ็กต์ Xcode
  2. แทนที่เนื้อหาของไฟล์นี้ด้วยข้อความต่อไปนี้
import GoogleSignIn
import GoogleSignInSwift
import SwiftUI

struct ContentView: View {
  var body: some View {
    VStack {
      GoogleSignInButton(action: handleSignInButton).padding()
    }
  }

  func handleSignInButton() {
    // Find the current window scene.
    guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene else {
      print("There is no active window scene")
      return
    }

    // Get the root view controller from the window scene.
    guard
      let rootViewController = windowScene.windows.first(where: { $0.isKeyWindow })?
        .rootViewController
    else {
      print("There is no key window or root view controller")
      return
    }

    // Start the sign-in process.
    GIDSignIn.sharedInstance.signIn(
      withPresenting: rootViewController
    ) { signInResult, error in
      guard let result = signInResult else {
        // Inspect error
        print("Error signing in: \(error?.localizedDescription ?? "No error description")")
        return
      }
      // If sign in succeeded, display the app's main content View.
      print("ID Token: \(result.user.idToken?.tokenString ?? "")")
    }
  }
}

#Preview {
  ContentView()
}

ปุ่มลงชื่อเข้าใช้ด้วย Google ในเฟรมเวิร์ก SwiftUI บนโปรแกรมจำลอง iOS

UIKit

  1. ค้นหาไฟล์ ViewController.swift ในแถบนำทางของโปรเจ็กต์ Xcode
  2. แทนที่เนื้อหาของไฟล์นี้ด้วยข้อความต่อไปนี้
import GoogleSignIn
import UIKit

class ViewController: UIViewController {

  // Create an instance of the Sign in with Google button
  let signInButton = GIDSignInButton()

  override func viewDidLoad() {
    super.viewDidLoad()

    // Add the sign-in button to your view
    view.addSubview(signInButton)

    // Position the button using constraints
    signInButton.translatesAutoresizingMaskIntoConstraints = false
    NSLayoutConstraint.activate([
      signInButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
      signInButton.centerYAnchor.constraint(equalTo: view.centerYAnchor),
    ])

    // Add a target to the button to call a method when it's pressed
    signInButton.addTarget(self, action: #selector(signInButtonTapped), for: .touchUpInside)
  }

  // This method is called when the sign-in button is pressed.
  @objc func signInButtonTapped() {
    // Start the sign-in process.
    GIDSignIn.sharedInstance.signIn(withPresenting: self) { signInResult, error in
      guard let result = signInResult else {
        // Inspect error
        print("Error signing in: \(error?.localizedDescription ?? "No error description")")
        return
      }

      // If sign in succeeded, print the ID token.
      print("ID Token: \(result.user.idToken?.tokenString ?? "")")
    }
  }
}

ปุ่มลงชื่อเข้าใช้ด้วย Google ในเฟรมเวิร์ก UIKit บนโปรแกรมจำลอง iOS

ดูปุ่มลงชื่อเข้าใช้

เปิดแอปในเครื่องจำลอง คุณจะเห็นปุ่มลงชื่อเข้าใช้ด้วย Google แต่ปุ่มจะยังทำงานไม่ถูกต้อง ซึ่งเป็นเรื่องปกติ เนื่องจากคุณยังคงต้องติดตั้งใช้งานโค้ดเพื่อจัดการการเปลี่ยนเส้นทางกลับไปยังแอปหลังจากที่ผู้ใช้ตรวจสอบสิทธิ์แล้ว

6. ปรับแต่งปุ่มลงชื่อเข้าใช้

คุณปรับแต่งปุ่มลงชื่อเข้าใช้ด้วย Google เริ่มต้นเพื่อให้เหมาะกับธีมของแอปได้ดียิ่งขึ้น SDK การลงชื่อเข้าใช้ด้วย Google ช่วยให้คุณแก้ไขรูปแบบสีและสไตล์ของปุ่มได้

SwiftUI

ระบบจะเพิ่มปุ่มเริ่มต้นลงในหน้าเว็บด้วยบรรทัดโค้ดนี้

GoogleSignInButton(action: handleSignInButton)

GoogleSignInButton ได้รับการปรับแต่งโดยการส่งพารามิเตอร์ไปยังตัวเริ่มต้น โค้ดต่อไปนี้จะทำให้ปุ่มลงชื่อเข้าใช้แสดงในโหมดมืด

  1. เปิด ContentView.swift
  2. อัปเดตตัวเริ่มต้นสำหรับ GoogleSignInButton ให้มีค่าต่อไปนี้
GoogleSignInButton(
  scheme: .dark,  // Options: .light, .dark, .auto
  style: .standard,  // Options: .standard, .wide, .icon
  state: .normal,  // Options: .normal, .disabled
  action: handleSignInButton
).padding()

ปุ่มลงชื่อเข้าใช้ด้วย Google ในโหมดมืดของเฟรมเวิร์ก SwiftUI บนโปรแกรมจำลอง iOS

ดูข้อมูลเพิ่มเติมเกี่ยวกับตัวเลือกการปรับแต่งได้ที่การอ้างอิงเฟรมเวิร์ก GoogleSignInSwift

UIKit

ปุ่มเริ่มต้นจะสร้างขึ้นด้วยบรรทัดโค้ดต่อไปนี้

// Create an instance of the Sign in with Google button
let signInButton = GIDSignInButton()

// Add the button to your view
view.addSubview(signInButton)

GIDSignInButton ได้รับการปรับแต่งโดยการตั้งค่าพร็อพเพอร์ตี้ในอินสแตนซ์ของปุ่ม โค้ดต่อไปนี้จะทำให้ปุ่มลงชื่อเข้าใช้แสดงในโหมดมืด

  1. เปิด ViewController.swift
  2. เพิ่มบรรทัดโค้ดต่อไปนี้ทันทีก่อนเพิ่มปุ่มลงชื่อเข้าใช้ในมุมมองในฟังก์ชัน viewDidLoad
// Set the width and color of the sign-in button
signInButton.style = .standard  // Options: .standard, .wide, .iconOnly
signInButton.colorScheme = .dark  // Options: .dark, .light

ปุ่มลงชื่อเข้าใช้ด้วย Google ในโหมดมืดของเฟรมเวิร์ก UIKit ในโปรแกรมจำลอง iOS

ดูข้อมูลเพิ่มเติมเกี่ยวกับการปรับแต่งได้ที่การอ้างอิงเฟรมเวิร์ก GoogleSignIn

7. จัดการ URL เปลี่ยนเส้นทางสำหรับการตรวจสอบสิทธิ์

เมื่อเพิ่มปุ่มลงชื่อเข้าใช้แล้ว ขั้นตอนถัดไปคือการจัดการการเปลี่ยนเส้นทางที่จะเกิดขึ้นหลังจากที่ผู้ใช้ตรวจสอบสิทธิ์ หลังจากตรวจสอบสิทธิ์แล้ว Google จะแสดง URL พร้อมรหัสการให้สิทธิ์ชั่วคราว ตัวแฮนเดิลจะสกัดกั้น URL นี้และส่งไปยัง SDK ของการลงชื่อเข้าใช้ด้วย Google เพื่อแลกเปลี่ยนเป็นโทเค็นรหัสที่ลงชื่อ (JWT) เพื่อให้กระบวนการลงชื่อเข้าใช้เสร็จสมบูรณ์

SwiftUI

  1. เปิดไฟล์ที่มี App struct ไฟล์นี้จะตั้งชื่อตามโปรเจ็กต์ของคุณ ดังนั้นชื่อไฟล์จึงมีลักษณะคล้ายกับ YourProjectNameApp.swift
  2. แทนที่เนื้อหาของไฟล์นี้ด้วยข้อความต่อไปนี้
import GoogleSignIn
import SwiftUI

@main
struct iOS_Sign_in_with_Google_App: App {
  var body: some Scene {
    WindowGroup {
      ContentView()

        .onOpenURL { url in
          GIDSignIn.sharedInstance.handle(url)
        }
    }
  }
}

UIKit

  1. เปิด AppDelegate.swift
  2. เพิ่มการนำเข้าต่อไปนี้ที่ด้านบนของไฟล์
import GoogleSignIn
  1. เพิ่มฟังก์ชันตัวแฮนเดิลการตรวจสอบสิทธิ์ต่อไปนี้ภายในคลาส AppDelegate ตำแหน่งที่เหมาะในการวางคือต่อจากเครื่องหมายปีกกาปิดของapplication(_:didFinishLaunchingWithOptions:)เมธอดโดยตรง
func application(
  _ app: UIApplication,
  open url: URL,
  options: [UIApplication.OpenURLOptionsKey: Any] = [:]
) -> Bool {
  var handled: Bool

  handled = GIDSignIn.sharedInstance.handle(url)
  if handled {
    return true
  }
  // If not handled by this app, return false.
  return false
}

หลังจากทำการเปลี่ยนแปลงเหล่านี้แล้ว ไฟล์ AppDelegate.swift ควรมีลักษณะดังนี้

import GoogleSignIn
import UIKit

@main
class AppDelegate: UIResponder, UIApplicationDelegate {

  func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    // Override point for customization after application launch.
    return true
  }

  func application(
    _ app: UIApplication,
    open url: URL,
    options: [UIApplication.OpenURLOptionsKey: Any] = [:]
  ) -> Bool {
    var handled: Bool

    handled = GIDSignIn.sharedInstance.handle(url)
    if handled {
      return true
    }
    // If not handled by this app, return false.
    return false
  }

  // MARK: UISceneSession Lifecycle

  func application(
    _ application: UIApplication,
    configurationForConnecting connectingSceneSession: UISceneSession,
    options: UIScene.ConnectionOptions
  ) -> UISceneConfiguration {
    // Called when a new scene session is being created.
    // Use this method to select a configuration to create the new scene with.
    return UISceneConfiguration(
      name: "Default Configuration",
      sessionRole: connectingSceneSession.role
    )
  }

  func application(
    _ application: UIApplication,
    didDiscardSceneSessions sceneSessions: Set<UISceneSession>
  ) {
    // Called when the user discards a scene session.
    // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
    // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
  }
}

ทดสอบขั้นตอนการลงชื่อเข้าใช้

ตอนนี้คุณสามารถทดสอบขั้นตอนการลงชื่อเข้าใช้ทั้งหมดได้แล้ว

เรียกใช้แอปแล้วแตะปุ่มลงชื่อเข้าใช้ หลังจากที่คุณตรวจสอบสิทธิ์แล้ว Google จะแสดงหน้าจอความยินยอมที่คุณสามารถให้สิทธิ์แอปในการเข้าถึงข้อมูลได้ เมื่ออนุมัติแล้ว ระบบจะลงชื่อเข้าใช้ให้เสร็จสมบูรณ์และนำคุณกลับไปที่แอป

เมื่อขั้นตอนการลงชื่อเข้าใช้เสร็จสมบูรณ์แล้ว SDK การลงชื่อเข้าใช้ด้วย Google จะจัดเก็บข้อมูลเข้าสู่ระบบของผู้ใช้ในพวงกุญแจของอุปกรณ์อย่างปลอดภัย โดยสามารถใช้ข้อมูลเข้าสู่ระบบเหล่านี้ในภายหลังเพื่อให้ผู้ใช้ยังคงลงชื่อเข้าใช้ได้เมื่อเปิดแอปในครั้งต่อๆ ไป

8. เพิ่มปุ่มออกจากระบบ

ตอนนี้การลงชื่อเข้าใช้ใช้งานได้แล้ว ขั้นตอนถัดไปคือการเพิ่มปุ่มลงชื่อออกและอัปเดต UI เพื่อแสดงสถานะการลงชื่อเข้าใช้ปัจจุบันของผู้ใช้ เมื่อลงชื่อเข้าใช้สำเร็จ SDK จะแสดงออบเจ็กต์ GIDGoogleUser ออบเจ็กต์นี้มีพร็อพเพอร์ตี้ profile พร้อมข้อมูลพื้นฐาน เช่น ชื่อและอีเมลของผู้ใช้ ซึ่งคุณจะใช้เพื่อปรับแต่ง UI

SwiftUI

  1. เปิดไฟล์ ContentView.swift
  2. เพิ่มตัวแปรสถานะที่ด้านบนของ ContentView struct ตัวแปรนี้จะเก็บข้อมูลของผู้ใช้หลังจากที่ผู้ใช้ลงชื่อเข้าใช้ เนื่องจากเป็นตัวแปร @State SwiftUI จะอัปเดต UI โดยอัตโนมัติเมื่อใดก็ตามที่ค่ามีการเปลี่ยนแปลง
struct ContentView: View {
  @State private var user: GIDGoogleUser?
}
  1. แทนที่ body ปัจจุบันของโครงสร้าง ContentView ด้วย VStack ต่อไปนี้ ซึ่งจะตรวจสอบว่าตัวแปรสถานะ user มีผู้ใช้หรือไม่ หากมี ระบบจะแสดงข้อความต้อนรับและปุ่มออกจากระบบ หากไม่เป็นเช่นนั้น ระบบจะแสดงปุ่มลงชื่อเข้าใช้ด้วย Google แบบเดิม
var body: some View {
  VStack {
    // Check if the user is signed in.
    if let user = user {
      // If signed in, show a welcome message and the sign-out button.
      Text("Hello, \(user.profile?.givenName ?? "User")!")
        .font(.title)
        .padding()

      Button("Sign Out", action: signOut)
        .buttonStyle(.borderedProminent)

    } else {
      // If not signed in, show the "Sign in with Google" button.
      GoogleSignInButton(
        scheme: .dark,  // Options: .light, .dark, .auto
        style: .standard,  // Options: .standard, .wide, .icon
        state: .normal,  // Options: .normal, .disabled
        action: handleSignInButton
      ).padding()
    }
  }
}
  1. อัปเดตบล็อกการดำเนินการให้เสร็จสมบูรณ์เพื่อกำหนด signInResult.user ให้กับตัวแปร user ใหม่handleSignInButton โดยสิ่งที่จะทริกเกอร์ให้ UI เปลี่ยนไปเป็นมุมมองที่ลงชื่อเข้าใช้แล้วมีดังนี้
func handleSignInButton() {
  // Find the current window scene.
  guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene else {
    print("There is no active window scene")
    return
  }

  // Get the root view controller from the window scene.
  guard
    let rootViewController = windowScene.windows.first(where: { $0.isKeyWindow })?
      .rootViewController
  else {
    print("There is no key window or root view controller")
    return
  }

  // Start the sign-in process.
  GIDSignIn.sharedInstance.signIn(
    withPresenting: rootViewController
  ) { signInResult, error in
    guard let result = signInResult else {
      // Inspect error
      print("Error signing in: \(error?.localizedDescription ?? "No error description")")
      return
    }

    DispatchQueue.main.async {
      self.user = result.user
    }

    // If sign in succeeded, display the app's main content View.
    print("ID Token: \(result.user.idToken?.tokenString ?? "")")
  }
}
  1. เพิ่มฟังก์ชัน signOut ใหม่ที่ด้านล่างของโครงสร้าง ContentView เพื่อให้ปุ่มออกจากระบบเรียกใช้ได้
func signOut() {
  GIDSignIn.sharedInstance.signOut()
  // After signing out, set the `user` state variable to `nil`.
  self.user = nil
}

เปิดแอปและลงชื่อเข้าใช้ คุณควรเห็นการเปลี่ยนแปลง UI หลังจากตรวจสอบสิทธิ์สำเร็จ

สถานะการลงชื่อเข้าใช้เฟรมเวิร์ก SwiftUI ในโปรแกรมจำลอง iOS

หลังจากทำการเปลี่ยนแปลงเหล่านี้แล้ว ไฟล์ ContentView.swift ควรมีลักษณะดังนี้

import GoogleSignIn
import GoogleSignInSwift
import SwiftUI

struct ContentView: View {

  @State private var user: GIDGoogleUser?

  var body: some View {
    VStack {
      // Check if the user is signed in.
      if let user = user {
        // If signed in, show a welcome message and the sign-out button.
        Text("Hello, \(user.profile?.givenName ?? "User")!")
          .font(.title)
          .padding()

        Button("Sign Out", action: signOut)
          .buttonStyle(.borderedProminent)

      } else {
        // If not signed in, show the "Sign in with Google" button.
        GoogleSignInButton(
          scheme: .dark,  // Options: .light, .dark, .auto
          style: .standard,  // Options: .standard, .wide, .icon
          state: .normal,  // Options: .normal, .disabled
          action: handleSignInButton
        ).padding()
      }
    }
  }

  func handleSignInButton() {
    // Find the current window scene.
    guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene else {
      print("There is no active window scene")
      return
    }

    // Get the root view controller from the window scene.
    guard
      let rootViewController = windowScene.windows.first(where: { $0.isKeyWindow })?
        .rootViewController
    else {
      print("There is no key window or root view controller")
      return
    }

    // Start the sign-in process.
    GIDSignIn.sharedInstance.signIn(
      withPresenting: rootViewController
    ) { signInResult, error in
      guard let result = signInResult else {
        // Inspect error
        print("Error signing in: \(error?.localizedDescription ?? "No error description")")
        return
      }

      DispatchQueue.main.async {
        self.user = result.user
      }

      // If sign in succeeded, display the app's main content View.
      print("ID Token: \(result.user.idToken?.tokenString ?? "")")
    }
  }

  func signOut() {
    GIDSignIn.sharedInstance.signOut()
    // After signing out, set the `user` state variable to `nil`.
    self.user = nil
  }
}

#Preview {
  ContentView()
}

UIKit

  1. เปิด ViewController.swift
  2. ที่ด้านบนของ ViewController ใต้ตำแหน่งที่คุณประกาศ signInButton ให้เพิ่มปุ่มออกจากระบบและป้ายกำกับต้อนรับ
let signOutButton = UIButton(type: .system)
let welcomeLabel = UILabel()
  1. เพิ่มฟังก์ชันต่อไปนี้ที่ด้านล่างของ ViewController ฟังก์ชันนี้จะแสดง UI ที่แตกต่างกันแก่ผู้ใช้ตามสถานะการลงชื่อเข้าใช้ของผู้ใช้ ดังนี้
private func updateUI(for user: GIDGoogleUser?) {
  if let user = user {
    // User is signed in.
    signInButton.isHidden = true
    signOutButton.isHidden = false
    welcomeLabel.isHidden = false
    welcomeLabel.text = "Hello, \(user.profile?.givenName ?? "User")!"
  } else {
    // User is signed out.
    signInButton.isHidden = false
    signOutButton.isHidden = true
    welcomeLabel.isHidden = true
  }
}
  1. ที่ด้านล่างของฟังก์ชัน viewDidLoad ให้เพิ่มโค้ดต่อไปนี้เพื่อเพิ่มป้ายกำกับต้อนรับและปุ่มออกจากระบบลงในมุมมอง
// --- Set up the Welcome Label ---
welcomeLabel.translatesAutoresizingMaskIntoConstraints = false
welcomeLabel.textAlignment = .center
welcomeLabel.font = .systemFont(ofSize: 24, weight: .bold)
view.addSubview(welcomeLabel)

NSLayoutConstraint.activate([
  welcomeLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor),
  welcomeLabel.bottomAnchor.constraint(equalTo: signInButton.topAnchor, constant: -20),
])

// --- Set up the Sign-Out Button ---
signOutButton.translatesAutoresizingMaskIntoConstraints = false
signOutButton.setTitle("Sign Out", for: .normal)
view.addSubview(signOutButton)

NSLayoutConstraint.activate([
  signOutButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
  signOutButton.topAnchor.constraint(equalTo: signInButton.bottomAnchor, constant: 20),
])

signOutButton.addTarget(self, action: #selector(signOutButtonTapped), for: .touchUpInside)

// --- Set Initial UI State ---
updateUI(for: nil)
  1. อัปเดตฟังก์ชัน signInButtonTapped เพื่อเรียกใช้เมธอด UpdateUI เมื่อลงชื่อเข้าใช้สำเร็จ
@objc func signInButtonTapped() {
  // Start the sign-in process.
  GIDSignIn.sharedInstance.signIn(withPresenting: self) { signInResult, error in
    guard let result = signInResult else {
      // Inspect error
      print("Error signing in: \(error?.localizedDescription ?? "No error description")")
      return
    }

    // If sign in succeeded, print the ID token.
    print("ID Token: \(result.user.idToken?.tokenString ?? "")")

    DispatchQueue.main.async {
      self.updateUI(for: result.user)
    }
  }
}
  1. สุดท้าย ให้เพิ่มฟังก์ชัน signOutButtonTapped ลงใน ViewController เพื่อจัดการกระบวนการออกจากระบบ
@objc func signOutButtonTapped() {
  GIDSignIn.sharedInstance.signOut()
  // Update the UI for the signed-out state.
  updateUI(for: nil)
}

เปิดแอปและลงชื่อเข้าใช้ คุณควรเห็นการเปลี่ยนแปลง UI หลังจากตรวจสอบสิทธิ์สำเร็จ

สถานะที่ลงชื่อเข้าใช้ของเฟรมเวิร์ก UIKit ในโปรแกรมจำลอง iOS

หลังจากทำการเปลี่ยนแปลงเหล่านี้แล้ว ไฟล์ ViewController.swift ควรมีลักษณะดังนี้

import GoogleSignIn
import UIKit

class ViewController: UIViewController {

  // Create an instance of the Sign in with Google button
  let signInButton = GIDSignInButton()
  let signOutButton = UIButton(type: .system)
  let welcomeLabel = UILabel()

  override func viewDidLoad() {
    super.viewDidLoad()

    // Set the width and color of the sign-in button
    signInButton.style = .standard  // Options: .standard, .wide, .iconOnly
    signInButton.colorScheme = .dark  // Options: .dark, .light

    // Add the sign-in button to your view
    view.addSubview(signInButton)

    // Position the button using constraints
    signInButton.translatesAutoresizingMaskIntoConstraints = false
    NSLayoutConstraint.activate([
      signInButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
      signInButton.centerYAnchor.constraint(equalTo: view.centerYAnchor),
    ])

    // Add a target to the button to call a method when it's pressed
    signInButton.addTarget(self, action: #selector(signInButtonTapped), for: .touchUpInside)

    // --- Set up the Welcome Label ---
    welcomeLabel.translatesAutoresizingMaskIntoConstraints = false
    welcomeLabel.textAlignment = .center
    welcomeLabel.font = .systemFont(ofSize: 24, weight: .bold)
    view.addSubview(welcomeLabel)

    NSLayoutConstraint.activate([
      welcomeLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor),
      welcomeLabel.bottomAnchor.constraint(equalTo: signInButton.topAnchor, constant: -20),
    ])

    // --- Set up the Sign-Out Button ---
    signOutButton.translatesAutoresizingMaskIntoConstraints = false
    signOutButton.setTitle("Sign Out", for: .normal)
    view.addSubview(signOutButton)

    NSLayoutConstraint.activate([
      signOutButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
      signOutButton.topAnchor.constraint(equalTo: signInButton.bottomAnchor, constant: 20),
    ])

    signOutButton.addTarget(self, action: #selector(signOutButtonTapped), for: .touchUpInside)

    // --- Set Initial UI State ---
    updateUI(for: nil)
  }

  // This method is called when the sign-in button is pressed.
  @objc func signInButtonTapped() {
    // Start the sign-in process.
    GIDSignIn.sharedInstance.signIn(withPresenting: self) { signInResult, error in
      guard let result = signInResult else {
        // Inspect error
        print("Error signing in: \(error?.localizedDescription ?? "No error description")")
        return
      }

      // If sign in succeeded, print the ID token.
      print("ID Token: \(result.user.idToken?.tokenString ?? "")")

      DispatchQueue.main.async {
        self.updateUI(for: result.user)
      }
    }
  }

  private func updateUI(for user: GIDGoogleUser?) {
    if let user = user {
      // User is signed in.
      signInButton.isHidden = true
      signOutButton.isHidden = false
      welcomeLabel.isHidden = false
      welcomeLabel.text = "Hello, \(user.profile?.givenName ?? "User")!"
    } else {
      // User is signed out.
      signInButton.isHidden = false
      signOutButton.isHidden = true
      welcomeLabel.isHidden = true
    }
  }

  @objc func signOutButtonTapped() {
    GIDSignIn.sharedInstance.signOut()
    // Update the UI for the signed-out state.
    updateUI(for: nil)
  }
}

9. กู้คืนสถานะการลงชื่อเข้าใช้ของผู้ใช้

ขั้นตอนถัดไปคือการคืนค่าสถานะการลงชื่อเข้าใช้เมื่อเปิดแอปเพื่อปรับปรุงประสบการณ์การใช้งานสำหรับผู้ใช้ที่กลับมา การเรียกใช้ restorePreviousSignIn จะใช้ข้อมูลเข้าสู่ระบบที่บันทึกไว้ในพวงกุญแจเพื่อลงชื่อเข้าใช้ให้ผู้ใช้อีกครั้งโดยอัตโนมัติ เพื่อให้ผู้ใช้ไม่ต้องทำตามขั้นตอนการลงชื่อเข้าใช้ทุกครั้ง

SwiftUI

  1. เปิด ContentView.swift
  2. เพิ่มโค้ดต่อไปนี้ต่อจาก VStack ภายในตัวแปร body โดยตรง
.onAppear {
  // On appear, try to restore a previous sign-in.
  GIDSignIn.sharedInstance.restorePreviousSignIn { user, error in
    // This closure is called when the restoration is complete.
    if let user = user {
      // If a user was restored, update the `user` state variable.
      DispatchQueue.main.async {
        self.user = user
      }

      // Print the ID token to the console when restored.
      print("Restored ID Token: \(user.idToken?.tokenString ?? "")")
    }
  }
}

ContentView.swift ควรมีลักษณะดังนี้

import GoogleSignIn
import GoogleSignInSwift
import SwiftUI

struct ContentView: View {

  @State private var user: GIDGoogleUser?

  var body: some View {
    VStack {
      // Check if the user is signed in.
      if let user = user {
        // If signed in, show a welcome message and the sign-out button.
        Text("Hello, \(user.profile?.givenName ?? "User")!")
          .font(.title)
          .padding()

        Button("Sign Out", action: signOut)
          .buttonStyle(.borderedProminent)

      } else {
        // If not signed in, show the "Sign in with Google" button.
        GoogleSignInButton(
          scheme: .dark,  // Options: .light, .dark, .auto
          style: .standard,  // Options: .standard, .wide, .icon
          state: .normal,  // Options: .normal, .disabled
          action: handleSignInButton
        ).padding()
      }
    }

    .onAppear {
      // On appear, try to restore a previous sign-in.
      GIDSignIn.sharedInstance.restorePreviousSignIn { user, error in
        // This closure is called when the restoration is complete.
        if let user = user {
          // If a user was restored, update the `user` state variable.
          DispatchQueue.main.async {
            self.user = user
          }

          // Print the ID token to the console when restored.
          print("Restored ID Token: \(user.idToken?.tokenString ?? "")")
        }
      }
    }
  }

  func handleSignInButton() {
    // Find the current window scene.
    guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene else {
      print("There is no active window scene")
      return
    }

    // Get the root view controller from the window scene.
    guard
      let rootViewController = windowScene.windows.first(where: { $0.isKeyWindow })?
        .rootViewController
    else {
      print("There is no key window or root view controller")
      return
    }

    // Start the sign-in process.
    GIDSignIn.sharedInstance.signIn(
      withPresenting: rootViewController
    ) { signInResult, error in
      guard let result = signInResult else {
        // Inspect error
        print("Error signing in: \(error?.localizedDescription ?? "No error description")")
        return
      }

      DispatchQueue.main.async {
        self.user = result.user
      }

      // If sign in succeeded, display the app's main content View.
      print("ID Token: \(result.user.idToken?.tokenString ?? "")")
    }
  }

  func signOut() {
    GIDSignIn.sharedInstance.signOut()
    // After signing out, set the `user` state variable to `nil`.
    self.user = nil
  }
}

#Preview {
  ContentView()
}

UIKit

  1. เปิด ViewController.swift
  2. เพิ่มrestorePreviousSignInการเรียกต่อไปนี้ที่ส่วนท้ายของเมธอด viewDidLoad
// Attempt to restore a previous sign-in session
GIDSignIn.sharedInstance.restorePreviousSignIn { user, error in
  if let user = user {
    print("Successfully restored sign-in for user: \(user.profile?.givenName ?? "Unknown")")

    // Print the ID token when a session is restored.
    print("Restored ID Token: \(user.idToken?.tokenString ?? "")")

    // On success, update the UI for the signed-in state on the main thread.
    DispatchQueue.main.async {
      self.updateUI(for: user)
    }
  }
}

ไฟล์ ViewController.swift ควรมีลักษณะดังนี้

import GoogleSignIn
import UIKit

class ViewController: UIViewController {

  // Create an instance of the Sign in with Google button
  let signInButton = GIDSignInButton()
  let signOutButton = UIButton(type: .system)
  let welcomeLabel = UILabel()

  override func viewDidLoad() {
    super.viewDidLoad()

    // Set the width and color of the sign-in button
    signInButton.style = .standard  // Options: .standard, .wide, .iconOnly
    signInButton.colorScheme = .dark  // Options: .dark, .light

    // Add the sign-in button to your view
    view.addSubview(signInButton)

    // Position the button using constraints
    signInButton.translatesAutoresizingMaskIntoConstraints = false
    NSLayoutConstraint.activate([
      signInButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
      signInButton.centerYAnchor.constraint(equalTo: view.centerYAnchor),
    ])

    // Add a target to the button to call a method when it's pressed
    signInButton.addTarget(self, action: #selector(signInButtonTapped), for: .touchUpInside)

    // --- Set up the Welcome Label ---
    welcomeLabel.translatesAutoresizingMaskIntoConstraints = false
    welcomeLabel.textAlignment = .center
    welcomeLabel.font = .systemFont(ofSize: 24, weight: .bold)
    view.addSubview(welcomeLabel)

    NSLayoutConstraint.activate([
      welcomeLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor),
      welcomeLabel.bottomAnchor.constraint(equalTo: signInButton.topAnchor, constant: -20),
    ])

    // --- Set up the Sign-Out Button ---
    signOutButton.translatesAutoresizingMaskIntoConstraints = false
    signOutButton.setTitle("Sign Out", for: .normal)
    view.addSubview(signOutButton)

    NSLayoutConstraint.activate([
      signOutButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
      signOutButton.topAnchor.constraint(equalTo: signInButton.bottomAnchor, constant: 20),
    ])

    signOutButton.addTarget(self, action: #selector(signOutButtonTapped), for: .touchUpInside)

    // --- Set Initial UI State ---
    updateUI(for: nil)

    // Attempt to restore a previous sign-in session
    GIDSignIn.sharedInstance.restorePreviousSignIn { user, error in
      if let user = user {
        print("Successfully restored sign-in for user: \(user.profile?.givenName ?? "Unknown")")

        // Print the ID token when a session is restored.
        print("Restored ID Token: \(user.idToken?.tokenString ?? "")")

        // On success, update the UI for the signed-in state on the main thread.
        DispatchQueue.main.async {
          self.updateUI(for: user)
        }
      }
    }
  }

  // This method is called when the sign-in button is pressed.
  @objc func signInButtonTapped() {
    // Start the sign-in process.
    GIDSignIn.sharedInstance.signIn(withPresenting: self) { signInResult, error in
      guard let result = signInResult else {
        // Inspect error
        print("Error signing in: \(error?.localizedDescription ?? "No error description")")
        return
      }

      // If sign in succeeded, print the ID token.
      print("ID Token: \(result.user.idToken?.tokenString ?? "")")

      DispatchQueue.main.async {
        self.updateUI(for: result.user)
      }
    }
  }

  private func updateUI(for user: GIDGoogleUser?) {
    if let user = user {
      // User is signed in.
      signInButton.isHidden = true
      signOutButton.isHidden = false
      welcomeLabel.isHidden = false
      welcomeLabel.text = "Hello, \(user.profile?.givenName ?? "User")!"
    } else {
      // User is signed out.
      signInButton.isHidden = false
      signOutButton.isHidden = true
      welcomeLabel.isHidden = true
    }
  }

  @objc func signOutButtonTapped() {
    GIDSignIn.sharedInstance.signOut()
    // Update the UI for the signed-out state.
    updateUI(for: nil)
  }
}

ทดสอบการลงชื่อเข้าใช้แบบเงียบ

หลังจากลงชื่อเข้าใช้แล้ว ให้ออกจากแอปโดยสมบูรณ์แล้วเปิดแอปอีกครั้ง คุณควรเห็นว่าตอนนี้ระบบลงชื่อเข้าใช้ให้คุณโดยอัตโนมัติโดยไม่ต้องแตะปุ่ม

10. ทำความเข้าใจโทเค็นรหัส

แม้ว่าออบเจ็กต์ GIDGoogleUser จะสะดวกในการปรับแต่ง UI โดยใช้ชื่อและอีเมลของผู้ใช้ แต่ข้อมูลที่สำคัญที่สุดที่ SDK ส่งคืนคือโทเค็นรหัส

Codelab นี้ใช้เครื่องมือออนไลน์เพื่อตรวจสอบเนื้อหา JWT ในแอปเวอร์ชันที่ใช้งานจริง คุณควรส่งโทเค็นรหัสนี้ไปยังเซิร์ฟเวอร์แบ็กเอนด์ เซิร์ฟเวอร์ต้องยืนยันความสมบูรณ์ของโทเค็นรหัสและใช้ JWT เพื่อทำสิ่งที่มีความหมายมากขึ้น เช่น สร้างบัญชีใหม่ในแพลตฟอร์มแบ็กเอนด์หรือสร้างเซสชันใหม่สำหรับผู้ใช้

เข้าถึงและถอดรหัสโทเค็น JWT

  1. เปิดแอป
  2. เปิดคอนโซล Xcode คุณควรเห็นโทเค็นรหัสที่พิมพ์ออกมา โดยจะมีลักษณะดังนี้ eyJhbGciOiJSUzI1Ni ... Hecz6Wm4Q
  3. คัดลอกโทเค็นรหัสและใช้เครื่องมือออนไลน์ เช่น jwt.io เพื่อถอดรหัส JWT

JWT ที่ถอดรหัสแล้วจะมีลักษณะดังนี้

{
  "alg": "RS256",
  "kid": "c8ab71530972bba20b49f78a09c9852c43ff9118",
  "typ": "JWT"
}
{
  "iss": "https://accounts.google.com",
  "azp": "171291171076-rrbkcjrp5jbte92ai9gub115ertscphi.apps.googleusercontent.com",
  "aud": "171291171076-rrbkcjrp5jbte92ai9gub115ertscphi.apps.googleusercontent.com",
  "sub": "10769150350006150715113082367",
  "email": "example@example.com",
  "email_verified": true,
  "at_hash": "JyCYDmHtzhjkb0-qJhKsMg",
  "name": "Kimya",
  "picture": "https://lh3.googleusercontent.com/a/ACg8ocIyy4VoR31t_n0biPVcScBHwZOCRaKVDb_MoaMYep65fyqoAw=s96-c",
  "given_name": "Kimya",
  "iat": 1758645896,
  "exp": 1758649496
}

ฟิลด์โทเค็นที่สำคัญ

โทเค็นรหัสที่ถอดรหัสแล้วมีช่องที่มีวัตถุประสงค์แตกต่างกัน แม้ว่าบางอย่างจะเข้าใจได้ง่าย เช่น ชื่อและอีเมล แต่เซิร์ฟเวอร์แบ็กเอนด์จะใช้ข้อมูลอื่นๆ เพื่อการยืนยัน

คุณควรทำความเข้าใจช่องต่อไปนี้เป็นพิเศษ

  • sub: ฟิลด์ sub คือตัวระบุที่ไม่ซ้ำกันและถาวรสำหรับบัญชี Google ของผู้ใช้ ผู้ใช้สามารถเปลี่ยนอีเมลหลักหรือชื่อได้ แต่จะเปลี่ยนรหัส sub ไม่ได้ ซึ่งทำให้ฟิลด์ sub เป็นค่าที่เหมาะที่สุดที่จะใช้เป็นคีย์หลักสำหรับบัญชีผู้ใช้แบ็กเอนด์

รับข้อมูลผู้ใช้จากโทเค็นรหัสมีข้อมูลเพิ่มเติมเกี่ยวกับความหมายของฟิลด์โทเค็นทั้งหมด

11. รักษาความปลอดภัยให้แอปด้วย App Check

เราขอแนะนำอย่างยิ่งให้คุณเปิดใช้ App Check เพื่อให้มั่นใจว่าจะมีเพียงแอปของคุณเท่านั้นที่เข้าถึงปลายทาง OAuth 2.0 ของ Google ในนามของโปรเจ็กต์ได้ App Check ทำงานโดยการยืนยันว่าคำขอไปยังบริการแบ็กเอนด์มาจากแอปของแท้ในอุปกรณ์จริงที่ไม่มีการดัดแปลง

ส่วนนี้แสดงวิธีผสานรวม App Check เข้ากับแอปและกำหนดค่าสำหรับการแก้ไขข้อบกพร่องในโปรแกรมจำลองและสำหรับการสร้างเวอร์ชันที่ใช้งานจริงซึ่งทำงานในอุปกรณ์จริง

การตั้งค่าคอนโซล

การผสานรวม App Check เข้ากับแอปพลิเคชันของคุณต้องมีการตั้งค่าแบบครั้งเดียวในคอนโซล Google Cloud และ Firebase ซึ่งรวมถึงการเปิดใช้ App Check สำหรับไคลเอ็นต์ OAuth ของ iOS ใน Google Cloud Console, การสร้างคีย์ API เพื่อใช้กับผู้ให้บริการแก้ไขข้อบกพร่องของ App Check และการลิงก์โปรเจ็กต์ Google Cloud กับ Firebase

เปิดใช้ App Check ใน Google Cloud Console

  1. ไปที่รายการไคลเอ็นต์ที่เชื่อมโยงกับโปรเจ็กต์ Google Cloud
  2. เลือกรหัสไคลเอ็นต์ OAuth 2.0 ที่คุณสร้างขึ้นสำหรับแอป iOS
  3. เปิด App Check ใต้ Google Identity สำหรับ iOS

หน้าแก้ไขไคลเอ็นต์ OAuth พร้อมปุ่มเปิด/ปิด App Check

  1. คลิกบันทึก

สร้างคีย์ API

  1. ไปที่หน้าคลัง API สำหรับโปรเจ็กต์ Google Cloud
  2. ป้อน Firebase App Check API ในแถบค้นหา

หน้าไลบรารี API ของ Google Cloud Console

  1. เลือกและเปิดใช้ Firebase App Check API
  2. ไปที่ API และบริการ แล้วเลือกข้อมูลเข้าสู่ระบบในเมนูการนำทาง
  3. เลือกสร้างข้อมูลเข้าสู่ระบบที่ด้านบนของหน้า

หน้าข้อมูลเข้าสู่ระบบ API ของ Google Cloud Console

  1. ตั้งชื่อคีย์ API นี้
  2. เลือกแอป iOS ในส่วนการจำกัดแอปพลิเคชัน
  3. เพิ่มตัวระบุชุดของแอปเป็นแอปพลิเคชันที่ได้รับอนุมัติ
  4. เลือกจำกัดคีย์ในส่วนการจำกัด API
  5. เลือก Firebase App Check API จากเมนูแบบเลื่อนลง
  6. เลือกสร้าง

หน้าสร้างคีย์ Google Cloud Console API

  1. คัดลอกคีย์ API ที่สร้างขึ้น เนื่องจากคุณจะต้องใช้ที่อยู่ IP นี้ในขั้นตอนต่อไป

เพิ่ม Firebase ไปยังโปรเจ็กต์ Google Cloud

  1. ไปที่คอนโซล Firebase
  2. เลือกเริ่มต้นใช้งานโดยการตั้งค่าโปรเจ็กต์ Firebase
  3. เลือกเพิ่ม Firebase ไปยังโปรเจ็กต์ Google Cloud

เพิ่ม Firebase ไปยังโปรเจ็กต์ Google Cloud ที่มีอยู่

  1. เลือกโปรเจ็กต์ Google Cloud จากเมนูแบบเลื่อนลง แล้วดำเนินการต่อในขั้นตอนการลงชื่อสมัครใช้
  2. เลือกเพิ่ม Firebase
  3. เมื่อโปรเจ็กต์ Firebase พร้อมแล้ว ให้เลือกต่อไปเพื่อเปิดโปรเจ็กต์

การผสานรวมโค้ดฝั่งไคลเอ็นต์

เมื่อกำหนดค่าโปรเจ็กต์ Google Cloud สำหรับ App Check แล้ว ก็ถึงเวลาเขียนโค้ดฝั่งไคลเอ็นต์เพื่อเปิดใช้ ผู้ให้บริการที่ใช้สำหรับการรับรองจะแตกต่างกันในสภาพแวดล้อมการใช้งานจริงและสภาพแวดล้อมการแก้ไขข้อบกพร่อง แอปเวอร์ชันที่ใช้งานจริงในอุปกรณ์จริงจะใช้บริการ App Attest ในตัวของ Apple เพื่อพิสูจน์ความถูกต้อง อย่างไรก็ตาม เนื่องจากโปรแกรมจำลอง iOS ไม่สามารถให้การรับรองประเภทนี้ได้ สภาพแวดล้อมการแก้ไขข้อบกพร่องจึงต้องมีผู้ให้บริการแก้ไขข้อบกพร่องพิเศษที่ส่งคีย์ API ให้

โค้ดต่อไปนี้จะจัดการทั้ง 2 สถานการณ์โดยใช้คำสั่งคอมไพเลอร์เพื่อเลือกผู้ให้บริการที่ถูกต้องโดยอัตโนมัติในเวลาบิลด์

SwiftUI

  1. เปิดไฟล์แอปหลัก
  2. กำหนดคลาส AppDelegate ต่อไปนี้หลังการนำเข้าและก่อนแอตทริบิวต์ @main
class AppDelegate: NSObject, UIApplicationDelegate {
  func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
  ) -> Bool {

    #if targetEnvironment(simulator)
      // Configure for debugging on a simulator.
      // TODO: Replace "YOUR_API_KEY" with the key from your Google Cloud project.
      let apiKey = "YOUR_API_KEY"
      GIDSignIn.sharedInstance.configureDebugProvider(withAPIKey: apiKey) { error in
        if let error {
          print("Error configuring GIDSignIn debug provider: \(error)")
        }
      }
    #else
      // Configure GIDSignIn for App Check on a real device.
      GIDSignIn.sharedInstance.configure { error in
        if let error {
          print("Error configuring GIDSignIn for App Check: \(error)")
        } else {
          print("GIDSignIn configured for App Check.")
        }
      }
    #endif

    return true
  }
}
  1. แทนที่ "YOUR_API_KEY" ในโค้ดที่ระบุด้วยคีย์ API ที่คุณคัดลอกจาก Google Cloud Console
  2. เพิ่มบรรทัดต่อไปนี้ภายในโครงสร้าง App ก่อนตัวแปร body ซึ่งจะลงทะเบียนคลาส AppDelegate กับวงจรของแอป ทำให้คลาสตอบสนองต่อการเปิดแอปและเหตุการณ์อื่นๆ ของระบบได้
@UIApplicationDelegateAdaptor(AppDelegate.self) var delegate

ไฟล์แอปหลักควรมีลักษณะดังนี้

import GoogleSignIn
import SwiftUI

class AppDelegate: NSObject, UIApplicationDelegate {
  func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
  ) -> Bool {

    #if targetEnvironment(simulator)
      // Configure for debugging on a simulator.
      // TODO: Replace "YOUR_API_KEY" with the key from your Google Cloud project.
      let apiKey = "YOUR_API_KEY"
      GIDSignIn.sharedInstance.configureDebugProvider(withAPIKey: apiKey) { error in
        if let error {
          print("Error configuring GIDSignIn debug provider: \(error)")
        }
      }
    #else
      // Configure GIDSignIn for App Check on a real device.
      GIDSignIn.sharedInstance.configure { error in
        if let error {
          print("Error configuring GIDSignIn for App Check: \(error)")
        } else {
          print("GIDSignIn configured for App Check.")
        }
      }
    #endif

    return true
  }
}

@main
struct iOS_Sign_in_with_Google_App: App {

  @UIApplicationDelegateAdaptor(AppDelegate.self) var delegate

  var body: some Scene {
    WindowGroup {
      ContentView()

        .onOpenURL { url in
          GIDSignIn.sharedInstance.handle(url)
        }
    }
  }
}

UIKit

  1. เปิด AppDelegate.swift
  2. อัปเดตเมธอด application(_:didFinishLaunchingWithOptions:) ให้มีการเริ่มต้น App Check ดังนี้
func application(
  _ application: UIApplication,
  didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {

  #if targetEnvironment(simulator)
    // Configure for debugging on a simulator.
    // TODO: Replace "YOUR_API_KEY" with the key from your Google Cloud project.
    let apiKey = "YOUR_API_KEY"
    GIDSignIn.sharedInstance.configureDebugProvider(withAPIKey: apiKey) { error in
      if let error {
        print("Error configuring GIDSignIn debug provider: \(error)")
      }
    }
  #else
    // Configure GIDSignIn for App Check on a real device.
    GIDSignIn.sharedInstance.configure { error in
      if let error {
        print("Error configuring GIDSignIn for App Check: \(error)")
      }
    }
  #endif

  return true
}
  1. แทนที่ "YOUR_API_KEY" ในโค้ดที่ระบุด้วยคีย์ API ที่คุณคัดลอกจาก Google Cloud Console

ไฟล์ AppDelegate.swift ควรมีลักษณะดังนี้

import GoogleSignIn
import UIKit

@main
class AppDelegate: UIResponder, UIApplicationDelegate {

  func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {

    #if targetEnvironment(simulator)
      // Configure for debugging on a simulator.
      // TODO: Replace "YOUR_API_KEY" with the key from your Google Cloud project.
      let apiKey = "YOUR_API_KEY"
      GIDSignIn.sharedInstance.configureDebugProvider(withAPIKey: apiKey) { error in
        if let error {
          print("Error configuring GIDSignIn debug provider: \(error)")
        }
      }
    #else
      // Configure GIDSignIn for App Check on a real device.
      GIDSignIn.sharedInstance.configure { error in
        if let error {
          print("Error configuring GIDSignIn for App Check: \(error)")
        }
      }
    #endif

    return true
  }

  func application(
    _ app: UIApplication,
    open url: URL,
    options: [UIApplication.OpenURLOptionsKey: Any] = [:]
  ) -> Bool {
    var handled: Bool

    handled = GIDSignIn.sharedInstance.handle(url)
    if handled {
      return true
    }
    // If not handled by this app, return false.
    return false
  }

  // MARK: UISceneSession Lifecycle

  func application(
    _ application: UIApplication,
    configurationForConnecting connectingSceneSession: UISceneSession,
    options: UIScene.ConnectionOptions
  ) -> UISceneConfiguration {
    // Called when a new scene session is being created.
    // Use this method to select a configuration to create the new scene with.
    return UISceneConfiguration(
      name: "Default Configuration",
      sessionRole: connectingSceneSession.role
    )
  }

  func application(
    _ application: UIApplication,
    didDiscardSceneSessions sceneSessions: Set<UISceneSession>
  ) {
    // Called when the user discards a scene session.
    // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
    // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
  }
}

ทดสอบการตรวจสอบแอปในโปรแกรมจำลอง

  1. ในแถบเมนู Xcode ให้ไปที่ผลิตภัณฑ์ > รูปแบบ > แก้ไขรูปแบบ
  2. เลือกเรียกใช้ในเมนูการนำทาง
  3. เลือกแท็บอาร์กิวเมนต์
  4. ในส่วนอาร์กิวเมนต์ที่ส่งเมื่อตอนเริ่ม ให้เลือก + แล้วเพิ่ม -FIRDebugEnabled อาร์กิวเมนต์การเปิดตัวนี้จะเปิดใช้การบันทึกการแก้ไขข้อบกพร่องของ Firebase
  5. เลือกปิด

หน้าเครื่องมือแก้ไขอาร์กิวเมนต์ Xcode

  1. เปิดแอปในโปรแกรมจำลอง
  2. คัดลอกโทเค็นการแก้ไขข้อบกพร่องของ App Check ที่พิมพ์ในคอนโซล Xcode

โทเค็นการแก้ไขข้อบกพร่องของ App Check ในคอนโซล Xcode

  1. ไปที่โปรเจ็กต์ในคอนโซล Firebase
  2. ขยายส่วนสร้างในเมนูการนำทาง
  3. เลือกการตรวจสอบแอป
  4. เลือกแท็บแอป
  5. วางเมาส์เหนือแอป แล้วเลือกไอคอนเมนู 3 จุด

การตั้งค่า Firebase App Check

  1. เลือกจัดการโทเค็นการแก้ไขข้อบกพร่อง
  2. เลือกเพิ่มโทเค็นการแก้ไขข้อบกพร่อง
  3. ตั้งชื่อโทเค็นการแก้ไขข้อบกพร่อง แล้ววางโทเค็นการแก้ไขข้อบกพร่องที่คัดลอกไว้ก่อนหน้านี้เป็นค่า
  4. เลือกบันทึกเพื่อลงทะเบียนโทเค็น

การจัดการโทเค็นแก้ไขข้อบกพร่องของ Firebase App Check

  1. กลับไปที่เครื่องจำลองแล้วลงชื่อเข้าใช้

อาจใช้เวลาหลายนาทีก่อนที่เมตริกจะปรากฏในคอนโซล เมื่อผู้ใช้ดำเนินการดังกล่าวแล้ว คุณจะยืนยันได้ว่า App Check ทำงานได้โดยดูจำนวนคำขอที่ยืนยันแล้วที่เพิ่มขึ้นใน 1 ใน 2 ที่ต่อไปนี้

  • ในส่วน App Check ของคอนโซล Firebase ภายในแท็บ API

เมตริก Firebase App Check

  • ในหน้าแก้ไขสำหรับไคลเอ็นต์ OAuth ใน Google Cloud Console

เมตริก App Check ของ Google Cloud Console

หลังจากตรวจสอบเมตริก App Check ของแอปและยืนยันว่าคำขอที่ถูกต้องตามกฎหมายได้รับการยืนยันแล้ว คุณควรเปิดใช้การบังคับใช้ App Check เมื่อบังคับใช้แล้ว App Check จะปฏิเสธคำขอที่ยังไม่ยืนยันทั้งหมด เพื่อให้มั่นใจว่าเฉพาะการเข้าชมจากแอปจริงของคุณเท่านั้นที่จะเข้าถึงปลายทาง OAuth 2.0 ของ Google ในนามของโปรเจ็กต์ได้

12. แหล่งข้อมูลเพิ่มเติม

ยินดีด้วย

คุณได้กำหนดค่าไคลเอ็นต์ OAuth 2.0 iOS, เพิ่มปุ่มลงชื่อเข้าใช้ด้วย Google ลงในแอป iOS, เรียนรู้วิธีปรับแต่งลักษณะของปุ่ม, ถอดรหัสโทเค็นรหัส JWT และเปิดใช้ App Check สำหรับแอป

ลิงก์ต่อไปนี้อาจช่วยคุณในขั้นตอนถัดไปได้

คำถามที่พบบ่อย