AWS 入门

构建 Android 应用程序

使用 AWS Amplify 创建简易 Android 应用程序

模块 3:添加身份验证

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

简介

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

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

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

您将学到的内容

  • 创建和部署身份验证服务
  • 配置 Android 应用程序以包含 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 androidgettingstartedfc5a4717 locally
  • 现在,已在本地配置身份验证服务,我们可以将它部署到云:在终端中,请在项目目录中执行以下命令

    amplify push
    
    # press Y when asked to continue

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

    ✔ All resources are updated in the cloud
    
    Hosted UI Endpoint: https://androidgettingstarted-dev.auth.eu-central-1.amazoncognito.com/
    Test Your Hosted UI Endpoint: https://androidgettingstarted-dev.auth.eu-central-1.amazoncognito.com/login?response_type=code&client_id=1234567890&redirect_uri=gettingstarted://
  • 在转到代码之前,请先返回 Android Studio,将以下依赖项连同您之前添加的其他 `amplifyframework` 实现一起,添加到您的模块的 `build.gradle`,然后在看到提示时,单击 Sync Now

    dependencies {
        ...
        // Amplify core dependency
        implementation 'com.amplifyframework:core:1.4.0'
        implementation 'com.amplifyframework:aws-auth-cognito:1.4.0'
    }
  • 返回 Android Studio,打开 Backend.kt 文件。在后端类中,向我们在上一部分(在 initialize() 方法中)添加的 Amplify 初始化代码添加一行

    完整代码块应如下所示:

    // inside Backend class
    fun initialize(applicationContext: Context) : Backend {
        try {
            Amplify.addPlugin(AWSCognitoAuthPlugin())
            Amplify.configure(applicationContext)
    
            Log.i(TAG, "Initialized Amplify")
        } catch (e: AmplifyException) {
            Log.e(TAG, "Could not initialize Amplify", e)
        }
        return this
    }

    请不要忘记添加导入语句,Android Studio 会自动为您完成此操作(在 Mac 上,在代码编辑器检测到的每个错误上,同时按 Alt 和 Enter 键)。

    像在上一步骤中那样,为每个缺少的类定义添加所需的导入语句(在红色单词上同时按 Alt 和 Enter 键)。

    要验证一切是否都按预期运行,请构建项目。单击 Build 菜单,并选择 Make Project,或者,在 Mac 上按 ⌘F9。应该不会出现错误。

  • 其余代码更改会跟踪用户的状态(他们是否已登录?)并在用户单击锁定图标时触发“SignIn/SignUp”用户界面。

    a.添加 signIn 和 signOut 方法
    在后端类中的任意位置,添加以下四种方法:
    private fun updateUserData(withSignedInStatus : Boolean) {
        UserData.setSignedIn(withSignedInStatus)
    }
    
    fun signOut() {
        Log.i(TAG, "Initiate Signout Sequence")
    
        Amplify.Auth.signOut(
            { Log.i(TAG, "Signed out!") },
            { error -> Log.e(TAG, error.toString()) }
        )
    }
    
    fun signIn(callingActivity: Activity) {
        Log.i(TAG, "Initiate Signin Sequence")
    
        Amplify.Auth.signInWithWebUI(
            callingActivity,
            { result: AuthSignInResult ->  Log.i(TAG, result.toString()) },
            { error: AuthException -> Log.e(TAG, error.toString()) }
        )
    }

    然后为每个缺少的类定义添加所需的导入语句(在红色单词上按 Alt 和 Enter 键)。当您可以在多个类之间进行选择时,请务必从 Amplify 包中选择一个,如下面的屏幕截图所示。

    请注意,我们没有在这些方法中更新 UserData.isSignedIn 标记,该操作将在下一节中完成。

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

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

    在收到身份验证事件时,我们将调用 updateUserData() 方法。此方法可使 UserData 对象保持同步。UserData.isSignedIn 属性是 LiveData<Boolean>,这意味着当值更改时,订阅此属性的观察者将收到通知。我们使用此机制来自动刷新用户界面。您可以在 Android 文档中了解关于 LiveData 的更多信息

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

    在 Backend.initialize() 中,在 try/catch 块之后和 return 语句之前添加以下代码

    // in Backend.initialize() function, after the try/catch block but before the return statement 
    
    Log.i(TAG, "registering hub event")
    
    // listen to auth event
    Amplify.Hub.subscribe(HubChannel.AUTH) { hubEvent: HubEvent<*> ->
    
        when (hubEvent.name) {
            InitializationStatus.SUCCEEDED.toString() -> {
                Log.i(TAG, "Amplify successfully initialized")
            }
            InitializationStatus.FAILED.toString() -> {
                Log.i(TAG, "Amplify initialization failed")
            }
            else -> {
                when (AuthChannelEventName.valueOf(hubEvent.name)) {
                    AuthChannelEventName.SIGNED_IN -> {
                        updateUserData(true)
                        Log.i(TAG, "HUB : SIGNED_IN")
                    }
                    AuthChannelEventName.SIGNED_OUT -> {
                        updateUserData(false)
                        Log.i(TAG, "HUB : SIGNED_OUT")
                    }
                    else -> Log.i(TAG, """HUB EVENT:${hubEvent.name}""")
                }
            }
        }
    }
    
    Log.i(TAG, "retrieving session status")
    
    // is user already authenticated (from a previous execution) ?
    Amplify.Auth.fetchAuthSession(
        { result ->
            Log.i(TAG, result.toString())
            val cognitoAuthSession = result as AWSCognitoAuthSession
            // update UI
            this.updateUserData(cognitoAuthSession.isSignedIn)
            when (cognitoAuthSession.identityId.type) {
                AuthSessionResult.Type.SUCCESS ->  Log.i(TAG, "IdentityId: " + cognitoAuthSession.identityId.value)
                AuthSessionResult.Type.FAILURE -> Log.i(TAG, "IdentityId not present because: " + cognitoAuthSession.identityId.error.toString())
            }
        },
        { error -> Log.i(TAG, error.toString()) }
    )

    要验证一切是否都按预期运行,请构建项目。单击 Build菜单,并选择 Make Project,或者,在 Mac 上按 ⌘F9。应该不会出现错误。

    c.更新用户界面代码

    代码中的最后一个更改与用户界面相关,我们将 FloatingActionButton 添加到主要活动中。

    在“res/layout”下,打开 activity_main.xml,并将现有的 FloatingActionButton 替换为以下内容:

    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:id="@+id/fabAuth"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_gravity="bottom|end"
        android:layout_margin="@dimen/fab_margin"
        android:src="@drawable/ic_baseline_lock"
        app:fabCustomSize="60dp"
        app:fabSize="auto"
        />

    在“res/drawable”下添加一个锁状图标。右键单击“drawable”,选择 New,然后选择 Vector Asset。从 Clilp Art 中选择锁状图标,然后输入 ic_baseline_lock(不含 _24)作为名称,并从 Clip Art 中选择闭合的锁状图标。单击 Next,然后单击 Finish

    对打开的锁状图标重复相同的操作。

    执行完以上操作后,您的“drawable”目录下应具有以下文件:

    现在,在代码中链接新创建的按钮。在 java/com.example.androidgettingstarted/ 下,打开 MainActivity.kt 并添加以下代码。

    // anywhere in the MainActivity class
    private fun setupAuthButton(userData: UserData) {
    
        // register a click listener
        fabAuth.setOnClickListener { view ->
    
            val authButton = view as FloatingActionButton
    
            if (userData.isSignedIn.value!!) {
                authButton.setImageResource(R.drawable.ic_baseline_lock_open)
                Backend.signOut()
            } else {
                authButton.setImageResource(R.drawable.ic_baseline_lock_open)
                Backend.signIn(this)
            }
        }
    }

    还是在 MainActivity 中,在 onCreate() 方法的末尾添加以下代码

    setupAuthButton(UserData)
    
    UserData.isSignedIn.observe(this, Observer<Boolean> { isSignedUp ->
        // update UI
        Log.i(TAG, "isSignedIn changed : $isSignedUp")
    
        if (isSignedUp) {
            fabAuth.setImageResource(R.drawable.ic_baseline_lock_open)
        } else {
            fabAuth.setImageResource(R.drawable.ic_baseline_lock)
        }
    })

    以上代码会针对 Userdata.isSignedIn 值注册观察者。当 isSignedIn 值更改时调用闭包。现在,我们只是更改锁状图标:当用户通过身份验证时为打开的锁,当用户没有会话时为闭合的锁。

    要验证一切是否都按预期运行,请构建项目。单击 Build 菜单,并选择 Make Project,或者,在 Mac 上按 ⌘F9。应该不会出现错误。

    d.更新 AndroidManifest.xml 和 MainActivity

    最后,我们必须确保在 Cognito 托管用户界面提供的 Web 身份验证序列结束时启动我们的应用程序。我们在清单文件中添加一个新的活动。当接收到 gettingstarted URI 方案时,将调用该活动。

    在 Android Studio 中的“manifests”下,打开 AndroidManifest.xml,并在应用程序元素中添加以下活动。

        <activity
    android:name="com.amazonaws.mobileconnectors.cognitoauth.activities.CustomTabsRedirectActivity">
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />
    
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />
    
                <data android:scheme="gettingstarted" />
            </intent-filter>
        </activity>
    

    在 java/com.example.androidgettingstarted/ 下,打开 MainActivity.kt 并在类中的任意位置添加以下代码。

    // MainActivity.kt
    // receive the web redirect after authentication
    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        Backend.handleWebUISignInResponse(requestCode, resultCode, data)
    }

    在 java/com.example.androidgettingstarted/ 下,打开 Backend.kt 并在类中的任意位置添加以下代码。

    // Backend.kt
    // pass the data from web redirect to Amplify libs 
    fun handleWebUISignInResponse(requestCode: Int, resultCode: Int, data: Intent?) {
        Log.d(TAG, "received requestCode : $requestCode and resultCode : $resultCode")
        if (requestCode == AWSCognitoAuthPlugin.WEB_UI_SIGN_IN_ACTIVITY_CODE) {
            Amplify.Auth.handleWebUISignInResponse(data)
        }
    }

    e.构建和测试

    要验证一切是否都按预期运行,请构建并运行项目。单击工具栏中的运行图标 ▶️,或按 ^ R。应该不会出现错误。应用程序将启动,且屏幕右下角会显示一个闭合的锁状浮动按钮。

    以下是完整的注册流程。

结论

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

添加 GraphQL API 和数据库