.Net 腾讯云OCR对接

公司有自动识别身份证的需求,于是就采用了腾讯云的OCR自动识别功能,由于对接过程中踩坑较多,于是就将对接的过程及示例整理出来,方便有这方面需求的同志

腾讯云OCR识别官方文档:https://cloud.tencent.com/document/product/1007/35920

对接主要分为以下几个步骤

  1. 获取 Access Token 
  2. 获取 SIGN ticket 
  3. 生成签名
  4. OCR API 调用

一.获取 Access Token 

注意事项

  • 所有场景默认采用 UTF-8 编码。
  • Access Token 必须缓存在磁盘,并定时刷新,且不能并发刷新,建议每20分钟请求新的 Access Token,获取之后立即使用最新的 Access Token。旧的只有一分钟的并存期。
  • 如果未按照上述做定时刷新,可能导致鉴权不通过,影响人脸服务正常调用。
  • 每次用户登录时必须重新获取 NONCE ticket。
        private static string RedisAccessTokenKey { get; set; } = "TencentCloudAccessTokenKey-";
        private static string RedisSignTicket { get; set; } = "TencentCloudSignTicket-";
        private static string GetAccessToken()
        {
            string redisAccessKey = (RedisAccessTokenKey + Config.TencentCloudAppId);
            TencentCloudTokenInfoValidity validity = CacheManager.Instance.Get<TencentCloudTokenInfoValidity>(redisAccessKey);

            //如果为空保存更新
            if (validity == null || (DateTime.Now - validity.LastUpdateTime).TotalSeconds > (int.Parse(validity.TokenInfo.ExpireIn) - 60))
            {
                using (RedLockManager.GetTencentCloudAccessToken(Config.TencentCloudAppId))
                {
                    //拿到锁后,再次尝试
                    validity = CacheManager.Instance.Get<TencentCloudTokenInfoValidity>(redisAccessKey);
                    if (validity == null || (DateTime.Now - validity.LastUpdateTime).TotalSeconds > (int.Parse(validity.TokenInfo.ExpireIn) - 60))
                    {
                        string apiUrl = $"https://miniprogram-kyc.tencentcloudapi.com/api/oauth2/access_token?app_id={Config.TencentCloudAppId}&secret={Config.TencentCloudSecret}&grant_type=client_credential&version=1.0.0";
                        var tencentCloudApiResponse = TencentCloudApiRequestHelper.Get<GetTencentCloudTokenResponse>(apiUrl, new Operater { Name = "GetAccessToken" });
                        if (tencentCloudApiResponse == null)
                        {
                            throw new ArgumentNullException($"请求错误,url:{apiUrl},响应值为null");
                        }
                        validity = new TencentCloudTokenInfoValidity()
                        {
                            LastUpdateTime = DateTime.Now,
                            TokenInfo = new TencentCloudTokenData { AccessToken = tencentCloudApiResponse.AccessToken, ExpireIn = tencentCloudApiResponse.ExpireIn }
                        };
                        //提前三分钟过期
                        CacheManager.Instance.Set(redisAccessKey, validity, ((int.Parse(tencentCloudApiResponse.ExpireIn) / 60)) - 3);
                    }
                }
            }
            return validity.TokenInfo.AccessToken;
        }

二.获取 SIGN ticket 

