资讯动态

身份证 OCR 实名认证:拍照上传、结果回填、18位/15位校验,一步到位

发布时间:2026/10/8 21:49:31 来源:尧图企业网站定制
身份证 OCR 实名认证拍照上传、结果回填、18位/15位校验一步到位导读招聘平台要做实名认证用户手动填身份证号码十个人有三个填错——少一位、多一位、X 写成 x。后来做成拍照识别自动回填识别完还要本地再校验一遍身份证格式。这篇把 uni-app 端的实现拆开讲含一个必踩的坑。做求职平台实名认证是硬需求工人要实名才能接单企业要实名才能发岗。第一版是让用户手动填姓名、身份证号、性别、出生日期上线一周客服就被身份证填错改不了的工单淹没了。后来改成拍照 OCR用户传身份证照片 → 后端调 OCR 识别 → 结果回填表单 → 前端再校验格式。整个流程里最坑的不是 OCR 识别率而是文件上传和身份证校验的细节。坑在前头uni.uploadFile 不走拦截器项目里 HTTP 请求都封装了拦截器自动带 token但uni.uploadFile是不走拦截器的token 必须自己手动塞进 header。第一次没注意上传接口一直报未登录importbasefrom/config/baseUrl;importstorefrom/store;functiongetAccessToken(){constcachedUseruni.getStorageSync(userInfo)||{};returnstore.state.userInfo?.token||cachedUser.token||;}exportfunctionuploadApiFile(filePath,biz){returnnewPromise((resolve,reject){consttokengetAccessToken();if(!token){reject(newError(请先登录));return;}uni.uploadFile({url:base.baseUrl/api/file/upload,filePath,name:file,header:{X-Access-Token:token},// 手动带不走拦截器formData:biz?{biz}:{},success:(res){try{constdataJSON.parse(res.data||{});constokdata.successtrue||data.code200||data.code0;consturldata.message||data.result;if(okurl){resolve(url);return;}reject(newError(data.message||上传失败));}catch(e){reject(e);}},fail:(err)reject(err),});});}上传成功后拿到文件 URL带着 URL 调后端 OCR 接口识别结果返回来回填表单。身份证校验18 位和 15 位都要处理OCR 识别回来的号码不能直接信必须本地再校验一遍。身份证有 18 位和 15 位两种格式18 位带校验位最后一位可能是 X15 位是老证没有校验位exportfunctionparseIdCard(idCard){constnormalizedString(idCard||).trim().toUpperCase();constreg18/^[1-9]\d{5}(19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9X]$/;constreg15/^[1-9]\d{5}\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}$/;letbirthday;letgender;if(reg18.test(normalized)){constbirthStrnormalized.substring(6,14);birthday${birthStr.substring(0,4)}-${birthStr.substring(4,6)}-${birthStr.substring(6,8)};constgenderCodeparseInt(normalized.substring(16,17),10);gendergenderCode%21?男:女;}elseif(reg15.test(normalized)){constbirthStr19${normalized.substring(6,12)};birthday${birthStr.substring(0,4)}-${birthStr.substring(4,6)}-${birthStr.substring(6,8)};constgenderCodeparseInt(normalized.substring(14,15),10);gendergenderCode%21?男:女;}else{returnnull;}return{birthday,gender};}两个细节一是先 toUpperCase把用户手输的小写 x 转大写再比对二是 15 位老证的出生年份要补19前缀性别位在第 15 位而不是第 17 位。识别结果回填容错优先OCR 结果字段和表单字段不一定同名写了个映射函数统一回填字段缺失就跳过不覆盖用户已有的输入exportfunctionapplyIdCardOcrToForm(form,res){if(!form||!res)returnfalse;if(res.name)form.realnameres.name;if(res.sex)form.sexres.sex;if(res.birth)form.birthres.birth;if(res.address)form.addressres.address;if(res.num){form.idNores.num;constparsedparseIdCard(form.idNo);if(parsed){form.birthparsed.birthday;form.sexparsed.gender;}}returntrue;}企业认证那边同理营业执照 OCR 识别法人、统一社会信用代码、注册地址回填还额外校验了统一社会信用代码格式18 位第二位到第六位有字母规则exportfunctionisValidUscc(code){constvalueString(code||).trim().toUpperCase();return/^[0-9A-HJ-NPQRTUWXY]{2}\d{6}[0-9A-HJ-NPQRTUWXY]{10}$/.test(value);}踩坑记录识别成功但表单校验死活过不去问题现象联调时发现OCR 识别返回的身份证号明明是对的但parseIdCard一直返回 null实名认证提交被前端拦下。排查过程打印识别结果发现 OCR 返回的号码里混了一个全角数字正则里只匹配半角[0-9]全角直接不通过。再看有些 OCR 结果还带空格和换行。定位思路OCR 引擎返回的字符串不能假设是干净数据全角/半角、空格、换行、大小写都是要处理的面。最终解决解析前统一做归一化——trim()去空白、全角数字转半角、字母 toUpperCase再进正则。归一化函数加上后识别结果的通过率从 60% 提到 99%。可直接复用的清单uni.uploadFile不走拦截器token 必须手动塞 header身份证解析前先trim 全角转半角 toUpperCase18 位校验位可能是 X先转大写再比对15 位老证年份补19性别位在第 15 位OCR 回填字段缺失就跳过不覆盖用户已填内容企业认证额外校验统一社会信用代码格式。这套实名认证流程在小蓝直聘移动端里。项目源码https://gitee.com/gzqkl/job-uniapp

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