# 实名信息校验

为了更安全的网络访问，请务必使用TLS1.2协议及规定内的加密套件。若使用协议是TLS1.0、TLS1.1或规定外的加密套件，可能无法正常访问华为账号服务。

关于TLS1.2协议及规定内加密套件的信息，可以点击这里进行详细了解：TLS协议及加密套件。

该接口目前暂停开放。

#### 功能介绍

应用服务端向华为账号服务器调用该接口，用于校验用户提供的实名信息和华为账号实名信息是否一致。

#### 场景描述

应用已经通过授权码（Authorization Code）获取到Access Token，并且已申请账号开放信息对应权限后，将用户填写的实名信息与华为账号实名信息进行校验，并获取用户实名信息校验结果。

#### 使用约束

该接口目前暂停开放。

#### 接口原型

*   **承载协议：** HTTPS POST
    
*   **接口方向：** 开发者服务器->华为账号服务器
    
*   **接口URL：** 
    
*   **数据格式：**
    
    请求消息：Content-Type: application/x-www-form-urlencoded
    
    响应消息：Content-Type: application/json;charset=utf-8
    

#### 请求参数

#### Request Header

| 参数 | 是否必选 | 参数类型 | 描述 |
| --- | --- | --- | --- |
| Content-Type | 是 | String | 取值为：application/x-www-form-urlencoded。 说明： Request Body传参，请务必遵循此请求头格式，否则可能导致请求失败，具体传参方式可参考示例代码。 |

#### Request Body

| 参数 | 是否必选 | 参数类型 | 描述 |
| --- | --- | --- | --- |
| access_token | 是 | String | 通过获取用户级凭证获取的Access Token。 说明： 本场景下Access Token只能使用一次，再次使用会报“access forbidden”错误。 |
| sceneID | 是 | Integer | 调用场景 0：使用华为账号实名信息验证姓名、证件类型、证件号场景 1：使用华为账号实名信息验证姓名、证件类型、证件号、人脸场景 2：使用华为账号实名信息验证人脸场景 |
| idType | 是 | Integer | ID类型枚举对象 1：UserID类型 2：OpenID类型 3：UnionID类型 |
| idValue | 是 | String | ID实际值，值类型通过idType属性定义，如传用户的UnionID、OpenID值。 |
| ctfType | 否 | Integer | 证件类型 1：身份证（sceneID调用场景为0或1时需传） |
| realName | 否 | String | 待校验实名信息中的姓名，需使用SHA-512算法进行HASH后传入（sceneID调用场景为0或1时需传） |
| ctfCode | 否 | String | 待校验实名信息中的身份证号（若尾号为x，需统一转成大写X后校验），需使用SHA-512算法进行HASH后传入（sceneID调用场景为0或1时需传） |
| supportAlg | 是 | String | 指定返回的verifyToken的签名算法类型。 - RS256 - PS256 - ES256 |

#### 请求示例

请通过POST方式调用，示例如下：

```
POST /rest.php?nsp_svc=OpenRealName.User.verifyRealName HTTP/1.1
Host: openrealname.cloud.huawei.com
Content-Type: application/x-www-form-urlencoded

access_token=<access_token>&sceneID=1&ctfType=1&realName=<realName>&ctfCode=<ctfCode>&idType=2&idValue=<idValue>&supportAlg=RS256
```

#### 响应参数

#### Response Header

| 参数 | 是否必选 | 参数类型 | 描述 |
| --- | --- | --- | --- |
| Content-Type | 是 | String | 取值为：application/json;charset=utf-8。 |

#### Response Body

调用成功时，响应消息体返回如下：

| 参数 | 是否必选 | 参数类型 | 描述 |
| --- | --- | --- | --- |
| state | 是 | Integer | 实名状态 0：未认证 1：已认证 2： 认证中 |
| realNameLevel | 否 | Integer | 实名认证等级 0：未实名 10：未送权威渠道验证 20：已验证填写的姓名证件号实名 30：已验证证件照片实名 35：已验证过银行卡实名 40：已验证人脸实名 |
| verifyResult | 否 | Integer | 实名一致性校验结果 0：校验一致 1：姓名不匹配 2：姓名与证件号码不匹配 |
| verifyToken | 否 | String | 验证通过后返回的Token，JWT格式的数据 |

