# 解绑账号

#### 功能介绍

调用此接口可以解绑游戏官方账号与华为teamPlayerId的绑定关系。

#### 场景描述

玩家选择华为账号登录游戏后，游戏会绑定游戏官方账号与华为teamPlayerId。

若需要解绑游戏官方账号与华为teamPlayerId的绑定关系，客户端侧可以调用unbindPlayer接口实现，服务端可以调用本接口实现。

#### 接口原型

*   **承载协议**：HTTPS POST
    
*   **接口方向**：开发者服务器->华为游戏服务器
    
*   **接口URL**：
    
*   **数据格式**：
    
    *   请求：Content-Type: application/x-www-form-urlencoded（表单方式）
    *   响应：Content-Type: application/json

#### 请求参数

**body参数**

| 参数 | 是否必选 | 类型 | 描述 |
| --- | --- | --- | --- |
| method | 是 | String | 固定传入“external.hms.gs.player.unbindPlayer”。 最大长度64个字符。 |
| appId | 否 | String | 游戏在AppGallery Connect中的APP ID，获取方法请参见查看应用信息。若解绑“游戏级别”类型，该参数必填。 最大长度32个字符。 |
| cpId | 是 | String | 游戏开发者在AppGallery Connect中的Developer ID，获取方法请参见查看应用信息。 最大长度32个字符。 |
| teamPlayerId | 是 | String | HarmonyOS 5.0及以上游戏的玩家标识，通过调用unionLogin接口返回， 最大长度256个字符。 |
| ts | 是 | Long | 当前时间的时间戳，即当前时间距离GMT时间1970年1月1号0时0分0秒所差的毫秒数。 |
| sign | 是 | String | 用于华为游戏服务器对请求参数验签的签名字符串。 为防止请求被篡改，游戏需要根据签名机制中的方法生成签名字符串，华为服务器在收到请求后会对签名字符串进行验签，验签成功后才会进行后续处理，否则将返回失败错误码。请求中除sign和method以外的所有Body参数均参与签名。 最大长度1024个字符。 |

#### 请求示例

```
POST /gameservice/api/gbClientApi HTTP/1.1
Host: jos-open-api.cloud.huawei.com
Content-Type: application/x-www-form-urlencoded
// 所有请求参数值均需要urlencode编码后再进行拼接
method=external.hms.gs.player.unbindPlayer&appId=135***568&cpId=123***21f&teamPlayerId=******&ts=1670841860308&sign=**************
```

#### 响应参数

| 参数 | 是否必选 | 类型 | 描述 |
| --- | --- | --- | --- |
| rtnCode | 是 | int | 服务端返回码。 -1：响应失败。由未知异常导致。 0：解绑成功。 1：验签失败。通常由于签名不一致导致。 3001：参数错误。表示缺失请求参数或格式错误。 2031002：玩家账号信息错误。 2031006：游戏信息错误。表示未查询到游戏信息。 2031007：华为玩家账号已绑定其他游戏玩家账号。 |
| errMsg | 否 | String | 异常场景下返回错误码的描述。 |

#### 响应示例

```
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
{
    "rtnCode":0
}
```

#### 签名机制

为了确保HTTPS传输的安全性，防止请求参数被篡改，应用需要在调用接口时携带请求参数的签名字符串，用于华为服务器对请求参数进行校验。签名字符串的生成规则如下所示：

1.  将请求参数Body中除**sign**和**method**以外的参数，按参数名首字母的ASCII码将参数升序排序。若遇到相同首字母，则比较第二个字母，以此类推。
    
    **sign**和**method**参数不参与签名。
    
2.  添加依赖项。
    
    ```
    <dependencies>
           <dependency>
                <groupId>commons-codec</groupId>
                <artifactId>commons-codec</artifactId>
                <version>1.15</version> <!-- 请使用最新的稳定版本 -->
            </dependency>
            <dependency>
                <groupId>org.bouncycastle</groupId>
                <artifactId>bcprov-jdk18on</artifactId>
                <version>1.74</version> <!-- 请使用最新的稳定版本 -->
            </dependency>
    </dependencies>
    ```
    
3.  将所有参与签名的参数名和参数值的键值对以“&”字符连接成待签名字符串，例如“a=xxxxxx&b=xxxxxxx&c=xxxxxxxxxxx...”。其中，参数值需要进行urlencode。
    
    Java示例代码如下：
    
    ```
    // 组装body内除sign和method以外的参数，此处参数值仅为示例
    Map<String, String> paramsMap = new HashMap<>();
    paramsMap.put("appId", "135***568");
    paramsMap.put("cpId", "123***21f");
    paramsMap.put("teamPlayerId", "E5B***E9B");
    paramsMap.put("ts", 123456L);
    
    // 对参数进行字典序排序
    Map<String, String> tempMap = new TreeMap<>(paramsMap);
    StringBuffer base = new StringBuffer();
    
    // 拼接参数
    for (Map.Entry<String, String> entry : tempMap.entrySet()) {
        String key = entry.getKey();
        String value = entry.getValue();
        base.append(key).append('=').append(null == value ? '' : URLEncoder.encode(value, "UTF-8")).append('&');
    }
    
    if (base.length() > 0) {
        base.deleteCharAt(base.length() - 1);
    }
    ```
    
4.  将待签名字符串使用游戏私钥按照RSA算法（SHA256WithRSA/PSS）进行签名，将签名后的字符串经过Base64编码，得到的字符串即为签名字符串。
    
    *   游戏私钥获取请参见获取游戏密钥。
        
    *   签名字符串需要进行urlencode后再拼接到请求中。
        
    
    Java示例代码如下：
    
    ```
    // 获取签名私钥，具体实现方法由开发者自行决定，此处仅为接口示例
    String privateKey = "xxxxxx";
    
    // 加签
    byte[] keyBytes = Base64.decodeBase64(privateKey);
    PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    PrivateKey privateK =  keyFactory.generatePrivate(pkcs8KeySpec);
    Signature signature = Signature.getInstance("SHA256withRSA/PSS", new BouncyCastleProvider());
    signature.initSign(privateK);
    signature.update(base.getBytes(StandardCharsets.UTF_8));
    String sign =  Base64.encodeBase64String(signature.sign());
    ```