FIDO2提供基于WebAuthn标准的FIDO2 线上快速身份验证客户端实现,为应用及浏览器提供安卓Java API,支持使用USB、NFC、蓝牙漫游认证器,以及指纹和3D面容的平台认证器,进行安全认证。
在这个Codelab中,您将使用已经创建好的Demo Project实现对华为FIDO2客户端API调用,通过DemoProject你可以体验到:
集成HUAWEI HMS Core能力,需要完成以下准备工作
具体操作,请按照《HUAWEI HMS Core集成准备》中详细说明来完成。
点击"管理中心"->"应用市场"->"我的应用"->"应用名"->"开发"->"概览"->"API 管理",进入服务管理菜单。
打开"FIDO"服务开关。
将下载的"agconnect-services.json"文件移至Android Studio开发工程app的根目录下。
allprojects {
repositories {
google()
jcenter()
// Add the following line
maven { url 'http://developer.huawei.com/repo/' }
}
}
buildscript {
repositories {
google()
jcenter()
// Add the following line
maven { url 'http://developer.huawei.com/repo/' }
}
}
buildscript {
dependencies {
classpath 'com.android.tools.build:gradle:3.3.0'
// Add the following line
classpath 'com.huawei.agconnect:agcp:1.0.0.300'
}
}
dependencies {
implementation 'com.huawei.hms:fido-fido2:4.0.3.300'
}
Apply plugin: 'com.huawei.agconnect'
将从能力接入准备中获取的JKS文件(如FIDO BioAuthn Android Sample.jks)拷贝到工程的app目录下。同时在build.gradle文件中配置签名。
android {
signingConfigs {
config {
keyAlias 'FIDO BioAuthn Android Sample'
keyPassword '123456'
storeFile file('FIDO BioAuthn Android Sample.jks')
storePassword '123456'
}
}
buildTypes {
debug {
signingConfig signingConfigs.config
}
release {
signingConfig signingConfigs.config
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
package com.huawei.hms.kit.fidocp;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import com.huawei.hms.fidocp.R;
import com.huawei.hms.support.api.fido.fido2.Algorithm;
import com.huawei.hms.support.api.fido.fido2.AttestationConveyancePreference;
import com.huawei.hms.support.api.fido.fido2.AuthenticatorSelectionCriteria;
import com.huawei.hms.support.api.fido.fido2.Fido2;
import com.huawei.hms.support.api.fido.fido2.Fido2AuthenticationRequest;
import com.huawei.hms.support.api.fido.fido2.Fido2AuthenticationResponse;
import com.huawei.hms.support.api.fido.fido2.Fido2Client;
import com.huawei.hms.support.api.fido.fido2.Fido2Intent;
import com.huawei.hms.support.api.fido.fido2.Fido2IntentCallback;
import com.huawei.hms.support.api.fido.fido2.Fido2RegistrationRequest;
import com.huawei.hms.support.api.fido.fido2.Fido2RegistrationResponse;
import com.huawei.hms.support.api.fido.fido2.Fido2Response;
import com.huawei.hms.support.api.fido.fido2.NativeFido2AuthenticationOptions;
import com.huawei.hms.support.api.fido.fido2.NativeFido2RegistrationOptions;
import com.huawei.hms.support.api.fido.fido2.PublicKeyCredentialCreationOptions;
import com.huawei.hms.support.api.fido.fido2.PublicKeyCredentialDescriptor;
import com.huawei.hms.support.api.fido.fido2.PublicKeyCredentialParameters;
import com.huawei.hms.support.api.fido.fido2.PublicKeyCredentialRequestOptions;
import com.huawei.hms.support.api.fido.fido2.PublicKeyCredentialRpEntity;
import com.huawei.hms.support.api.fido.fido2.PublicKeyCredentialType;
import com.huawei.hms.support.api.fido.fido2.PublicKeyCredentialUserEntity;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
public class Fido2DemoActivity extends AppCompatActivity {
private TextView reusltView;
private Fido2Client fido2Client;
private byte[] regCredentialId = null;
private String rpId = "com.huawei.hms.fido2.test";
private String user = "fidoCp";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fido2_demo);
reusltView = findViewById(R.id.reusltView);
fido2Client = Fido2.getFido2Client(this);
}
// 从FIDO服务获取挑战值及相关策略,并组装Fido2RegistrationRequest请求消息。
private Fido2RegistrationRequest assembleFido2RegistrationRequest() {
// TODO 从FIDO服务获取挑战值及相关策略。
byte[] challengeBytes = getChallege();
// 组装Fido2RegistrationRequest请求消息。
PublicKeyCredentialCreationOptions.Builder builder = new PublicKeyCredentialCreationOptions.Builder();
builder.setRp(new PublicKeyCredentialRpEntity(rpId, rpId, null))
.setUser(new PublicKeyCredentialUserEntity(user, user.getBytes()))
.setChallenge(challengeBytes)
.setAttestation(AttestationConveyancePreference.DIRECT)
.setAuthenticatorSelection(new AuthenticatorSelectionCriteria(null, null, null))
.setPubKeyCredParams(new ArrayList<PublicKeyCredentialParameters>(
Arrays.asList(new PublicKeyCredentialParameters(PublicKeyCredentialType.PUBLIC_KEY, Algorithm.ES256),
new PublicKeyCredentialParameters(PublicKeyCredentialType.PUBLIC_KEY, Algorithm.RS256))))
.setTimeoutSeconds(60L);
if (regCredentialId != null) {
builder.setExcludeList(new ArrayList<PublicKeyCredentialDescriptor>(
Arrays.asList(new PublicKeyCredentialDescriptor(PublicKeyCredentialType.PUBLIC_KEY, regCredentialId))));
}
return new Fido2RegistrationRequest(builder.build(), null);
}
public void btnRegistrationClicked(View view) {
if (!fido2Client.isSupported()) {
showMsg("不支持FIDO2。");
return;
}
Fido2RegistrationRequest request = assembleFido2RegistrationRequest();
// 调用Fido2Client.getRegistrationIntent获取一个Fido2Intent实例,并启动FIDO客户端注册流程。
fido2Client.getRegistrationIntent(request, NativeFido2RegistrationOptions.DEFAULT_OPTIONS,
new Fido2IntentCallback() {
@Override
public void onSuccess(Fido2Intent fido2Intent) {
// 通过Fido2Client.REGISTRATION_REQUEST,启动FIDO客户端注册流程。
fido2Intent.launchFido2Activity(Fido2DemoActivity.this, Fido2Client.REGISTRATION_REQUEST);
}
@Override
public void onFailure(int errorCode, CharSequence errString) {
showError("注册失败。" + errorCode + "=" + errString);
}
});
}
// 从FIDO服务获取挑战值及相关策略,并组装Fido2AuthenticationRequest请求消息。
private Fido2AuthenticationRequest assembleFido2AuthenticationRequest() {
// TODO 从FIDO服务获取挑战值及相关策略。
byte[] challengeBytes = getChallege();
// 组装Fido2RegistrationRequest请求消息。
List<PublicKeyCredentialDescriptor> allowList = new ArrayList<>();
allowList.add(new PublicKeyCredentialDescriptor(PublicKeyCredentialType.PUBLIC_KEY, regCredentialId));
PublicKeyCredentialRequestOptions.Builder builder = new PublicKeyCredentialRequestOptions.Builder();
builder.setRpId(rpId).setChallenge(challengeBytes).setAllowList(allowList).setTimeoutSeconds(60L);
return new Fido2AuthenticationRequest(builder.build(), null);
}
public void btnAuthenticationClicked(View view) {
if (regCredentialId == null) {
showMsg("请先进行注册。");
return;
}
if (!fido2Client.isSupported()) {
showMsg("不支持FIDO2。");
return;
}
Fido2AuthenticationRequest request = assembleFido2AuthenticationRequest();
// 调用Fido2Client.getAuthenticationIntent获取一个Fido2Intent实例,并启动FIDO客户端认证流程。
fido2Client.getAuthenticationIntent(request, NativeFido2AuthenticationOptions.DEFAULT_OPTIONS,
new Fido2IntentCallback() {
@Override
public void onSuccess(Fido2Intent fido2Intent) {
// 通过Fido2Client.AUTHENTICATION_REQUEST,启动FIDO客户端注册流程。
fido2Intent.launchFido2Activity(Fido2DemoActivity.this, Fido2Client.AUTHENTICATION_REQUEST);
}
@Override
public void onFailure(int errorCode, CharSequence errString) {
showError("认证失败。" + errorCode + "=" + errString);
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode != Activity.RESULT_OK) {
showMsg("未知错误。");
return;
}
switch (requestCode) {
// Receive registration response
case Fido2Client.REGISTRATION_REQUEST:
Fido2RegistrationResponse fido2RegistrationResponse = fido2Client.getFido2RegistrationResponse(data);
if (fido2RegistrationResponse.isSuccess()) {
reusltView.append("注册\n");
reusltView.append(fido2RegistrationResponse.getAuthenticatorAttestationResponse().toJson());
reusltView.append("\n");
// save the credentialId
regCredentialId = fido2RegistrationResponse.getAuthenticatorAttestationResponse().getCredentialId();
showMsg("注册成功。");
} else {
showError("注册失败。", fido2RegistrationResponse);
}
break;
// Receive authentication response
case Fido2Client.AUTHENTICATION_REQUEST:
Fido2AuthenticationResponse fido2AuthenticationResponse =
fido2Client.getFido2AuthenticationResponse(data);
if (fido2AuthenticationResponse.isSuccess()) {
reusltView.append("认证\n");
reusltView.append(fido2AuthenticationResponse.getAuthenticatorAssertionResponse().toJson());
reusltView.append("\n");
showMsg("认证成功。");
} else {
showError("认证失败。", fido2AuthenticationResponse);
}
}
}
private void showError(String message) {
AlertDialog.Builder builder = new AlertDialog.Builder(Fido2DemoActivity.this);
builder.setTitle("错误");
builder.setMessage(message);
builder.setPositiveButton("确认", null);
builder.show();
}
private void showError(String message, Fido2Response fido2Response) {
StringBuilder errMsgBuilder = new StringBuilder();
errMsgBuilder.append(message)
.append(fido2Response.getFido2Status())
.append("=")
.append(fido2Response.getFido2StatusMessage())
.append(String.format(Locale.getDefault(), "(Ctap错误:0x%x=%s)", fido2Response.getCtapStatus(),
fido2Response.getCtapStatusMessage()));
showError(errMsgBuilder.toString());
}
public void showMsg(String message) {
AlertDialog.Builder builder = new AlertDialog.Builder(Fido2DemoActivity.this);
builder.setTitle("提示");
builder.setMessage(message);
builder.setPositiveButton("确认", null);
builder.show();
}
public void btnClearLogClicked(View view) {
reusltView.setText("");
regCredentialId = null;
}
private byte[] getChallege() {
return SecureRandom.getSeed(16);
}
}
安装测试apk,点击注册或认证按钮。
干得好,您已经成功完成了Codelab并学到了:
1894E85F57B06676DE6DF2353533C2B0D97FD742AC2FE403A5FC7BC.zip?needInitFileName=true)