调用失败时，响应消息体返回如下：

| 参数 | 参数位置 | 参数类型 | 描述 |
| --- | --- | --- | --- |
| NSP_STATUS | header | String | 错误码，详见本章节错误码。 |
| error | body | String | 错误描述信息。 |

#### 响应示例

#### 请求成功时

```
HTTP/1.1 200 OK
Content-Type: application/json;charset=utf-8

{
    "state": 1,
    "verifyResult": 0,
    "realNameLevel": 20,
    "verifyToken": "eyJraWQ****Aad-dw"
}
```

#### 请求失败时

```
HTTP/1.1 200 OK
Content-Type: application/json;charset=utf-8
NSP_STATUS: 6

{
    "error": "session timeout"
}
```

#### 示例代码

Java示例代码如下，运行前需要进行示例代码环境配置（请将此示例代码与工具类CallUtils放于同一路径下，如不在同一路径，请手动添加import）

```
import com.alibaba.fastjson2.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.message.BasicNameValuePair;
import javax.xml.bind.annotation.adapters.HexBinaryAdapter;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

/**
 * 实名信息校验
 */
@Slf4j
public class VerifyRealNameDemo {

  public static void main(String[] args) throws IOException {
    // 实名信息校验的接口URL
    String url = "";
    // 替换为获取的Access Token
    String accessToken = "<Access Token>";
    // 替换为需要的调用场景
    Integer sceneID = 1;
    // 待校验姓名，当sceneID值为0或1时，该参数必传（此处无需进行SHA-512，后面调用逻辑中已具备SHA-512处理能力）
    String realName = "<realName>";
    // 替换为需要校验的实名信息中的身份证号，此处无需进行SHA-512，后面调用逻辑中已具备SHA-512处理能力
    String ctfCode = "<ctfCode>";
    // 证件类型，当sceneID值为0或1时，该参数必传，并且固定传1；否则传null
    Integer ctfType = 1;
    // 请替换为实际场景的idType(1：UserID类型 2：OpenID类型 3：UnionID类型)
    Integer idType = 2;
    // 请替换为实际场景的idValue(根据idType属性定义，传对应用户的身份标识，如UserID值、OpenID值、UnionID值)
    String idValue = "<idValue>";

    JSONObject result = verifyRealName(url, accessToken, sceneID, realName, ctfCode, ctfType, idType, idValue);

    // 解析获取state
    Integer state = result.getInteger("state");
    // 解析获取realNameLevel
    Integer realNameLevel = result.getInteger("realNameLevel");
    // 解析获取verifyResult
    Integer verifyResult = result.getInteger("verifyResult");
    // 解析获取verifyToken
    String verifyToken = result.getString("verifyToken");
  }

  /**
   * 调用华为账号服务，进行实名信息校验
   *
   * @param url 实名信息校验的接口URL
   * @param accessToken Access Token
   * @param sceneID 调用场景 0：使用华为账号实名信息验证姓名、证件类型、证件号场景 1：使用华为账号实名信息验证姓名、证件类型、证件号、人脸场景 2：使用华为账号实名信息验证人脸场景
   * @param realName 待校验姓名，当sceneID值为0或1时，该参数必传（此处无需进行SHA-512，后面调用逻辑中已具备SHA-512处理能力）；否则传null
   * @param ctfCode 待校验身份证号，当sceneID值为0或1时，该参数必传（此处无需进行SHA-512，后面调用逻辑中已具备SHA-512处理能力）；否则传null
   * @param ctfType 证件类型，当sceneID值为0或1时，该参数必传，并且固定传1；否则传null
   * @param idType ID类型枚举对象 1：UserID类型 2：OpenID类型 3：UnionID类型
   * @param idValue 根据idType参数值，传入对应用户的身份标识，如UserID值、UnionID值、OpenID值
   * @return JSONObject 服务响应数据
   * @throws IOException 调用异常
   */
  private static JSONObject verifyRealName (
          String url, String accessToken, Integer sceneID,
          String realName, String ctfCode, Integer ctfType,
          Integer idType, String idValue
  ) throws IOException {
    HttpPost httpPost = new HttpPost(url);
    List<NameValuePair> request = new ArrayList<>();
    request.add(new BasicNameValuePair("access_token", accessToken));
    request.add(new BasicNameValuePair("sceneID", String.valueOf(sceneID)));
    request.add(new BasicNameValuePair("realName", encryptBySHA512(realName)));
    request.add(new BasicNameValuePair("ctfCode", encryptBySHA512(ctfCode.toLowerCase(Locale.US))));
    if (ctfType != null) {
      request.add(new BasicNameValuePair("ctfType", String.valueOf(ctfType)));
    }
    request.add(new BasicNameValuePair("idType", String.valueOf(idType)));
    request.add(new BasicNameValuePair("idValue", idValue));
    // 请根据实际情况调整supportAlg的值
    request.add(new BasicNameValuePair("supportAlg", "PS256"));
    httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded");
    httpPost.setEntity(new UrlEncodedFormEntity(request));
    // 使用默认异常处理逻辑，自定义异常处理请使用api CallUtils#remoteCall(HttpUriRequest, BiFunction<CloseableHttpResponse,String,E>)
    return CallUtils.toJsonObject(CallUtils.remoteCall(httpPost));
  }

  private static String encryptBySHA512(String str) {
    try {
      MessageDigest md = MessageDigest.getInstance("SHA-512");
      return new HexBinaryAdapter().marshal(md.digest(str.getBytes(StandardCharsets.UTF_8)))
              .toLowerCase(Locale.US);
    } catch (NoSuchAlgorithmException e) {
      log.error("no such alg", e);
    }
    return null;
  }
}
```