注意事项

  • 前置条件:请合作方确保 Access Token 已经正常获取,获取方式请参见 获取 Access Token。
  • 用途:SIGN ticket 是合作方后台服务端业务请求生成签名鉴权参数之一,用于后台查询验证结果、调用其他业务服务等。
  • API ticket 的 SIGN 类型,必须缓存在磁盘,并定时刷新,刷新的机制如下:
    • 因为 API ticket 依赖于 Access Token 为了简单方便,建议将 API ticket 与 Access Token 绑定,每20分钟定时刷新,且不能并发刷新。
    • 获取新的之后请立即使用最新的,旧的有一分钟的并存期。
    • 如果未按照上述做定时刷新,可能导致鉴权不通过,影响人脸服务正常调用。
        public static string GetSignTicket()
        {
            string redisAccessKey = (RedisSignTicket + Config.TencentCloudAppId);
            TencentCloudTicketInfoValidity validity = CacheManager.Instance.Get<TencentCloudTicketInfoValidity>(redisAccessKey);

            //如果为空保存更新
            if (validity == null || (DateTime.Now - validity.LastUpdateTime).TotalSeconds > (int.Parse(validity.TicketInfo.ExpireIn) - 60))
            {
                using (RedLockManager.GetTencentCloudSignTicket(Config.TencentCloudAppId))
                {
                    //拿到锁后,再次尝试
                    validity = CacheManager.Instance.Get<TencentCloudTicketInfoValidity>(redisAccessKey);
                    if (validity == null || (DateTime.Now - validity.LastUpdateTime).TotalSeconds > (int.Parse(validity.TicketInfo.ExpireIn) - 60))
                    {
                        string AccessToken = GetAccessToken();
                        string apiUrl = $"https://miniprogram-kyc.tencentcloudapi.com/api/oauth2/api_ticket?app_id={Config.TencentCloudAppId}&access_token={AccessToken}&type=SIGN&version=1.0.0";
                        var tencentCloudApiResponse = TencentCloudApiRequestHelper.Get<GetTencentCloudTicketResponse>(apiUrl, new Operater { Name = "GetSignTicket" });
                        if (tencentCloudApiResponse == null || tencentCloudApiResponse.Code != "0" || !tencentCloudApiResponse.Tickets.Any())
                        {
                            throw new ArgumentNullException($"请求错误 url:{apiUrl}  ");
                        }
                        validity = new TencentCloudTicketInfoValidity()
                        {
                            LastUpdateTime = DateTime.Now,
                            TicketInfo = new TencentCloudTicketData { Value = tencentCloudApiResponse.Tickets.FirstOrDefault().Value, ExpireIn = tencentCloudApiResponse.Tickets.FirstOrDefault().ExpireIn }
                        };
                        //提前三分钟过期
                        CacheManager.Instance.Set(redisAccessKey, validity, ((int.Parse(tencentCloudApiResponse.Tickets.FirstOrDefault().ExpireIn) / 60) - 3));
                    }
                }
            }
            return validity.TicketInfo.Value;
        }

三.生成签名

基本步骤

  1. 生成一个32位的随机字符串(字母和数字) nonce(登录时也要用到),将 webankAppId、orderNo、version、连同 ticket、nonce 共5个参数的值进行字典序排序。
  2. 将排序后的所有参数字符串拼接成一个字符串进行 SHA1 编码。
  3. SHA1 编码后的40位字符串作为签名(sign)。
           List<string> signList = new List<string> { req.Version, req.WebankAppId, ticket, req.Nonce, req.OrderNo };
                signList.Sort(string.CompareOrdinal);                   //字典序排序
                string signStr = string.Join("", signList.ToArray());
                req.Sign = TencentCloudApiRequestHelper.SHA1(signStr);

四.OCR API 调用

 public static GetIDCardOCRResponse GetIDCardOCR(GetIDCardOCRRequest req)
        {
            try
            {
                string apiUrl = $"https://miniprogram-kyc.tencentcloudapi.com/api/paas/idcardocrapp?orderNo=" + req.OrderNo;
                var ticket = TencentCloudCommon.GetSignTicket();
                req.WebankAppId = Config.TencentCloudAppId;
                req.Version = "1.0.0";
                List<string> signList = new List<string> { req.Version, req.WebankAppId, ticket, req.Nonce, req.OrderNo };
                signList.Sort(string.CompareOrdinal);
                string signStr = string.Join("", signList.ToArray());
                req.Sign = TencentCloudApiRequestHelper.SHA1(signStr);
                var getIDCardOCRRes = TencentCloudApiRequestHelper.Post<GetIDCardOCRResponse>(apiUrl, req);
                return getIDCardOCRRes;
            }
            catch (Exception ex)
            {
                LoggerHelper.Logger.Error($"请求错误,GetIDCardOCR Exception:{ex}", ex);
                return null;
            }
        }

 

posted @ 2022-07-29 15:20  hello-*-world  阅读(275)  评论(0编辑  收藏  举报