使用SwiftUI的iOS认证——第2部分用户配置文件

130 阅读6分钟

教程章节

在本教程的前一部分中,你创建了一个基于SwiftUI的iOS应用,该应用使用Auth0实现基本的登录和注销功能。在这一部分中,你将增强你的应用程序,让它能够读取用户的个人资料,在用户登录时显示其照片、姓名和电子邮件地址。

显示用户的资料信息

应用程序只 "知道 "用户在其当前状态下是登录还是注销。它还拥有关于用户身份的信息,这些信息在ID令牌中被编码。让我们提取这些用户信息--用户资料--并在用户登录时使用它来显示用户的姓名、电子邮件地址和图片。

当你完成这一部分后,应用程序的 "登录 "屏幕将看起来像这样。

The app’s “logged in” screen, now displaying the user’s picture, name, and email address.

为用户资料创建一个数据结构

在我们从ID令牌中提取用户的资料信息之前,我们需要建立一个数据结构来存储它。让我们为此目的创建一个struct

🛠 右键单击(或控制单击)项目资源管理器中的SwiftUI 登录演示文件夹,选择 "新文件",为struct 创建一个新的 Swift 文件...。

Xcode screenshot, showing the user selecting “File -> New File...”

🛠 在出现的窗口中,确保选择iOS标签。选择Swift文件,然后点击下一步

Xcode screenshot, showing the selection of the “Swift File” file template..

🛠 命名该文件 Profile.swift并单击"创建"来创建文件。

Xcode screenshot, showing the “Save” dialog box for the Swift file.

现在有了一个Profile struct ,让我们每次一点点地实现它。

🛠用以下内容替换Profile 的内容。

// 1
import JWTDecode


// 2
struct Profile {
  let id: String
  let name: String
  let email: String
  let emailVerified: String
  let picture: String
  let updatedAt: String
}

下面是对上面代码中的编号注释的解释。

  1. ID令牌的格式是JWT,即JSON Web令牌JWTDecode 库允许你对令牌进行解码,以提取其包含的用户资料信息。

  2. 这段代码定义了Profile ,这个struct ,它将解码并存储ID令牌中的用户资料信息。它有以下属性,所有这些都是字符串。

    • id:用户的唯一标识符
    • name:用户的全名
    • email:用户的电子邮件地址
    • emailVerified: true如果用户向Auth0验证了他们的电子邮件地址。 false否则
    • picture:用户图片的URL
    • updatedAt:用户资料最后更新的日期和时间

🛠 在Profile 的定义后添加以下内容。

extension Profile {

}

我们再一次使用extension ,将一个struct 分成更小的部分,以便于阅读和更新。这个扩展将包含方法和类似方法的变量。

🛠新创建的extension添加以下变量声明。

  static var empty: Self {
    return Profile(
      id: "",
      name: "",
      email: "",
      emailVerified: "",
      picture: "",
      updatedAt: ""
    )
  }

这定义了empty ,一个静态变量,它的作用更像一个函数。它创建了一个新的Profile 实例,其属性都被设置为空字符串。

🛠 在empty 的声明之后,立即将此函数添加到extension

static func from(_ idToken: String) -> Self {
  guard 
    let jwt = try? decode(jwt: idToken),
        let id = jwt.subject,
        let name = jwt.claim(name: "name").string,
        let email = jwt.claim(name: "email").string,
        let emailVerified = jwt.claim(name: "email_verified").boolean,
        let picture = jwt.claim(name: "picture").string,
        let updatedAt = jwt.claim(name: "updated_at").string
  else {
    return .empty
  }
  
  return Profile(
    id: id,
    name: name,
    email: email,
    emailVerified: String(describing: emailVerified),
    picture: picture,
    updatedAt: updatedAt
  )
}

给出一个ID令牌字符串,该 from()函数创建一个Profile 实例。如果 from()能够从ID令牌中提取声称--关于用户身份的值,包括他们的名字、电子邮件地址和他们的照片的URL--它返回一个Profile 实例,其属性中包含这些信息。否则,它将返回一个空属性的Profile 实例。

