The Android Developer Challenge is back! Submit your idea before December 2.

Wear 中的身份验证

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

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

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

Google 登录

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

Google 登录是最受青睐的解决方案,因为它在 iOS 上同样表现出色。下一部分介绍了如何完成基本的 Google 登录集成。

前提条件

您必须先配置一个 Google API 控制台项目并设置您的 Android Studio 项目,然后才能开始将 Google 登录集成到您的 Wear 应用中。如需了解详情,请参阅 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 设备上存储并加密的身份验证令牌,以便后续进行经过身份验证的调用。

另请参阅以下相关资源: