From e2b11b3b009c3613530ed05da14f126ef81dec9c Mon Sep 17 00:00:00 2001 From: wangyaqi Date: Mon, 18 Nov 2019 13:30:33 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=90=8C=E6=AD=A5=E7=94=9F=E7=89=A9?= =?UTF-8?q?=E8=AE=A4=E8=AF=81api?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/device/soter-authentication.js | 226 ++++++++++++++++++ src/platforms/app-plus/service/api/index.js | 4 +- 2 files changed, 228 insertions(+), 2 deletions(-) create mode 100644 src/platforms/app-plus/service/api/device/soter-authentication.js diff --git a/src/platforms/app-plus/service/api/device/soter-authentication.js b/src/platforms/app-plus/service/api/device/soter-authentication.js new file mode 100644 index 000000000..93afd401e --- /dev/null +++ b/src/platforms/app-plus/service/api/device/soter-authentication.js @@ -0,0 +1,226 @@ +import { + invoke, + requireNativePlugin +} from '../../bridge' + +function checkIsSupportFaceID () { + const platform = plus.os.name.toLowerCase() + if (platform !== 'ios') { + return false + } + const faceID = requireNativePlugin('faceID') + return !!(faceID && faceID.isSupport()) +} + +function checkIsSupportFingerPrint () { + return !!(plus.fingerprint && plus.fingerprint.isSupport()) +} + +export function checkIsSupportSoterAuthentication () { + let supportMode = [] + if (checkIsSupportFingerPrint()) { + supportMode.push('fingerPrint') + } + if (checkIsSupportFaceID()) { + supportMode.push('facial') + } + return { + supportMode, + errMsg: 'checkIsSupportSoterAuthentication:ok' + } +} + +export function checkIsSoterEnrolledInDevice ({ + checkAuthMode +} = {}) { + if (checkAuthMode === 'fingerPrint') { + if (checkIsSupportFingerPrint()) { + const isEnrolled = plus.fingerprint.isKeyguardSecure() && plus.fingerprint.isEnrolledFingerprints() + return { + isEnrolled, + errMsg: 'checkIsSoterEnrolledInDevice:ok' + } + } + return { + isEnrolled: false, + errMsg: 'checkIsSoterEnrolledInDevice:fail not support' + } + } else if (checkAuthMode === 'facial') { + if (checkIsSupportFaceID()) { + const faceID = requireNativePlugin('faceID') + const isEnrolled = faceID && faceID.isKeyguardSecure() && faceID.isEnrolledFaceID() + return { + isEnrolled, + errMsg: 'checkIsSoterEnrolledInDevice:ok' + } + } + return { + isEnrolled: false, + errMsg: 'checkIsSoterEnrolledInDevice:fail not support' + } + } + return { + isEnrolled: false, + errMsg: 'checkIsSoterEnrolledInDevice:fail not support' + } +} + +export function startSoterAuthentication ({ + requestAuthModes, + challenge = false, + authContent +} = {}, callbackId) { + /* + 以手机不支持facial未录入fingerPrint为例 + requestAuthModes:['facial','fingerPrint']时,微信小程序返回值里的authMode为"fingerPrint" + requestAuthModes:['fingerPrint','facial']时,微信小程序返回值里的authMode为"fingerPrint" + 即先过滤不支持的方式之后再判断是否录入 + 微信小程序errCode(从企业号开发者中心查到如下文档): + 0:识别成功 'startSoterAuthentication:ok' + 90001:本设备不支持SOTER 'startSoterAuthentication:fail not support soter' + 90002:用户未授权微信使用该生物认证接口 注:APP端暂不支持 + 90003:请求使用的生物认证方式不支持 'startSoterAuthentication:fail no corresponding mode' + 90004:未传入challenge或challenge长度过长(最长512字符)注:APP端暂不支持 + 90005:auth_content长度超过限制(最长42个字符)注:微信小程序auth_content指纹识别时无效果,faceID暂未测试 + 90007:内部错误 'startSoterAuthentication:fail auth key update error' + 90008:用户取消授权 'startSoterAuthentication:fail cancel' + 90009:识别失败 'startSoterAuthentication:fail' + 90010:重试次数过多被冻结 'startSoterAuthentication:fail authenticate freeze. please try again later' + 90011:用户未录入所选识别方式 'startSoterAuthentication:fail no fingerprint enrolled' + */ + const supportMode = checkIsSupportSoterAuthentication().supportMode + if (supportMode.length === 0) { + return { + authMode: supportMode[0] || 'fingerPrint', + errCode: 90001, + errMsg: 'startSoterAuthentication:fail' + } + } + let supportRequestAuthMode = [] + requestAuthModes.map((item, index) => { + if (supportMode.indexOf(item) > -1) { + supportRequestAuthMode.push(item) + } + }) + if (supportRequestAuthMode.length === 0) { + return { + authMode: supportRequestAuthMode[0] || 'fingerPrint', + errCode: 90003, + errMsg: 'startSoterAuthentication:fail no corresponding mode' + } + } + let enrolledRequestAuthMode = [] + supportRequestAuthMode.map((item, index) => { + const checked = checkIsSoterEnrolledInDevice({ + checkAuthMode: item + }).isEnrolled + if (checked) { + enrolledRequestAuthMode.push(item) + } + }) + if (enrolledRequestAuthMode.length === 0) { + return { + authMode: supportRequestAuthMode[0], + errCode: 90011, + errMsg: `startSoterAuthentication:fail no ${supportRequestAuthMode[0]} enrolled` + } + } + const realAuthMode = enrolledRequestAuthMode[0] + if (realAuthMode === 'fingerPrint') { + if (plus.os.name.toLowerCase() === 'android') { + plus.nativeUI.showWaiting(authContent || '指纹识别中...').onclose = function () { + plus.fingerprint.cancel() + } + } + plus.fingerprint.authenticate(() => { + plus.nativeUI.closeWaiting() + invoke(callbackId, { + authMode: realAuthMode, + errCode: 0, + errMsg: 'startSoterAuthentication:ok' + }) + }, (e) => { + switch (e.code) { + case e.AUTHENTICATE_MISMATCH: + // 微信小程序没有这个回调,如果要实现此处回调需要多次触发需要用事件publish实现 + // invoke(callbackId, { + // authMode: realAuthMode, + // errCode: 90009, + // errMsg: 'startSoterAuthentication:fail' + // }) + break + case e.AUTHENTICATE_OVERLIMIT: + // 微信小程序在第一次重试次数超限时安卓IOS返回不一致,安卓端会返回次数超过限制(errCode: 90010),IOS端会返回认证失败(errCode: 90009)。APP-IOS实际运行时不会次数超限,超过指定次数之后会弹出输入密码的界面 + plus.nativeUI.closeWaiting() + invoke(callbackId, { + authMode: realAuthMode, + errCode: 90010, + errMsg: 'startSoterAuthentication:fail authenticate freeze. please try again later' + }) + break + case e.CANCEL: + plus.nativeUI.closeWaiting() + invoke(callbackId, { + authMode: realAuthMode, + errCode: 90008, + errMsg: 'startSoterAuthentication:fail cancel' + }) + break + default: + plus.nativeUI.closeWaiting() + invoke(callbackId, { + authMode: realAuthMode, + errCode: 90007, + errMsg: 'startSoterAuthentication:fail' + }) + break + } + }, { + message: authContent + }) + } else if (realAuthMode === 'facial') { + const faceID = requireNativePlugin('faceID') + faceID.authenticate({ + message: authContent + }, (e) => { + if (e.type === 'success' && e.code === 0) { + invoke(callbackId, { + authMode: realAuthMode, + errCode: 0, + errMsg: 'startSoterAuthentication:ok' + }) + } else { + switch (e.code) { + case 4: + invoke(callbackId, { + authMode: realAuthMode, + errCode: 90009, + errMsg: 'startSoterAuthentication:fail' + }) + break + case 5: + invoke(callbackId, { + authMode: realAuthMode, + errCode: 90010, + errMsg: 'startSoterAuthentication:fail authenticate freeze. please try again later' + }) + break + case 6: + invoke(callbackId, { + authMode: realAuthMode, + errCode: 90008, + errMsg: 'startSoterAuthentication:fail cancel' + }) + break + default: + invoke(callbackId, { + authMode: realAuthMode, + errCode: 90007, + errMsg: 'startSoterAuthentication:fail' + }) + break + } + } + }) + } +} diff --git a/src/platforms/app-plus/service/api/index.js b/src/platforms/app-plus/service/api/index.js index b6c0a53a3..33e559329 100644 --- a/src/platforms/app-plus/service/api/index.js +++ b/src/platforms/app-plus/service/api/index.js @@ -1,4 +1,3 @@ -export * from './base/event-bus' export * from './context/audio' export * from './context/background-audio' @@ -12,6 +11,7 @@ export * from './device/get-network-type' export * from './device/ibeacon' export * from './device/make-phone-call' export * from './device/scan-code' +export * from './device/soter-authentication' export * from './device/system' export * from './device/vibrate' @@ -53,4 +53,4 @@ export { } from './ui/pull-down-refresh' -export * from './ui/tab-bar' +export * from './ui/tab-bar' -- GitLab