更新用户界面

现在有了一种从ID标记中提取信息的方法,让我们把它用起来。在这一步,我们将对用户界面进行修改,使其能够显示登录用户的姓名、电子邮件地址和照片。

🛠 打开ContentView ,在isAuthenticated ,紧接着添加一个新属性。注意注释中告诉你要添加新代码的地方。

  @State private var isAuthenticated = false
  // 👇🏽👇🏽👇🏽 New line of code here!
  @State var userProfile = Profile.empty
  // 👆🏽👆🏽👆🏽

这就创建了userProfile ,这是一个Profile 的实例,当用户登录时,它将包含有关用户的信息。应用程序将使用其属性来显示用户的姓名、电子邮件地址和照片。

由于userProfile 是用@State 属性标记的,它定义了用户界面的状态。每当userProfile 或它的一个属性发生变化时,应用程序就会重新绘制用户界面以反映这一变化。

🛠 在body 属性中添加用户界面元素,以显示用户的信息。再一次,注释会告诉你在哪里添加新代码。

  var body: some View {

    if isAuthenticated {
      
      // 3
      VStack {
        
        // 4
        Text("Logged in")
          .padding()
        
        // 👇🏽👇🏽👇🏽 New lines of code here!
        AsyncImage(url: URL(string: userProfile.picture)) { image in
          image
            .frame(maxWidth: 128)
        } placeholder: {
          Image(systemName: "photo.circle.fill")
            .resizable()
            .scaledToFit()
            .frame(maxWidth: 128)
            .foregroundColor(.gray)
            .opacity(0.5)
        }
        .padding(40)
        
        VStack {
          Text("Name: \(userProfile.name)")
          Text("Email: \(userProfile.email)")
        }
        .padding()
        // 👆🏽👆🏽👆🏽
        
        // 5
        Button("Log out") {
          logout()
        }
        .padding()
        
      }
      
    } else {
    
    // The rest of the “body” property goes here...

新的代码在ContentView 中添加了两个新的视图。

  1. 一个AsyncImage ,这个视图将异步下载用户的图片,并在下载完成后显示。它使用placeholder 选项,在下载用户图片的同时显示iOS内置图标集的相机图标。
  2. 一个VStack 包含两个Text 视图:一个显示用户的姓名,一个显示用户的电子邮件地址。

🛠 滚动到定义了ContentView 方法的extension ,并更新 login()来从ID标记中提取用户的资料信息。下面代码中的注释将告诉你在哪里添加新行。

  func login() {
    Auth0 // 1
      .webAuth() // 2
      .start { result in // 3
        switch result {
          // 4
          case .failure(let error):
            print("Failed with: \(error)")
          // 5
          case .success(let credentials):
            self.isAuthenticated = true
            // 👇🏽👇🏽👇🏽 New line of code here!
            self.userProfile = Profile.from(credentials.idToken)
            // 👆🏽👆🏽👆🏽
            print("Credentials: \(credentials)")
            print("ID token: \(credentials.idToken)")
        }
      }
  }

新添加的这行代码在用户登录和应用程序收到ID令牌后运行。它从ID令牌中的数据创建一个新的Profile 实例,并将ContentView'suserProfile 属性设置为该实例。

运行应用程序

运行应用程序,并确认所做的更改是否有效。当你登录时,你应该看到用户的姓名、电子邮件地址和照片。

接下来的步骤

在这个练习中,你已经覆盖了很多地方。你不仅使用SwiftUI框架建立了一个iOS应用程序,而且还让它具有用Auth0验证用户的能力。

你可以在Auth0博客样本GitHub账户的get-started-ios-authentication-swiftui仓库中下载一个完整的项目。

SwiftUI是一个广泛的话题,我们在本教程中只触及了它的表面。对于你下一步的探索,你可能想看看这些有用的资源。

这是关于使用Auth0进行iOS开发的新系列文章中的第二篇。未来的文章将深入探讨iOS和Auth0的认证和授权,以及标准用户名和密码的替代方法。请关注这个空间。