#### 错误码

| HTTP响应码 | 描述 | 解决方法 |
| --- | --- | --- |
| 200 | 仅表示本次接口调用成功，实际业务处理结果需要通过Response Header中的NSP_STATUS进行判断。 | - |
| 400 | 参数错误。 | 请根据文档排查请求参数是否符合规范。 |
| 403 | 无权限访问。 | 通常是调用方网络安全策略阻止了访问，请检查网络环境配置。若仍无法解决，请通过在线提单提交问题。 |
| 404 | 找不到服务。 | 请检查请求URI是否正确。 |
| 405 | 不支持的http请求method。 | 请检查http请求method是否与接口说明一致。 |
| 500 | 服务内部错误。 | 请通过在线提单提交问题。 |
| 502 | 请求连接异常，常见于网络状况不稳定。 | 建议稍后重试，若仍无法解决，请通过在线提单提交问题。 |
| 503 | 系统流控。 | 触发系统流控，请稍后重试。 |
| 504 | 请求连接超时，常见于网络状况不稳定。 | 建议稍后重试，若仍无法解决，请通过在线提单提交问题。 |
| 590 | 服务内部错误。 | 请通过在线提单提交问题。 |

Response Header中的NSP\_STATUS字段，在处理成功时不会返回。

| NSP_STATUS | 描述 | 解决方法 |
| --- | --- | --- |
| 6 | 会话失效，session timeout。 可能原因: - access_token无效或已过期 - access_token格式不正确 | - access_token无效或已过期，请检查传参是否正确，如无问题请尝试重新获取。 - 未对access_token进行URLEncode处理，可参考示例代码组装参数。 |
| 105 | 请求url中nsp_svc参数错误。 | 请检查请求地址参数是否正确。 |
| 403 | 访问无权限。 | 请根据使用约束章节进行检查。 |
| 500 | 接口内部错误。 | 根据返回的错误描述进行处理，若仍无法解决，请通过在线提单提交问题。 |
| 503 | 接口流控。 | 业务调用频率过高，请稍后重试。 |
| 70001201 | 请求参数错误。 | 请根据错误描述信息确定错误参数并修正后重试。 |
| 70001401 | 服务内部错误。 | 请通过在线提单提交问题。 |
| 70009019 | 实名信息不存在 | 账号未实名，请先进行实名，或更换已实名账号，若仍无法解决，请通过在线提单提交问题。 |