开始使用 AWS

构建 iOS 应用程序

使用 AWS Amplify 创建简单的 iOS 应用程序

模块 3:添加身份验证

在此模块中,您将使用 Amplify CLI 和库配置和添加身份验证到您的应用程序中。

简介

您将添加的下一个功能是用户身份验证。在此模块中,您将了解如何使用 Amplify CLI 和库对用户进行身份验证,以利用托管用户身份提供商 Amazon Cognito

您还将了解如何使用 Cognito 托管用户界面展示整个用户身份验证流,从而使用户只需几行代码即可注册、登录和重置密码。

使用“托管用户界面”意味着应用程序利用 Cognito 网页登录和注册用户界面流。应用程序的用户将重定向到 Cognito 托管的网页,并在登录后重定向回应用程序。当然,Cognito 和 Amplify 也支持本机 UI,您可以按照这些研讨会说明了解有关自定义身份验证 UI 的更多信息。

您将学到的内容

  • 创建和部署身份验证服务
  • 配置 iOS 应用程序以包括 Cognito 托管的 UI 身份验证

重要概念

Amplify 库 – 您可以使用 Amplify 库从 Web 应用程序或移动应用程序中与 AWS 服务互动。

身份验证 – 在软件中,身份验证是使用身份验证服务或 API 验证和管理用户身份的过程。

 完成时间

10 分钟

 使用的服务

