专栏首页技术拓展与说明Tencent 人脸识别 Android V3 鉴权
原创

Tencent 人脸识别 Android V3 鉴权

Android 关于腾讯 人脸识别 V3 鉴权代码,供参考

注意:Android9.0 默认是禁止所有的http,且android4.0以后不能在主线程发起网络请求。

package com.example.iaiface;

import android.text.TextUtils;
import android.util.Log;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.TimeZone;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

/**
 * 人脸识别V3鉴权
 */
public class AuthFace {

    private static String SecretId  = "";
    private static String SecretKey = "";

    private static String Url       = "https://iai.tencentcloudapi.com";
    //规范请求串
    private static String  HTTPRequestMethod     = "POST";
    private static String  CanonicalURI          = "/";
    private static String  CanonicalQueryString  = "";
    private static String  CanonicalHeaders      = "content-type:application/json; charset=utf-8\nhost:iai.tencentcloudapi.com\n";
    private static String  SignedHeaders         = "content-type;host";//参与签名的头部信息

    //签名字符串
    private static String  Algorithm             = "TC3-HMAC-SHA256";
    private static String  Service               = "iai";
    private static String  Stop                  = "tc3_request";

    //版本
    public static String  Version               = "2018-03-01";

    /**
     * v3鉴权
     * @param action  人脸识别接口名 例如 DetectFace
     * @param paramJson json化的参数
     * @param version  版本号 2018-03-01
     * @return
     */
    public static String getAuthTC3(String action, String paramJson, String version){
        try{
            String hashedRequestPayload   =   HashEncryption(paramJson);
            Log.e("hashedRequestPayload", hashedRequestPayload);
            String CanonicalRequest =
                    HTTPRequestMethod + '\n' +
                            CanonicalURI + '\n' +
                            CanonicalQueryString + '\n' +
                            CanonicalHeaders + '\n' +
                            SignedHeaders + '\n' +
                            hashedRequestPayload;
            Log.e("CanonicalRequest", CanonicalRequest);
            //时间戳
            Date date = new Date();
            //微秒->秒
            String timestamp    =   String.valueOf(date.getTime() / 1000);

            //格林威治时间转化
            SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
            formatter.setTimeZone(TimeZone.getTimeZone("GMT+0"));
            String dateString = formatter.format(date.getTime());

            //签名字符串
            String credentialScope = dateString + "/" + Service + "/" + Stop;
            String hashedCanonicalRequest =   HashEncryption(CanonicalRequest);
            String stringToSign           =   Algorithm + "\n" +
                    timestamp + "\n" +
                    credentialScope + "\n" +
                    hashedCanonicalRequest;

            //计算签名
            byte[] secretDate             =   HashHmacSha256Encryption(("TC3" + SecretKey).getBytes("UTF-8"), dateString);
            byte[] secretService          =   HashHmacSha256Encryption(secretDate, Service);
            byte[] secretSigning          =   HashHmacSha256Encryption(secretService, Stop);

            //签名字符串
            byte[] signatureHmacSHA256    =   HashHmacSha256Encryption(secretSigning, stringToSign);
            //替换java DatatypeConverter.printHexBinary(d).toLowerCase()

            StringBuilder builder = new StringBuilder();
            for (byte b : signatureHmacSHA256) {
                String hex = Integer.toHexString(b & 0xFF);
                if (hex.length() == 1) {
                    hex = '0' + hex;
                }
                builder.append(hex);
            }
            String signature = builder.toString().toLowerCase();
            //组装签名字符串
            String authorization          =   Algorithm + ' ' +
                                            "Credential=" + SecretId + '/' + credentialScope + ", " +
                                            "SignedHeaders=" + SignedHeaders + ", " +
                                            "Signature=" + signature;

            //创建header 头部
            Map<String, String> headers = new HashMap<>();
            headers.put("Authorization", authorization);
            headers.put("Host", "iai.tencentcloudapi.com");
            headers.put("Content-Type", "application/json; charset=utf-8");
            headers.put("X-TC-Action", action);
            headers.put("X-TC-Version", version);
            headers.put("X-TC-Timestamp", timestamp);
            //headers.put("X-TC-Region", "ap-chengdu");

            //request 请求
            String response = submitPostData(Url, paramJson, headers);
            Log.e("response", response);
            return response;
        }catch(Exception e){
            return e.getMessage();
        }
    }


