开始使用 AWS

构建 Flutter 应用程序

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

模块 3:添加身份验证

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

简介

您要添加到应用程序中的第一个 Amplify 类别是身份验证。Amplify 在后台利用 Amazon Cognito 来管理用户池和身份池。

在此模块中,您将学习如何注册、确认、登录和注销用户。我们只需使用几行代码即可为每个屏幕实现这些功能。

您将学到的内容

  • 配置身份验证类别
  • 注册用户
  • 验证用户电子邮件
  • 登录经过身份验证的用户
  • 注销经过身份验证的用户

重要概念

身份验证 – 身份验证是验证和管理用户以允许他们与应用程序的资源进行交互的过程。

 完成时间

10 分钟

 使用的服务

实施

  • 创建身份验证服务

    若要将身份验证服务添加到 Amplify 项目中,我们需要在终端的项目根目录下执行以下命令

    amplify add auth

    系统将提示您一些有关身份验证服务配置的问题。按 Enter 键为每个问题选择默认值。输出结果应该如下所示:

    ➜  photo_gallery git:(master) ✗ amplify add auth
    Using service: Cognito, provided by: awscloudformation
    
     The current configured provider is Amazon Cognito.
    
     Do you want to use the default authentication and security configuration? Default configuration
     Warning: you will not be able to edit these selections.
     How do you want users to be able to sign in? Username
     Do you want to configure advanced settings? No, I am done.

    身份验证资源完全配置后,您将看到如下所示的输出:

    Successfully added resource photogallery42b5391b locally

    如上面的输出所述,资源仅在本地添加。为了使用在本地所做的更改配置后端,我们必须运行以下命令:

    amplify push

    在将本地更改发送到后端之前,Amplify CLI 将显示一个状态报告,以确保您希望推送以下更改:

    Current Environment: dev
    
    | Category | Resource name        | Operation | Provider plugin   |
    | -------- | -------------------- | --------- | ----------------- |
    | Auth     | photogallery42b5391b | Create    | awscloudformation |
    ? Are you sure you want to continue? Yes

    在将本地更改发送到后端之前,Amplify CLI 将显示一个状态报告,以确保您希望推送以下更改:

    ✔ All resources are updated in the cloud

    还可以通过查看 /lib/amplifyconfiguration.dart 文件和检查身份验证值来验证您的身份验证资源是否已正确配置。

  • 安装依赖项

    回到 Visual Studio Code 中,打开 pubspec.yaml 并添加以下依赖项:

    ... # amplify_core: '<1.0.0'
    
    amplify_auth_cognito: '<1.0.0'
    
    ... # dev_dependencies:

    现在保存文件,让 Visual Studio Code 安装 Amplify Auth Cognito 插件。如果在保存时没有安装依赖项,您也可以从终端运行 $ flutter pub get。

    您应获得如下输出:

    exit code 0
  • 配置插件

    安装身份验证依赖项后,我们可以在 main.dart 文件的 _MyAppState._configureAmplify() 中,将身份验证插件添加到的 Amplify 实例中:

    ... // void _configureAmplify() async {
    
    _amplify.addPlugin(authPlugins: [AmplifyAuthCognito()]);
    
    ... // try {

    现在运行应用程序,并确认您仍可在日志中收到成功消息。

    如果能继续收到成功消息,就可以开始实现身份验证流的功能。如果不能,请重复上述步骤或访问初始化 Amplify 模块,确保您遵循了其中的所有步骤。

  • 实现功能

    回到创建 Flutter 应用程序模块,我们实施了 AuthService,以根据调用的函数处理 AuthState 的更新。现在,我们需要更新每个函数,以便仅在用户成功完成每个进程时更新状态。

    在 auth_service.dart 中,添加 AuthService 中的 AuthCredentials 属性:

    ... // final authStateController = StreamController<AuthState>();
    
    AuthCredentials _credentials;
    
    ... // void showSignUp() {

    此属性用于在注册过程中将 SignUpCredentials 保留在内存中,以便用户可以在系统验证其电子邮件地址后立即登录。如果不进行此设置,则用户需要前往登录屏幕手动登录。

    将 signUpWithCredentials 更新为以下内容:

    // 1
    void signUpWithCredentials(SignUpCredentials credentials) async {
      try {
        // 2
        final userAttributes = {'email': credentials.email};
    
        // 3
        final result = await Amplify.Auth.signUp(
            username: credentials.username,
            password: credentials.password,
            options: CognitoSignUpOptions(userAttributes: userAttributes));
    
        // 4
        if (result.isSignUpComplete) {
          loginWithCredentials(credentials);
        } else {
          // 5
          this._credentials = credentials;
    
          // 6
          final state = AuthState(authFlowStatus: AuthFlowStatus.verification);
          authStateController.add(state);
        }
      
      // 7
      } on AuthError catch (authError) {
        print('Failed to sign up - ${authError.cause}');
      }
    }
    1. 需要将函数更新为异步,因为我们将在注册过程中使用 await to。
    2. 我们必须创建 userAttributes,用于再注册过程中传入用户电子邮件。
    3. 我们将传入凭据提供的用户名和密码,以及包含用于通过 Cognito 注册的电子邮件的用户属性。因为这属于异步过程,所以我们必须使用 await 关键字。
    4. 如果我们能成功获得结果,则下一步应该是验证他们的电子邮件。如果注册过程因任何原因完成了,我们只需将用户登录到应用程序。
    5. 我们将 SignUpCredentials 存储在 _credentials 中,供用户验证其电子邮件时使用。
    6. 我们像之前一样将 AuthState 更新为验证,但只在成功登录并确定注册过程未完成后才执行此操作。
    7. 如果注册过程由于任何原因而失败,我们将直接把错误打印到日志中。

    将 verifyCode 更新为以下内容:

    // 1
    void verifyCode(String verificationCode) async {
     try {
       // 2
       final result = await Amplify.Auth.confirmSignUp(
           username: _credentials.username, confirmationCode: verificationCode);
    
       // 3
       if (result.isSignUpComplete) {
         loginWithCredentials(_credentials);
       } else {
         // 4
         // Follow more steps
       }
     } on AuthError catch (authError) {
       print('Could not verify code - ${authError.cause}');
     }
    }
    1. 就像对 signUpWithCredentials 执行的操作那样,我们也需要将 verifyCode 标记为异步函数。
    2. 我们将使用 _credentials 来提供用户名,并将输入的密码从 VerificationPage 传递到 confirmSignUp。
    3. 如果 confirmSignUp 中的结果指示注册已完成,则尝试使用在注册期间创建的 _credentials 来登录用户。需要注意的是,如果注册成功,我们将不再更新 AppState,因为用户仍需登录到 Amplify。
    4. 如果注册未完成,则使用该结果找出需要执行哪些额外步骤来完成注册。我们的应用程序中应不会发生此问题。

    我们已经实现了身份验证流的注册部分,但现在我们需要更新登录部分。将 loginWithCredentials 更新为以下内容:

    // 1
    void loginWithCredentials(AuthCredentials credentials) async {
     try {
       // 2
       final result = await Amplify.Auth.signIn(
           username: credentials.username, password: credentials.password);
    
       // 3
       if (result.isSignedIn) {
         final state = AuthState(authFlowStatus: AuthFlowStatus.session);
         authStateController.add(state);
       } else {
         // 4
         print('User could not be signed in');
       }
     } on AuthError catch (authError) {
       print('Could not login - ${authError.cause}');
     }
    }
    1. 由于 loginWithCredentials 将 AuthCredentials 作为形参,因此无论传递的是 LoginCredentials 还是 SignUpCredentials,它都可以正常运行。
    2. 我们将 AuthCredentials 用户名和密码传递给 Amplify 登录方法并等待结果。
    3. 如果登录成功,且该结果的 isSignedIn 属性确认用户现在已登录,则将状态更新为会话。
    4. 我们的应用程序中不应更新为此状态。如果用户输入的凭据有误或收到任何其他错误,则将触发 catch 块。

    现在,更新 logOut 方法:

    void logOut() async {
     try {
       // 1
       await Amplify.Auth.signOut();
    
       // 2
       showLogin();
     } on AuthError catch (authError) {
       print('Could not log out - ${authError.cause}');
     }
    }
    1. 如果我们在不传入任何选项的情况下调用 Auth.signOut(),则我们将仅注销此设备上的用户,而不是注销所有设备上的用户。
    2. 我们可以重用 showLogin() 方法来更新状态,并在注销成功后将用户定向回登录屏幕。

    最后,如果用户关闭了应用程序,但已经在前一个会话中登录,那么我们应该能够自动登录该用户。将此最终函数添加到 AuthService。

    void checkAuthStatus() async {
     try {
       await Amplify.Auth.fetchAuthSession();
    
       final state = AuthState(authFlowStatus: AuthFlowStatus.session);
       authStateController.add(state);
     } catch (_) {
       final state = AuthState(authFlowStatus: AuthFlowStatus.login);
       authStateController.add(state);
     }
    }

    checkAuthStatus 将尝试获取当前 AuthSession;如果成功,则用户将登录。如果获取失败,则意味着用户没有登录,应显示 LoginPage。

    目前,我们正在 initState 方法的 showLogin 内调用 _MyAppState。我们来将其更改为 checkAuthStatus:

    ... // _configureAmplify();
    
    _authService.checkAuthStatus();
    
    ... // initState closing }

    这些是补充我们现有身份验证流所需的唯一修改。构建和运行应用程序后,您应能够注册、确认电子邮件、注销和再次登录。

结论

您已成功将用户身份验证添加到照片库应用程序! 在下一个模块中,我们将向应用程序添加存储。

此模块有帮助吗?