实施

  • 要创建身份验证服务,请打开一个终端,然后执行以下命令:

    amplify add auth
    
    ? Do you want to use the default authentication and security configuration? Select Default configuration with Social Provider and press enter
    ? How do you want users to be able to sign in? Select the default Username and press enter
    ? Do you want to configure advanced settings? Select the default No, I am done and press enter
    ? What domain name prefix do you want to use? Select the default and press enter
    Enter your redirect signin URI: type gettingstarted:// and press enter
    ? Do you want to add another redirect signin URI? Select the default N and press enter
    Enter your redirect signout URI: type gettingstarted:// and press enter
    ? Do you want to add another redirect signout URI? Select the default N and press enter
    ? Select the social providers you want to configure for your user pool: do not select any provider and press enter

    当您看到此消息时,即表示配置成功(资源的确切名称将有所不同):

    Successfully added resource iosgettingstartedfc5a4717 locally
  • 现在,已在本地配置身份验证服务,我们可以将它部署到云:在终端中,请在项目目录中执行以下命令

    amplify push
    
    # press Y when asked to continue

    片刻之后,您应看到以下消息:

    ✔ All resources are updated in the cloud
    
    Hosted UI Endpoint: https://iosgettingstarted-dev.auth.eu-central-1.amazoncognito.com/
    Test Your Hosted UI Endpoint: https://iosgettingstarted-dev.auth.eu-central-1.amazoncognito.com/login?response_type=code&client_id=1234567890&redirect_uri=gettingstarted://
  • 在转至代码之前,请将 Amplify 身份验证库添加到项目的依赖项中。打开 Podfile 文件,然后使用 AmplifyPlugins/AWSCognitoAuthPlugin 添加行,或者复制并粘贴以下整个文件

    # you need at least version 13.0 for this tutorial, more recent versions are valid too
    platform :ios, '13.0'
    
    target 'getting started' do
      # Comment the next line if you don't want to use dynamic frameworks
      use_frameworks!
    
      # Pods for getting started
      pod 'Amplify', '~> 1.0'                             # required amplify dependency
      pod 'Amplify/Tools', '~> 1.0'                       # allows to call amplify CLI from within Xcode
    
      pod 'AmplifyPlugins/AWSCognitoAuthPlugin', '~> 1.0' # support for Cognito user authentication
    
    end

    在终端执行以下命令:

    pod install

    该命令需要几秒钟才能完成。您将看到(实际版本号可能有所不同):

    Analyzing dependencies
    Downloading dependencies
    Installing AWSAuthCore (2.14.1)
    Installing AWSCognitoIdentityProvider (2.14.1)
    Installing AWSCognitoIdentityProviderASF (1.0.1)
    Installing AWSCore (2.14.1)
    Installing AWSMobileClient (2.14.1)
    Installing AWSPluginsCore (1.0.4)
    Installing AmplifyPlugins (1.0.4)
    Generating Pods project
    Integrating client project
    Pod installation complete! There are 3 dependencies from the Podfile and 8 total pods installed.
  • 返回到 Xcode,打开 Backend.swift 文件。在后端类中,

    • 为 AmplifyPlugins 添加导入语句
    • 向上一节中添加的 Amplify 初始化代码中添加一行

    完整代码块应如下所示:

    // at the top of the file
    import AmplifyPlugins
    
    private init () {
      // initialize amplify
      do {
         try Amplify.add(plugin: AWSCognitoAuthPlugin())
         try Amplify.configure()
         print("Initialized Amplify")
      } catch {
         print("Could not initialize Amplify: \(error)")
      }
    }

    要验证一切是否都按预期运行,请构建项目。单击 Product 菜单,然后选择 Build,或按 ⌘B。应该不会出现错误。

  • 其余代码更改会跟踪用户的状态(他们是否已登录?)并在用户未登录时触发登录/注册用户界面。 

    a.添加登录和注销代码。在后端类中的任意位置,添加以下三种方法:

     

    // MARK: - User Authentication
    
    // signin with Cognito web user interface
    public func signIn() {
    
        _ = Amplify.Auth.signInWithWebUI(presentationAnchor: UIApplication.shared.windows.first!) { result in
            switch result {
            case .success(_):
                print("Sign in succeeded")
            case .failure(let error):
                print("Sign in failed \(error)")
            }
        }
    }
    
    // signout
    public func signOut() {
    
        _ = Amplify.Auth.signOut() { (result) in
            switch result {
            case .success:
                print("Successfully signed out")
            case .failure(let error):
                print("Sign out failed with error \(error)")
            }
        }
    }
    
    // change our internal state, this triggers an UI update on the main thread
    func updateUserData(withSignInStatus status : Bool) {
        DispatchQueue.main.async() {
            let userData : UserData = .shared
            userData.isSignedIn = status
        }
    }

    b.添加身份验证中心侦听器

    为了跟踪身份验证状态的变化,我们添加了代码以订阅由 Amplify 发送的身份验证事件。我们在 Backend.init() 方法中初始化该中心。

    在收到身份验证事件时,我们将调用 updateUserData() 方法。此方法可使 UserData 对象保持同步。UserData.isSignedIn 属性为 @Published,这意味着当值更改时,用户界面会自动刷新。 

    我们还添加了代码以在应用程序启动时检查以前的身份验证状态。当应用程序启动时,它会检查 Cognito 会话是否已存在,并相应地更新 UI。

    在 Backend.init() 中,请在 Amplify 初始化后添加以下代码

    // in private init() function
    // listen to auth events.
    // see https://github.com/aws-amplify/amplify-ios/blob/master/Amplify/Categories/Auth/Models/AuthEventName.swift
    _ = Amplify.Hub.listen(to: .auth) { (payload) in
    
        switch payload.eventName {
    
        case HubPayload.EventName.Auth.signedIn:
            print("==HUB== User signed In, update UI")
            self.updateUserData(withSignInStatus: true)
    
        case HubPayload.EventName.Auth.signedOut:
            print("==HUB== User signed Out, update UI")
            self.updateUserData(withSignInStatus: false)
    
        case HubPayload.EventName.Auth.sessionExpired:
            print("==HUB== Session expired, show sign in UI")
            self.updateUserData(withSignInStatus: false)
    
        default:
            //print("==HUB== \(payload)")
            break
        }
    }
     
    // let's check if user is signedIn or not
     _ = Amplify.Auth.fetchAuthSession { (result) in
         do {
             let session = try result.get()
                    
    // let's update UserData and the UI
         self.updateUserData(withSignInStatus: session.isSignedIn)
                    
         } catch {
              print("Fetch auth session failed with error - \(error)")
        }
    }    

    c.更新用户界面代码

    代码中的最后一个更改与用户界面相关,我们将 ZStack 添加到 ContentView。根据 UserData.isSignedIn 的值,UI 将显示 SigninButton 或主列表视图。

    打开 ContentView.swift 并替换 ContentView 结构中的正文:

    var body: some View {
    
        ZStack {
            if (userData.isSignedIn) {
                NavigationView {
                    List {
                        ForEach(userData.notes) { note in
                            ListRow(note: note)
                        }
                    }
                    .navigationBarTitle(Text("Notes"))
                    .navigationBarItems(leading: SignOutButton())
                }
            } else {
                SignInButton()
            }
        }
    }

    在同一文件中,添加 SignInButton 和 SignOutButton 视图:

    struct SignInButton: View {
        var body: some View {
            Button(action: { Backend.shared.signIn() }){
                HStack {
                    Image(systemName: "person.fill")
                        .scaleEffect(1.5)
                        .padding()
                    Text("Sign In")
                        .font(.largeTitle)
                }
                .padding()
                .foregroundColor(.white)
                .background(Color.green)
                .cornerRadius(30)
            }
        }
    }
    
    struct SignOutButton : View {
        var body: some View {
            Button(action: { Backend.shared.signOut() }) {
                    Text("Sign Out")
            }
        }
    }

    要验证一切是否都按预期运行,请构建项目。单击 Product 菜单,然后选择 Build,或按 ⌘B。应该不会出现错误。

    d.更新 Info.plist

    最后,我们必须确保在 Cognito 托管用户界面提供的 Web 身份验证序列结束时启动我们的应用程序。我们将 gettingstarted URI 方案添加到应用程序的 Info.plist 文件中。

    在 Xcode 中,选择 Info.plist 文件,右键单击该文件,然后选择“打开为源代码”。

    在顶部 <dict> 元素添加以下 <key> 和 <array> 元素。

    <plist version="1.0">
    
        <dict>
        <!-- YOUR OTHER PLIST ENTRIES HERE -->
    
        <!-- ADD AN ENTRY TO CFBundleURLTypes for Cognito Auth -->
        <!-- IF YOU DO NOT HAVE CFBundleURLTypes, YOU CAN COPY THE WHOLE BLOCK BELOW -->
        <key>CFBundleURLTypes</key>
        <array>
            <dict>
                <key>CFBundleURLSchemes</key>
                <array>
                    <string>gettingstarted</string>
                </array>
            </dict>
        </array>
    
        <!-- ... -->
        </dict>

    e.构建和测试

    要验证一切是否都按预期运行,请构建项目。单击 Product 菜单,然后选择 Run,或按 ⌘R。应该不会出现错误。应用程序将在“登录”按钮上启动。

    以下是完整的注册流程:

结论

您现在已使用几行代码将用户身份验证添加到您的应用程序中! 在下一个模块中,我们将添加 API 到您的应用程序中。

此模块有帮助吗?

添加 GraphQL API 和数据库