    /**
     *
     */
    private static String  HashEncryption(String s)  throws Exception {
        MessageDigest sha = MessageDigest.getInstance("SHA-256");
        sha.update(s.getBytes());
        //替换java DatatypeConverter.printHexBinary(d).toLowerCase()
        StringBuilder builder = new StringBuilder();
        for (byte b : sha.digest()) {
            String hex = Integer.toHexString(b & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            builder.append(hex);
        }
        return builder.toString().toLowerCase();
    }

    private static byte[] HashHmacSha256Encryption(byte[] key, String msg) throws Exception {
        Mac mac = Mac.getInstance("HmacSHA256");
        SecretKeySpec secretKeySpec = new SecretKeySpec(key, mac.getAlgorithm());
        mac.init(secretKeySpec);
        return mac.doFinal(msg.getBytes("UTF-8"));
    }


    /*
     * Function  :   发送Post请求到服务器
     * Param     :   params请求体内容,encode编码格式
     */
    public static String submitPostData(String strUrlPath, String data, Map<String, String> headers) {
        try {
            URL url = new URL(strUrlPath);
            HttpURLConnection httpURLConnection = (HttpURLConnection)url.openConnection();
            httpURLConnection.setConnectTimeout(3000);     //设置连接超时时间
            httpURLConnection.setDoInput(true);                  //打开输入流,以便从服务器获取数据
            httpURLConnection.setDoOutput(true);                 //打开输出流,以便向服务器提交数据
            httpURLConnection.setRequestMethod("POST");     //设置以Post方式提交数据
            httpURLConnection.setUseCaches(false);               //使用Post方式不能使用缓存

            //设置header
            if (headers.isEmpty()) {
                //设置请求体的类型是文本类型
                httpURLConnection.setRequestProperty("Content-Type", "application/json");
            } else {
                for (Map.Entry<String, String> entry : headers.entrySet()) {
                    String key = entry.getKey();
                    String value = entry.getValue();
                    httpURLConnection.setRequestProperty(key, value);
                }
            }
            //设置请求体的长度
            httpURLConnection.setRequestProperty("Content-Length", String.valueOf(data.length()));

            //获得输出流,向服务器写入数据
            if (data != null && !TextUtils.isEmpty(data)) {
                byte[] writebytes = data.getBytes();
                // 设置文件长度
                OutputStream outputStream = httpURLConnection.getOutputStream();
                outputStream.write(data.getBytes());
                outputStream.flush();
            }
            int response = httpURLConnection.getResponseCode();            //获得服务器的响应码
            if(response == HttpURLConnection.HTTP_OK) {
                InputStream inptStream = httpURLConnection.getInputStream();
                return dealResponseResult(inptStream);                     //处理服务器的响应结果
            }
        } catch (IOException e) {
            return "err: " + e.getMessage().toString();
        }
        return "-1";
    }

    /*
     * Function  :   封装请求体信息
     * Param     :   params请求体内容,encode编码格式
     */
    public static StringBuffer getRequestData(Map<String, String> params, String encode) {
        StringBuffer stringBuffer = new StringBuffer();        //存储封装好的请求体信息
        try {
            for(Map.Entry<String, String> entry : params.entrySet()) {
                stringBuffer.append(entry.getKey())
                        .append("=")
                        .append(URLEncoder.encode(entry.getValue(), encode))
                        .append("&");
            }
            stringBuffer.deleteCharAt(stringBuffer.length() - 1);    //删除最后的一个"&"
        } catch (Exception e) {
            e.printStackTrace();
        }
        return stringBuffer;
    }

    /*
     * Function  :   处理服务器的响应结果(将输入流转化成字符串)
     * Param     :   inputStream服务器的响应输入流
     */
    public static String dealResponseResult(InputStream inputStream) {
        String resultData = null;      //存储处理结果
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        byte[] data = new byte[1024];
        int len = 0;
        try {
            while((len = inputStream.read(data)) != -1) {
                byteArrayOutputStream.write(data, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        resultData = new String(byteArrayOutputStream.toByteArray());
        return resultData;
    }
}

调用示例:人脸检测与分析

        Map<String, Object> params = new HashMap<>();
        params.put("Url", "https://file.digitaling.com/eImg/uimages/20171009/1507508998226085.jpg");
        params.put("FaceModelVersion", "3.0");
        Gson gson = new Gson();
        String param = gson.toJson(params);
        String response = AuthFace.getAuthTC3("DetectFace", param, AuthFace.Version);

1. error: java.net.SocketException: socket failed: EPERM (Operation not permitted)

在常规调试Android HTTP请求或者其他功能(录音、拍照)等,需要在 AndroidManifest.xml 文件中开通权限,

权限集合参考:https://blog.csdn.net/snailbaby_soko/article/details/52954573

例如网络权限开通如下:

 <uses-permission android:name="android.permission.INTERNET" />

网络状态权限: (此权限不影响使用,可选择不添加)

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE">

重点:仍无法解决,则尝试卸载程序重新安装,导致这原因是:一开始网络请求时没有赋予网络权限,重新给程序赋予权限时没有卸载程序,只是重新编译,系统并没有获取到配置文件中的权限,因此需要卸载重新安装

2. error : No Network Security Config specified, using platform default

解决方案:

(1)res文件夹下新建xml目录,然后创建network_security_config.xml文件,内容如下

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="true"/>
</network-security-config>

(2)之后在application中添加配置如下,即可:

<application
       .....
        android:networkSecurityConfig="@xml/network_security_config"
        .......>

(3)需要在代码中设置如下代码才可以正常进行网络请求: android:usesCleartextTraffic="true" (本身是Android 6.0以下版本, 但实际也需要添加):指示应用程序是否打算使用明文网络流量

<application
       .....
        android:usesCleartextTraffic="true"
        .......>

整体示例:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.iaiface">

    <uses-permission android:name="android.permission.INTERNET" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:networkSecurityConfig="@xml/network_security_config"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"
        android:usesCleartextTraffic="true">
        <activity android:name=".activity.MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

3. JAVA 中 Hash 时 DatatypeConverter.printHexBinary 在Android 不可使用,替换方案

Java

public static String sha256Hex(String s) throws Exception {
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        byte[] d = md.digest(s.getBytes(UTF8));
        return DatatypeConverter.printHexBinary(d).toLowerCase();
}

Android

private static String  sha256Hex(String s)  throws Exception {
        MessageDigest sha = MessageDigest.getInstance("SHA-256");
        sha.update(s.getBytes());
        //替换java DatatypeConverter.printHexBinary(d).toLowerCase()
        StringBuilder builder = new StringBuilder();
        for (byte b : sha.digest()) {
            String hex = Integer.toHexString(b & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            builder.append(hex);
        }
        return builder.toString().toLowerCase();
}

觉得小编的文章对你有帮助,记得赞一个 ^v^

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • V3手动鉴权失败之PHP篇

    腾讯云 API 全新升级 3.0 ,该版本进行了性能优化且全地域部署、支持就近和按地域接入、访问时延下降显著,接口描述更加详细、错误码描述更加全面、SDK增加接...

    周朋伟
  • V3手动鉴权失败之Python篇

    腾讯云 API 全新升级 3.0 ,该版本进行了性能优化且全地域部署、支持就近和按地域接入、访问时延下降显著,接口描述更加详细、错误码描述更加全面、SDK增加接...

    周朋伟
  • V3手动鉴权失败之Go篇

    腾讯云 API 全新升级 3.0 ,该版本进行了性能优化且全地域部署、支持就近和按地域接入、访问时延下降显著,接口描述更加详细、错误码描述更加全面、SDK增加接...

    周朋伟
  • V3手动鉴权失败之C#篇

    腾讯云 API 全新升级 3.0 ,该版本进行了性能优化且全地域部署、支持就近和按地域接入、访问时延下降显著,接口描述更加详细、错误码描述更加全面、SDK增加接...

    周朋伟
  • V3手动鉴权失败之Java篇

    腾讯云 API 全新升级 3.0 ,该版本进行了性能优化且全地域部署、支持就近和按地域接入、访问时延下降显著,接口描述更加详细、错误码描述更加全面、SDK增加接...

    周朋伟
  • V3手动鉴权失败之Nodejs篇

    腾讯云 API 全新升级 3.0 ,该版本进行了性能优化且全地域部署、支持就近和按地域接入、访问时延下降显著,接口描述更加详细、错误码描述更加全面、SDK增加接...

    周朋伟
  • 腾讯SOTER 2.0开源带来三个特性升级

    ?      TENCENT SOTER生物认证标准目前已经在7.5亿部Android设备上得到支持,自2017年8月SOTER 1.0开源以来,有超过30个...

    腾讯开源
  • 增强版人脸核身产品上线,新增设备风险识别、智能分级认证能力,去了解 >>

    增强版人脸核身服务在基础版人脸核身的基础上,通过设备安全增强、活体安全增强、智能分级认证增强,全面升级核身安全能力,能够在刷脸核身的同时实时检测当前设备的风险,...

    TCS-F
  • Android人脸识别之识别人脸特征

    用户1269200
  • Android 人脸识别之人脸注册

    用户1269200
  • 腾讯云 实时语音识别介绍及其Android SDK Demo搭建

    实时语音识别API地址:https://cloud.tencent.com/document/product/1093/35799

    袁伦桥
  • 浅谈腾讯云·云开发与小程序·云开发的区别

    云开发(Tencent Cloud Base,TCB)是腾讯云为移动开发者提供的一站式后端云服务,它帮助开发者统一构建和管理资源,免去了移动应用开发过程中繁琐的...

    薛定喵君
  • 【玩转腾讯云】【腾讯云语音合成】智能语音交互之语音合成篇

    语音合成(Text To Speech,TTS)满足将文本转化成拟人化语音的需求,打通人机交互闭环。 提供多种音色选择,支持自定义音量、语速,让发音更自然、更专...

    ruskin
  • 人脸识别接入常见问题汇总

    https://cloud.tencent.com/act/event/iaidemo

    张世强
  • 腾讯数平精准推荐 | OCR技术之识别篇

    本文介绍了腾讯数平精准推荐团队的OCR识别算法,包括识别算法的演进之路以及4个代表性方法。

    腾讯大数据
  • 基于(PHP)人脸核身微信H5页面(普通模式)搭建

    (2)腾讯云控制台开通人脸核身权限 https://console.cloud.tencent.com/faceid/access

    袁伦桥
  • Android人脸识别,你也会做

    Android人脸识别APP事例,大家可以参考一下。注意这不是一下特别完整的项目,只有安卓端程序,缺少后台的程序。但大家也可以学习下吧。举一反三

    程序源代码
  • 百度:人脸登录集成

    为人脸登录提供人脸注册集合,基于人脸进行无动作活体检测、及后台在线活体检测算法,判断用户为真人,保障业务环节中的用户真实性判断。

    WindWant
  • 腾讯相册上了小程序·云开发,不仅不慌而且很爽

    小程序·云开发是基于腾讯云研发的全新 云开发 Tencent Cloud Base(简称 TCB) 服务,本文将阐述该解决方案如何帮助公司级业务腾讯相册加快迭代...

    李成熙heyli

扫码关注云+社区

领取腾讯云代金券