使用自定义按钮登录
=========

#### 场景介绍

应用应遵照[【华为账号登录】按钮](https://developer.huawei.com/consumer/cn/doc/design-guides/id-0000001880001344#section2624430102713)使用规则，在登录页面嵌入自定义华为账号登录按钮。当用户点击该按钮后，应用调用华为账号登录API获取Authorization Code，并通过服务端交互获取用户的UnionID、OpenID以完成登录。

#### 约束与限制

自定义按钮登录能力支持Phone、Tablet、PC/2in1设备。并且从5.1.0(18)版本开始，新增支持Wearable设备；从5.1.1(19)版本开始，新增支持TV设备；从26.0.0版本开始，新增支持Car设备。

#### 业务流程

![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/dc/v3/Pcz5PIzRSe-pWVNva8PwNQ/zh-cn_image_0000002625188413.png?HW-CC-KV=V1&HW-CC-Date=20260612T073547Z&HW-CC-Expire=86400&HW-CC-Sign=6638712646CC0C9EEED47B7FF74F6D6BB6E62E9D907F9C27FA274559881F7E70)

流程说明：

1.  展示自定义按钮调用登录API阶段（序号1-4）：
    
    1.  用户打开应用进行登录，点击自定义登录按钮，应用传forceLogin等参数后调用华为账号登录API，请求华为账号授权信息。
    2.  如华为账号未登录，将拉起华为账号登录页，用户登录后，将返回Authorization Code等数据给应用。
    3.  如华为账号已登录，将直接返回Authorization Code等数据给应用。
2.  用户关联应用账号阶段（序号5-16）：
    
    1.  应用服务端通过Authorization Code获取到Access Token，再使用Access Token调用[解析凭证接口](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/account-api-get-token-info#接口原型)获取用户相关信息。通过Authorization Code凭证获取用户信息可以有效避免黑客通过数据遍历、身份伪造、重放攻击等手段导致的安全风险。
    2.  应用服务端将业务登录凭证SessionId、UnionID/OpenID传给应用，应用获取到UnionID/OpenID可用于判断华为账号是否登录等功能。
    3.  应用对用户身份标识UnionID/OpenID、业务登录凭证SessionId信息进行认证后，通过UnionID/OpenID判断用户是否已关联应用系统数据库，如已关联，则完成用户登录；如未关联，则创建新用户，绑定UnionID/OpenID。

#### 接口说明

使用API获取UnionID登录关键接口如下表所示，具体API说明详见[API参考](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/account-api-authentication)。

| 接口名 | 描述 |
| :-- | :-- |
| [createLoginWithHuaweiIDRequest](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/account-api-authentication#createloginwithhuaweiidrequest)(): [LoginWithHuaweiIDRequest](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/account-api-authentication#loginwithhuaweiidrequest) | 创建账号登录请求。[LoginWithHuaweiIDRequest](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/account-api-authentication#loginwithhuaweiidrequest)中的forceLogin参数用来控制当用户未登录华为账号时，是否强制拉起华为账号登录界面。 |
| [constructor](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/account-api-authentication#constructor)(context?: [common.Context](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-app-ability-common#context)) | 创建登录请求Controller。 |
| [executeRequest](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/account-api-authentication#executerequest-1)(request: [AuthenticationRequest](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/account-api-authentication#authenticationrequest)): Promise<[AuthenticationResponse](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/account-api-authentication#authenticationresponse)\> | 通过Promise方式执行登录操作。 |

![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/2e/v3/zGoF6u-PSE6lBt3TcSlCkQ/caution_3.0-zh-cn.png?HW-CC-KV=V1&HW-CC-Date=20260612T073547Z&HW-CC-Expire=86400&HW-CC-Sign=CB2C9335866F9219DE49FFFB3E96F0362D7AA400F92CA7DC1823747C3EE37173)

上述接口需在页面或自定义组件生命周期内调用。

#### 开发前提

在进行代码开发前，请确保已按照“开发准备”章节中的指导完成[配置签名和指纹](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/account-sign-fingerprints)、[配置Client ID](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/account-client-id)。此场景无需申请账号权限。

#### 客户端开发

1.  根据[【华为账号登录】按钮](https://developer.huawei.com/consumer/cn/doc/design-guides/id-0000001880001344#section2624430102713)规范开发自定义登录图标按钮，参考如下步骤在点击事件中完成华为账号登录API调用。
    
2.  导入[authentication](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/account-api-authentication)模块及相关公共模块。
    
    import { authentication } from '@kit.AccountKit';
    import { hilog } from '@kit.PerformanceAnalysisKit';
    import { util } from '@kit.ArkTS';
    import { BusinessError } from '@kit.BasicServicesKit';
    
3.  创建登录请求并设置参数。
    
    // 创建登录请求，并设置参数
    const loginRequest = new authentication.HuaweiIDProvider().createLoginWithHuaweiIDRequest();
    // 用户是否需要登录授权，该值为true且用户未登录或未授权时，会拉起用户登录或授权页面
    loginRequest.forceLogin = true;
    // 建议使用generateRandomUUID生成state，可用于一致性比对，防止跨站攻击
    loginRequest.state = util.generateRandomUUID();
    
4.  调用[AuthenticationController](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/account-api-authentication#authenticationcontroller)对象的[executeRequest](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/account-api-authentication#executerequest-1)方法执行登录请求，并处理登录结果，获取到Authorization Code及ID Token。之后将Authorization Code传给应用服务端处理，可参考[客户端与服务端交互开发](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/account-phone-unionid-login#客户端与服务端交互开发)的开发步骤a和b。通过code凭证获取用户信息可以有效避免黑客通过数据遍历、身份伪造、重放攻击等手段导致的安全风险。应用可以通过公开的网址获取到华为账号服务器发布的公钥，对签名和ID Token中的必要信息进行验证，以证明其没有被篡改过。解析ID Token可参考[ID Token解析与验证](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/account-faq-12#解析与验证)。
    
    // 执行登录请求
    try {
      // 此示例为代码片段，实际需在自定义组件实例中使用，并传入有效的Context上下文对象
      const controller = new authentication.AuthenticationController(this.getUIContext().getHostContext());
      controller.executeRequest(loginRequest).then((response: authentication.LoginWithHuaweiIDResponse) => {
        const loginWithHuaweiIDResponse = response as authentication.LoginWithHuaweiIDResponse;
        const state = loginWithHuaweiIDResponse.state;
        if (state && loginRequest.state !== state) {
          hilog.error(0x0000, 'testTag', \`Failed to login. The state is different, response state: ${state}\`);
          return;
        }
        hilog.info(0x0000, 'testTag', 'Succeeded in logging in.');
        const loginWithHuaweiIDCredential = loginWithHuaweiIDResponse?.data;
        const authorizationCode = loginWithHuaweiIDCredential?.authorizationCode;
        // 开发者处理authorizationCode
      }).catch((error: BusinessError) => {
        dealAllError(error);
      });
    } catch (error) {
      dealAllError(error);
    }
    
    // 错误处理
    function dealAllError(error: BusinessError): void {
      hilog.error(0x0000, 'testTag', \`Failed to login. Code: ${error.code}, message: ${error.message}\`);
      // 在应用登录涉及UI交互场景下，建议按照如下错误码指导提示用户
      if (error.code === ErrorCode.ERROR\_CODE\_LOGIN\_OUT) {
        // 用户未登录华为账号，请登录华为账号并重试或者尝试使用其他方式登录
      } else if (error.code === ErrorCode.ERROR\_CODE\_NETWORK\_ERROR) {
        // 网络错误，请检查当前网络状态并重试
      } else if (error.code === ErrorCode.ERROR\_CODE\_INTERNAL\_ERROR) {
        // 登录失败，请尝试使用其他方式登录
      } else if (error.code === ErrorCode.ERROR\_CODE\_USER\_CANCEL) {
        // 用户取消授权
      } else if (error.code === ErrorCode.ERROR\_CODE\_SYSTEM\_SERVICE) {
        // 系统服务异常，请稍后重试或者尝试使用其他方式登录
      } else if (error.code === ErrorCode.ERROR\_CODE\_REQUEST\_REFUSE) {
        // 重复请求，应用无需处理
      } else {
        // 应用登录失败，请尝试使用其他方式登录
      }
    }
    
    export enum ErrorCode {
      // 账号未登录
      ERROR\_CODE\_LOGIN\_OUT = 1001502001,
      // 网络错误
      ERROR\_CODE\_NETWORK\_ERROR = 1001502005,
      // 内部错误
      ERROR\_CODE\_INTERNAL\_ERROR = 1001502009,
      // 用户取消授权
      ERROR\_CODE\_USER\_CANCEL = 1001502012,
      // 系统服务异常
      ERROR\_CODE\_SYSTEM\_SERVICE = 12300001,
      // 重复请求
      ERROR\_CODE\_REQUEST\_REFUSE = 1001500002
    }
    

#### 服务端开发

1.  应用服务端使用Client ID、Client Secret、Authorization Code调用[获取用户级凭证接口](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/account-api-obtain-user-token#接口原型)向华为账号服务器请求获取Access Token、Refresh Token。
    
2.  使用Access Token调用[解析凭证接口](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/account-api-get-token-info#接口原型)获取用户的UnionID。
    
    **Access Token过期处理**
    
    由于Access Token的有效期仅为60分钟，当Access Token失效或者即将失效时（可通过[REST API错误码](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/account-api-get-token-info#错误码)判断），可以使用Refresh Token（有效期180天）通过[刷新用户级凭证接口](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/account-api-obtain-refresh-token#接口原型)向华为账号服务器请求获取新的Access Token。
    
    ![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/3d/v3/vDzlspDUQq6CsCBz644yPg/note_3.0-zh-cn.png?HW-CC-KV=V1&HW-CC-Date=20260612T073547Z&HW-CC-Expire=86400&HW-CC-Sign=D48C7DF0268A42A42728F741338198717325BA5A599804E6CBD6C326E56CB216)
    
    1.  当Access Token失效时，若应用不使用Refresh Token向华为账号服务器请求获取新的Access Token，账号的授权信息将会失效，导致使用Access Token的功能都会失败。
        
    2.  当Access Token非正常失效（如修改密码、退出账号、删除设备）时，应用可重新登录授权获取Authorization Code，向华为账号服务器请求获取新的Access Token。
        
    
    **Refresh Token过期处理**
    
    由于Refresh Token的有效期为180天，当Refresh Token失效后（可通过[REST API错误码](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/account-api-obtain-refresh-token#错误码)判断），应用服务端需要通知客户端，重新调用授权接口，请求用户重新授权。
    
3.  应用在自己的用户体系通过查询获取的UnionID判断该用户是否已关联。如已关联，则完成用户登录；如未关联，则创建新用户，绑定UnionID，完成用户登录。