Wear 中的身份验证

随着独立手表的出现,Wear OS 应用现在可以完全独立地在手表上运行,而无需配套应用的协助。这种新的能力也意味着,当 Wear OS 独立应用需要访问云端数据时,它们需要自行管理身份验证。Wear OS 支持多种身份验证方法,以便独立 Wear 应用能够获得用户身份验证凭据。

目前,Wear OS 支持以下身份验证方法:

下面几节介绍如何将上述身份验证方法集成到您的 Wear 应用中。

Google 登录

Google 登录这种方法可让用户使用其现有的 Google 帐号登录。此方法能够提供最佳的用户体验,并且易于提供支持,尤其是您已经在手持式设备应用中实现了这些解决方案时。

Google 登录是最受青睐的解决方案,因为它在 iOS 上也运行良好。下一节将介绍如何完成基本的 Google 登录集成。

前提条件

要将 Google 登录集成到您的 Wear 应用中,您必须先配置一个 Google API 控制台项目并设置您的 Android Studio 项目。如需了解详情,请参阅 Google 登录集成入门指南

注意:如果您在与后端服务器通信的应用或网站上使用 Google 登录,请为后端服务器创建一个 OAuth 2.0 Web 应用客户端 ID。此客户端 ID 不同于您的应用的客户端 ID。如需了解详情,请参阅启用服务器端访问

重要提示:如果您的应用与后端服务器通信,则可以使用 HTTPS 发送用户的 ID 令牌,以便在该服务器上安全地识别当前已登录的用户。要了解如何在后端服务器上对用户进行身份验证,请参阅后端服务器身份验证

将 Google 登录集成到您的应用中

要将 Google 登录集成到您的 Wear 应用中,请执行以下操作:

  1. 配置 Google 登录
  2. 添加 Google 登录按钮
  3. 用户点击登录按钮后启动登录流程

配置 Google 登录并构建 GoogleApiClient 对象

在登录 Activity 的 onCreate 方法中,将 Google 登录配置为请求应用所要求的用户数据。然后,创建一个 GoogleApiClient 对象,并使其可以访问 Google Sign-In API 以及您指定的选项。

Kotlin

    // Configure sign-in to request the user's ID, email address, and basic
    // profile. The ID and basic profile are included in DEFAULT_SIGN_IN.
    // If you need to request additional scopes to access Google APIs, specify them with
    // requestScopes().
    googleApiClient = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
            .requestEmail()
            .build()
            .let { signInConfigBuilder ->
                // Build a GoogleApiClient with access to the Google Sign-In API and the
                // options specified in the sign-in configuration.
                GoogleApiClient.Builder(this)
                        .enableAutoManage(this /* FragmentActivity */, this /* OnConnectionFailedListener */)
                        .addApi(Auth.GOOGLE_SIGN_IN_API, signInConfigBuilder)
                        .build()
            }
    

Java

    // Configure sign-in to request the user's ID, email address, and basic
    // profile. The ID and basic profile are included in DEFAULT_SIGN_IN.
    // If you need to request additional scopes to access Google APIs, specify them with
    // requestScopes().
    GoogleSignInOptions.Builder signInConfigBuilder = new GoogleSignInOptions
            .Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
            .requestEmail()
            .build();

    // Build a GoogleApiClient with access to the Google Sign-In API and the
    // options specified in the sign-in configuration.
    googleApiClient = new GoogleApiClient.Builder(this)
            .enableAutoManage(this /* FragmentActivity */, this /* OnConnectionFailedListener */)
            .addApi(Auth.GOOGLE_SIGN_IN_API, signInConfigBuilder)
            .build();
    

在应用中添加 Google 登录按钮

  1. 在应用的布局中添加 SignInButton
  2.      <com.google.android.gms.common.SignInButton
         android:id="@+id/sign_in_button"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content" />
        
  3. 在应用的 onCreate() 方法中,注册按钮的 OnClickListener,让用户在点击按钮后登录。
  4. Kotlin

        findViewById<View>(R.id.sign_in_button).setOnClickListener(this)
        

    Java

        findViewById(R.id.sign_in_button).setOnClickListener(this);
        

创建登录 Intent 并启动登录流程

在用户点击登录按钮时,使用 getSignInIntent 方法创建登录 Intent,然后使用 startActivityForResult 方法启动该 Intent,以处理 onCLick() 方法中的登录按钮点按操作。

Kotlin

    Auth.GoogleSignInApi.getSignInIntent(googleApiClient).also { signInIntent ->
        startActivityForResult(signInIntent, RC_SIGN_IN)
    }
    

Java

    Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(googleApiClient);
    startActivityForResult(signInIntent, RC_SIGN_IN);
    

系统会提示用户选择用于登录的 Google 帐号。如果请求访问的范围超出了个人资料、电子邮件和 OpenID,系统还会提示用户授予对这些资源的访问权限。

最后,在 Activity 的 onActivityResult 方法中,使用 getSignInResultFromIntent 获取登录结果。获取登录结果后,您可以使用 isSuccess 方法检查登录是否成功。如果登录成功,您可以调用 getSignInAccount 方法来获取 GoogleSignInAccount 对象,该对象包含有关登录用户的信息,如用户名称。

Kotlin

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
        super.onActivityResult(requestCode, resultCode, data)

        // Result returned from launching the Intent from GoogleSignInApi.getSignInIntent(...)
        if (requestCode == RC_SIGN_IN) {
            Auth.GoogleSignInApi.getSignInResultFromIntent(data)?.apply {
                if (isSuccess) {
                    // Get account information
                    fullName = signInAccount?.displayName
                    mGivenName = signInAccount?.givenName
                    mFamilyName = signInAccount?.familyName
                    mEmail = signInAccount?.email
                }
            }
        }
    }
    

Java

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        // Result returned from launching the Intent from GoogleSignInApi.getSignInIntent(...)
        if (requestCode == RC_SIGN_IN) {
            GoogleSignInResult signInResult = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
            if (signInResult.isSuccess()) {
                GoogleSignInAccount acct = signInResult.getSignInAccount();

                // Get account information
                fullName = acct.getDisplayName();
                givenName = acct.getGivenName();
                familyName = acct.getFamilyName();
                email = acct.getEmail();
            }
        }
    }
    

要查看实现了 Google 登录的应用示例,请参阅应用示例

OAuth 2.0 支持

Wear 为第三方应用提供 OAuth 2.0 支持,以便它们能够使用网络服务对用户进行身份验证。考虑到 Wear 设备的屏幕空间有限,Wear OS OAuth 支持允许独立手表应用通过手机完成 OAuth 身份验证流程。独立应用使用请求和响应网址模型来验证用户的身份,并会收到用于访问相关服务的 OAuth 令牌。

注意:如果您的 Wear 2.0 应用有配套的手机应用,请为您的 Wear 应用和该手机应用使用相同的软件包名称。

前提条件

在开始之前,请先为您的后端服务器创建一个 OAuth 2.0 Web 应用客户端 ID。此客户端 ID 不同于您的应用的客户端 ID。您可以在 Google API 控制台中为您的服务器查找或创建一个客户端 ID。

流程

  1. 用户使用第三方应用执行一项需要授权的操作。
  2. 第三方应用使用 Wear Services API sendAuthorizationRequest() 向 Wear OS 配套应用发送请求,要求使用授权网址打开一个网页视图。
  3. 该网址对应的网站对用户进行授权(要求用户提供用户名和密码,或许还会执行双重身份验证等操作)。
  4. 授权成功或失败后,网站使用授权代码调用请求中指定的回调网址(指向应用的后端服务器)。
  5. 后端服务器使用授权代码向 OAuth 服务器换取访问权限和刷新令牌。
  6. 然后,后端服务器通过 Wear OS 配套应用将响应重定向到第三方手表应用。
  7. Wear OS 配套应用收到该重定向后,使用 Wearable Support API onAuthorizationResponse() 将来自服务器的整个响应发回到手表应用。
  8. 第三方应用解析来自身份验证网站的响应,并从响应中提取身份验证令牌。
  9. 第三方应用在其未来的请求中使用该身份验证令牌作为凭据。

要实现上述身份验证流程,您需要执行以下操作:

  1. 创建客户端 ID 和客户端密钥
  2. 执行身份验证请求
  3. 处理身份验证响应

创建客户端 ID 和客户端密钥

使用 OAuth 2.0 的 Wear 应用必须创建客户端 ID客户端密钥,以用于向 OAuth 提供程序证明应用的身份。您需要设置一个 API 控制台项目来获取这些凭据。

执行身份验证请求

要向 OAuth 提供程序发送身份验证请求,您需要先在 onCreate() 方法中创建一个用来发出 OAuth 2.0 请求的客户端对象。

注意:要确保您的应用在手表进入微光模式时不会关闭,请在应用的 OAuth Activity 中启用“始终开启”(可通过 setAmbientEnabled 实现)。要详细了解微光模式下的最佳做法,请参阅让您的应用始终保持可见页面。

Kotlin

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        oAuthClient = OAuthClient.create(this)
        …
    }
    

Java

    @Override
    public void onCreate(Bundle b) {
        super.onCreate(b);
        oAuthClient = OAuthClient.create(this);
        …
    }
    

接下来,构建一个网址,其中包含用于获取令牌的 OAuth 端点、您的服务器 OAuth 客户端 ID、重定向网址(指向您的后端服务器)以及响应类型。

所请求的网址与以下网址类似:

    https://accounts.google.com/o/oauth2/v2/auth?response_type=code
    &client_id="your_client_id_here";
    &scope=https://www.googleapis.com/auth/plus.login
    &redirect_uri=https://myserver.com
    

