员工身份(EIAM)
二次生物认证
# 文档说明
本文为您介绍Android客户端如何接入生物认证功能。生物认证即PC端登录时使用手机指纹/面容识别功能作为多因素认证。
用户在PC登录时选择“使用认证器作为二次认证”,此同时用户打开APP,确保登录状态和设备已绑定的情况下,App查询后台二次认证请求,如果有,APP会唤起手机生物识别确认是机主本人,同时APP会通知IDaaS服务端进行接下来的认证授权流程。
# 流程说明
绑定设备集成流程说明
- App客户端调用查询设备绑定状态方法,IDaaS SDK请求IDaaS服务端查询设备是否已绑定。
- 如果查询结果为没有绑定此设备,App客户端 调用绑定设备方法,IDaaS SDK 发起绑定流程,调起手机指纹识别/面容识别,确认是机主本人。IDaaS服务端记录本机为已绑定状态,并返回绑定成功/失败给App客户端。
二次认证流程说明
- 用户打开PC浏览器浏览器登录IDaaS系统,选择“使用认证器作为二次认证”,点击验证。App 客户端调用查询是否有二次认证方法,IDaaS服务端返回随机字串。
- App客户端拿到随机字串,用这个字串调用二次认证方法,IDaaS SDK拉起二次认证流程,调起手机指纹识别/面容识别,确认是机主本人,并发送二次认证请求到IDaaS服务端。服务端验证通过,PC网页端自动刷新状态。
解绑流程说明
- App客户端调用查询设备绑定状态方法,IDaaS SDK请求IDaaS服务端查询设备是否已绑定。
- 如果查询结果为已绑定此设备,App客户端调用解绑方法,IDaaS SDK发起解绑流程,调起手机指纹识别/面容识别,确认是机主本人,IDaaS服务端记录本机为未绑定状态,并返回解绑成功/失败给App客户端。
# 准备工作
# 获取clientID
登录IDaaS企业中心平台,点击 “资源-->应用” 选择跟自己相关的应用点击即可查看到。
# 开启二次认证
登录到IDaaS企业中心平台,点击 “认证—>认证策略”。
点击添加策略,此时会右边弹出一个策略框,输入描述,并且勾选“二次认证”和“竹云认证器(FaceID或指纹识别)”,点击确定。
如上步骤配置好后,会在登录用户中心页面,进行了一级登录后,需要二次认证的地方,会出现选项"通过竹云验证器进行验证"。
# 引入依赖包
AuthnCenter_Common-1.5.3.aar
AuthnCenter_MFA_BioVerify-1.5.3.aar
1
2
2
将IDaaS SDK拖入工程,并且引入方式如下:
# 配置 build.gradle
/*begin*/
/* rxjava2 + okhttp + retrofit2 */
api 'io.reactivex.rxjava2:rxjava:2.2.10'
api 'io.reactivex.rxjava2:rxandroid:2.1.1'
api 'com.squareup.retrofit2:retrofit:2.6.0'
api 'com.squareup.retrofit2:adapter-rxjava2:2.6.0'
api 'com.squareup.retrofit2:converter-gson:2.6.0'
api 'com.squareup.okhttp3:okhttp:4.3.1'
api 'com.squareup.okhttp3:logging-interceptor:3.6.0'
api 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0'
api 'com.trello.rxlifecycle2:rxlifecycle-components:2.1.0'
api 'com.alibaba:fastjson:1.2.61'
api 'org.greenrobot:greendao:3.3.0' // add library
implementation 'com.github.bumptech.glide:glide:4.14.2'
annotationProcessor 'com.github.bumptech.glide:compiler:4.14.2'
/*end */
api 'io.jsonwebtoken:jjwt-api:0.11.5'
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.5'
runtimeOnly('io.jsonwebtoken:jjwt-orgjson:0.11.5') {
exclude group: 'org.json', module: 'json' //provided by Android natively
}
implementation "androidx.biometric:biometric:1.1.0"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 开发集成
# SDK初始化
AuthnCenterSDK.Builder()
.init(this)
.setBaseUrl("https://xxx.xxx.com") //租户域名
.setClientId("xxxx") //租户后台应用client-id
.isCheckSSL(false) //是否检测SSL证书
.logEnable(false).build(); //是否打开http请求log 建议上线之后关闭
1
2
3
4
5
6
2
3
4
5
6
# 调用顺序说明
SDK 里面包含封装好的生物识别界面和单个业务接口,调用方可根据自己的实际业务需求进行灵活组合。
业务接口调用顺序说明。
查询绑定状态----> 查询是否有认证 ---->开启认证。
# 业务接口调用示例
查询设备绑定状态
AuthnCenterMFA.Builder().getStatus(this, accountInfo.getIdToken(), new MFAListener<Boolean>() {
@Override
public void success(Boolean data) {
}
@Override
public void error(String s, String s1) {
ToastUtils.ShowToast(InfoActivity.this, String.format("%s %s", s, s1));
}
});
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
绑定设备
try {
byte[] publicKey = keyStoreUtils.getPublicKey(accountInfo.getUserId()).getEncoded();
String pk = Base64.encodeToString(publicKey, Base64.DEFAULT).replaceAll("\n", "");
Map map = new HashMap();
map.put("publicKey", keyStoreUtils.PublicKeyToPem(pk));
AuthnCenterMFA.Builder().bind(this, accountInfo.getIdToken(), map, new MFAListener<Boolean>() {
@Override
public void success(Boolean o) {
ToastUtils.ShowToast(InfoActivity.this, o == true ? "绑定成功" : "绑定失败");
}
@Override
public void error(String s, String s1) {
ToastUtils.ShowToast(InfoActivity.this, String.format("%s %s", s, s1));
}
});
} catch (Exception e) {
ToastUtils.ShowToast(InfoActivity.this, String.format("%s", e.toString()));
e.printStackTrace();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
解绑设备
AuthnCenterMFA.Builder().unbind(this, accountInfo.getIdToken(), new MFAListener<Boolean>() {
@Override
public void success(Boolean data) {
tv_switch.setChecked(data == true ? false : true);
ToastUtils.ShowToast(InfoActivity.this, data == true ? "解绑成功" : "解绑失败");
}
@Override
public void error(String s, String s1) {
ToastUtils.ShowToast(InfoActivity.this, String.format("%s %s", s, s1));
}
});
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
查询是否有认证信息
AuthnCenterMFA.Builder().getAuthentication(this, accountInfo.getIdToken(), new MFAListener<AuthenticationInfo>() {
@Override
public void success(AuthenticationInfo data) {
if (data != null && !TextUtils.isEmpty(data.getRandom())) {
} else {
return;
}
}
@Override
public void error(String code, String msg) {
}
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
开启认证
try {
String singMsgTmp = String.format("%s", authenticationInfo.getRandom());
Signature signature = KeyStoreUtils.getInstance(getUserId(accountInfo.getIdToken())).initSignature();
signature.update(singMsgTmp.getBytes());
byte[] valueSign = signature.sign();
String sing = Base64.encodeToString(valueSign, Base64.DEFAULT).replaceAll("\n", "");
Map map = new HashMap();
map.put("signature", sing);
AuthnCenterMFA.Builder().startAuthentication(InfoActivity.this, accountInfo.getIdToken(), map, new MFAListener<Boolean>() {
@Override
public void success(Boolean data) {
if (data)
ToastUtils.ShowToast(mContext, "认证成功");
else
ToastUtils.ShowToast(mContext, "认证失败");
}
@Override
public void error(String code, String msg) {
ToastUtils.ShowToast(mContext, String.format("%s %s", code, msg));
}
});
} catch (Exception e) {
ToastUtils.ShowToast(mContext, String.format("%s", e.toString()));
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
包含生物识别界面绑定调用方式
AuthnCenterMFA.Builder().startBiometric(this, accountInfo.getIdToken(), BiometricType.BIND, new OnBiometricIdentifyCallback() {
@Override
public void onSucceeded() {
ToastUtils.ShowToast(InfoActivity.this, "绑定成功");
}
@Override
public void onFailed() {
}
@Override
public void onError(String s, String s1) {
ToastUtils.ShowToast(InfoActivity.this, "绑定失败" + s1);
}
@Override
public void onCancel() {
}
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
包含生物识别界面解绑调用方式
AuthnCenterMFA.Builder().startBiometric(this, accountInfo.getIdToken(), BiometricType.UNBIND, new OnBiometricIdentifyCallback() {
@Override
public void onSucceeded() {
ToastUtils.ShowToast(InfoActivity.this, "解绑成功");
}
@Override
public void onFailed() {
}
@Override
public void onError(String s, String s1) {
ToastUtils.ShowToast(InfoActivity.this, "解绑失败" + s1);
}
@Override
public void onCancel() {
}
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 返回码
状态码 | 错误码 (error_code) | 错误说明 (error_msg) | 处理措施 |
---|---|---|---|
400 | IDAAS.SDK.COMMON.1001 | Parameter {0} cannot be left blank | |
参数 {0} 不能为空 | |||
400 | IDAAS.SDK.COMMON.1002 | The {0} parameter format is incorrect | |
参数 {0} 格式错误 | |||
400 | IDAAS.SDK.COMMON.1003 | Device information is incomplete | |
设备信息不完整 | |||
400 | IDAAS.SDK.COMMON.1004 | Signature decryption error | |
签名解密错误 | |||
400 | IDAAS.SDK.COMMON.1005 | The {0} has failed | |
{0} 已失效 | |||
400 | IDAAS.SDK.COMMON.1006 | The {0} parameter error | |
{0} 参数错误 | |||
400 | IDAAS.SDK.COMMON.1007 | The {0} parameter type error | |
{0}参数类型错误 | |||
500 | IDAAS.SDK.COMMON.1008 | The system is busy. Try again later | |
系统繁忙。稍后再试 | |||
400 | IDAAS.SDK.COMMON.1009 | Unknown authentication configuration | |
未知的认证配置 | |||
400 | IDAAS.SDK.COMMON.1010 | Failed to obtain the enterprise center global configuration | |
获取企业中心全局配置失败 | |||
400 | IDAAS.SDK.COMMON.1011 | Failed to obtain the international area code configuration | |
获取国际区号配置失败 | |||
400 | IDAAS.SDK.COMMON.1012 | The x-client-ID is incorrect and the corresponding application cannot be found | |
X-client-id错误,找不到对应的应用 | |||
400 | IDAAS.SDK.COMMON.1013 | The corresponding user is not found | |
未找到对应的用户 | |||
400 | IDAAS.SDK.COMMON.1014 | Application private key not found | |
未找到应用私钥 | |||
400 | IDAAS.SDK.LOGIN.1001 | Error calling interface {0} | |
调用 {0} 接口出错 | |||
400 | IDAAS.SDK.LOGIN.1002 | User not bound | |
用户未绑定 | |||
400 | IDAAS.SDK.LOGIN.1003 | The user has been locked due to too many unsuccessful login attempts. It will be unlocked in {0} minutes and {1} seconds | |
由于多次登录失败,用户已被锁定。 它将在 {0} 分钟和 {1} 秒内解锁 | |||
400 | IDAAS.SDK.LOGIN.1004 | Failed to obtain the password policy | |
获取密码策略错误 | |||
400 | IDAAS.SDK.LOGIN.1005 | Invalid username or password. Remaining login attempts: {0} | |
无效的用户名或密码。 其余登录尝试次数:{0} | |||
400 | IDAAS.SDK.LOGIN.1006 | Configuration error, unable to find wechat authentication source | |
配置错误,找不到微信认证源 | |||
400 | IDAAS.SDK.LOGIN.1007 | Configuration error, unable to find alipay authentication source | |
配置错误,找不到支付宝认证源 | |||
400 | IDAAS.SDK.LOGIN.1008 | The configuration is incorrect. The one-click login authentication source cannot be found | |
配置错误,无法找到一键登录认证源 | |||
400 | IDAAS.SDK.SMS.1001 | {0} slide base map is not initialized successfully, please check the path | |
{0} 滑动底图未初始化成功,请检查路径 | |||
400 | IDAAS.SDK.SMS.1002 | {0} verification code coordinate resolution failed | |
{0} 验证码坐标解析失败 | |||
400 | IDAAS.SDK.SMS.1003 | {0} verification code coordinate verification fails | |
{0} 验证码坐标校验失败 | |||
400 | IDAAS.SDK.SMS.1004 | The graphic verification code is incorrect | |
图形验证码校验错误 | |||
400 | IDAAS.SDK.SMS.1005 | SMS verification code verification is incorrect | |
短信验证码验证错误 | |||
400 | IDAAS.SDK.SMS.1006 | The email verification code is incorrect | |
邮件验证码验证错误 | |||
400 | IDAAS.SDK.SMS.1007 | Sending scenario does not exist | |
发送场景不存在 | |||
400 | IDAAS.SDK.SMS.1008 | Failed to send the verification code | |
发送验证码失败 | |||
400 | IDAAS.SDK.SOCIAL.1001 | The social account is unbound incorrectly | |
社交账号解绑错误 | |||
400 | IDAAS.SDK.SOCIAL.1002 | The social account has been bound, please unbind it first | |
社交账号已绑定,请先解绑 | |||
400 | IDAAS.SDK.PWD.1001 | The password length is incorrect | |
密码长度错误 | |||
400 | IDAAS.SDK.PWD.1002 | The password cannot be the username | |
密码不能为用户名 | |||
400 | IDAAS.SDK.PWD.1003 | Your password complexity is low | |
你的密码复杂度过低 | |||
400 | IDAAS.SDK.PWD.1004 | The password is weak | |
密码很弱 | |||
400 | IDAAS.SDK.PWD.1005 | The password is used before, cannot be used again | |
该密码已被使用过,不能再次使用 | |||
400 | IDAAS.SDK.PWD.1006 | Password cannot username in reverse order | |
密码不能是用户名的倒序 | |||
400 | IDAAS.SDK.PWD.1007 | The number of repeated password characters exceeded the upper limit | |
密码重复字符数超过限制 | |||
400 | IDAAS.SDK.PWD.1008 | Password cannot contain :username, phone number, email prefix, name in PinYing | |
密码不能包含:用户名、电话号码、邮件前缀、拼音名 | |||
400 | IDAAS.SDK.MFA.1001 | The mobile doesn't match the user | |
手机号和用户不匹配 | |||
400 | IDAAS.SDK.MFA.1002 | The access control policy is incorrect | |
访问控制策略配置错误 | |||
400 | IDAAS.SDK.MFA.1003 | Access control authentication source type conversion error | |
访问控制身份验证源类型转换错误 |