构建身份验证请求后,您可以使用 Wear Services API sendAuthorizationRequest() 向配套应用发送请求。

此请求会触发对配套应用的远程过程调用 (RPC),从而在用户手机上显示授权界面。OAuth 2.0 提供程序会验证用户身份,并请求用户同意您的应用访问所请求的范围。系统会使用您指定的重定向网址将响应发回到您的后端服务器。

处理身份验证响应

授权成功或失败后,OAuth 2.0 服务器会重定向到请求中指定的网址。如果用户批准了访问请求,响应中会包含授权代码。如果用户未批准请求,响应中会包含错误消息。

响应将以查询字符串的形式提供,如下所示:

    https://myserver.com/oauthtokens?code=xyz
    

后端服务器收到授权代码后,可以用该授权代码来换取访问令牌。然后,后端服务器会返回一个 HTTP 302 重定向到 Wear OS 手机应用,该应用已注册为可接收以下形式的网址:https://wear.googleapis.com/3p_auth/app.html?full_suffix_from_redirect=com.your.package.name?accessToken=abc&refreshToken=xyz
该手机应用会验证响应网址,并使用 onAuthorizationResponse API 将该响应传递给第三方手表应用。

注意:请确保应用软件包名称是重定向网址中的第 3 个路径组成部分。因此,redirect_uri 必须等于 https://wear.googleapis.com/3p_auth/<receiving app's packagename>。例如:https://wear.googleapis.com/3p_auth/com.package.name

手表上的第三方应用会从响应中提取身份验证令牌,并在未来的请求中使用该身份验证令牌作为凭据。

Kotlin

    oAuthClient.sendAuthorizationRequest(Uri.parse(requestUrl), MyOAuthCallback())
    

Java

    // The callback provided will be called when the OAuth request completes.
    oAuthClient.sendAuthorizationRequest(Uri.parse(requestUrl), new MyOAuthCallback());
    

Kotlin

    private class MyOAuthCallback : OAuthClient.Callback() {

        override fun onAuthorizationResponse(requestUrl: Uri, responseUrl: Uri) {
            Runnable {
                acquireToken()
                accessAPI()
            }.apply {
                ...
            }
        }
    }
    

Java

    private class MyOAuthCallback extends OAuthClient.Callback {
        @Override
        public void onAuthorizationResponse(Uri requestUrl, Uri responseUrl) {
            Runnable r =
                new Runnable() {
                    public void run() {
                        acquireToken();
                        accessAPI();
                    }
                };
        }
    }
    

要查看此流程的完整实现,请参阅示例

注意:在本示例中,由手表负责换取令牌。不过,最佳做法是将重定向网址设为您自己的服务器网址,在这种情况下,可由服务器执行用授权代码换取令牌的操作。

通过数据层传递令牌

这种方式仅适用于 Android 配对手表。手机上的配套应用可以通过 Wearable Data Layer 将身份验证数据安全地传输到 Wear 应用。可将凭据作为消息或数据项进行传输。

注意:我们建议您使用相同的软件包名称分发手机 APK 和手表 APK。这样,手机应用和 Wear 应用就可以通过 DataItem 层进行通信,并在后台执行从手机到手表的令牌传输操作,以提供身份验证。

流程

您可以按照自己的业务逻辑使用 Data Layer API 传递凭据。下图说明了通过 Wearable Data Layer 获取令牌的方法之一。

自定义代码身份验证

这种身份验证方法要求用户从外部来源(移动设备/平板电脑/PC)进行身份验证并获取一个短时效代码,然后他们需要在 Wear 设备上输入该代码来证明自己的身份,并用该代码换取身份验证令牌。采用这种方法时,您可以通过以下两种方式对使用您的 Wear 应用的用户进行身份验证:使用应用的登录模块,或手动将第三方身份验证提供程序的登录方法集成到应用的代码中。虽然这种身份验证方法需要手动操作和额外的工作来提高安全性,但如果您需要在您的独立 Wear 应用中更早地进行身份验证,不妨采用这种方法。

此设置的身份验证流程如下:

  1. 用户使用第三方应用执行一项需要授权的操作。
  2. 第三方 Wear 应用向用户呈现身份验证屏幕,并指示用户从指定网址输入代码。
  3. 用户切换到移动设备/平板电脑或 PC,启动浏览器,转到 Wear 应用上指定的网址,然后登录。
  4. 用户收到一个短时效代码,然后使用 Wear 设备自带键盘将其输入到 Wear 应用的身份验证屏幕中进行身份验证:

  5. 今后,您就可以使用输入的代码来证明这是正确的用户,并用它换取存储在 Wear 设备上的加密身份验证令牌,以便以后执行需要身份验证的调用。

另请参阅以下相关资源: