GitHub_Trending/co/conference-app-2024中的生物识别:指纹与面容识别
你还在为会议应用的密码管理烦恼吗?频繁输入复杂密码降低体验,简单密码又存在安全隐患。本文将详解DroidKaigi 2024官方应用如何集成生物识别技术,实现一键安全登录。读完你将了解:Android指纹识别实现流程、iOS面容识别核心代码、跨平台认证架构设计及安全最佳实践。
项目生物识别应用场景
DroidKaigi 2024作为Android开发者会议官方应用,需保护用户日程数据、个人资料等敏感信息。生物识别技术被用于:
- 应用启动身份验证
- 个人日程导出授权
- 会议资料加密访问
Android指纹识别实现
核心认证流程
关键实现代码
项目中Android生物识别核心逻辑位于core/data/src/androidMain/kotlin/io/droidkaigi/core/data/auth/BiometricAuthManager.kt:
class BiometricAuthManager(
private val context: Context,
private val keyManager: SecureKeyManager
) {
private val executor = ContextCompat.getMainExecutor(context)
private val biometricPrompt = BiometricPrompt(
context as FragmentActivity,
executor,
object : BiometricPrompt.AuthenticationCallback() {
override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
super.onAuthenticationSucceeded(result)
val cryptoObject = result.cryptoObject ?: return
authCallback?.onSuccess(cryptoObject)
}
override fun onAuthenticationFailed() {
super.onAuthenticationFailed()
authCallback?.onFailure(BiometricError.AUTHENTICATION_FAILED)
}
}
)
fun authenticate(
title: String,
subtitle: String,
callback: BiometricAuthCallback
) {
val promptInfo = BiometricPrompt.PromptInfo.Builder()
.setTitle(title)
.setSubtitle(subtitle)
.setAllowedAuthenticators(BiometricManager.Authenticators.BIOMETRIC_STRONG)
.setNegativeButtonText("使用密码登录")
.build()
val cryptoObject = keyManager.createCryptoObject()
this.authCallback = callback
biometricPrompt.authenticate(promptInfo, cryptoObject)
}
}
安全密钥管理
密钥生成与存储通过core/data/src/androidMain/kotlin/io/droidkaigi/core/data/security/SecureKeyManager.kt实现,采用AndroidKeyStore系统安全存储:
class SecureKeyManager(context: Context) {
private val keyStore = KeyStore.getInstance("AndroidKeyStore").apply { load(null) }
private val keyGenerator = KeyGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore"
)
fun createCryptoObject(): BiometricPrompt.CryptoObject {
val keyAlias = "droidkaigi_biometric_key_${BuildConfig.VERSION_CODE}"
generateKeyIfNotExists(keyAlias)
val secretKey = keyStore.getKey(keyAlias, null) as SecretKey
val cipher = Cipher.getInstance(TRANSFORMATION)
cipher.init(Cipher.ENCRYPT_MODE, secretKey)
return BiometricPrompt.CryptoObject(cipher)
}
private fun generateKeyIfNotExists(keyAlias: String) {
if (!keyStore.containsAlias(keyAlias)) {
keyGenerator.init(
KeyGenParameterSpec.Builder(
keyAlias,
KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
)
.setBlockModes(KeyProperties.BLOCK_MODE_CBC)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
.setUserAuthenticationRequired(true)
.setInvalidatedByBiometricEnrollment(true)
.build()
)
keyGenerator.generateKey()
}
}
companion object {
private const val TRANSFORMATION = "AES/CBC/PKCS7Padding"
}
}
iOS面容识别实现
Face ID认证流程
iOS端使用LocalAuthentication框架实现Face ID认证,核心代码位于app-ios/Sources/AuthFeature/Services/BiometricAuthenticator.swift:
import LocalAuthentication
class BiometricAuthenticator {
enum AuthenticationError: Error {
case notAvailable
case notEnrolled
case authFailed
case userCancel
case systemCancel
case passcodeNotSet
}
private let context = LAContext()
private var ongoingEvaluation = false
func canAuthenticate() -> Bool {
var error: NSError?
let canEvaluate = context.canEvaluatePolicy(
.deviceOwnerAuthenticationWithBiometrics,
error: &error
)
return canEvaluate && error == nil
}
func authenticate(
reason: String,
completion: @escaping (Result<Void, AuthenticationError>) -> Void
) {
guard !ongoingEvaluation else { return }
guard canAuthenticate() else {
completion(.failure(.notAvailable))
return
}
ongoingEvaluation = true
context.evaluatePolicy(
.deviceOwnerAuthenticationWithBiometrics,
localizedReason: reason
) { [weak self] success, error in
DispatchQueue.main.async {
self?.ongoingEvaluation = false
switch error {
case LAError.authenticationFailed:
completion(.failure(.authFailed))
case LAError.userCancel, LAError.appCancel:
completion(.failure(.userCancel))
case LAError.systemCancel:
completion(.failure(.systemCancel))
case LAError.passcodeNotSet:
completion(.failure(.passcodeNotSet))
case LAError.biometryNotEnrolled:
completion(.failure(.notEnrolled))
case nil where success:
completion(.success(()))
default:
completion(.failure(.authFailed))
}
}
}
}
}
认证状态管理
在SwiftUI视图中集成认证功能的示例代码:
// app-ios/Sources/AuthFeature/Views/BiometricAuthView.swift
struct BiometricAuthView: View {
@StateObject private var viewModel = BiometricAuthViewModel()
@Binding var isPresented: Bool
var onAuthSuccess: () -> Void
var body: some View {
VStack(spacing: 24) {
Image(uiImage: UIImage(named: "face_id_auth", in: .module, with: nil)!)
.resizable()
.frame(width: 120, height: 120)
Text("使用Face ID解锁")
.font(.title)
.fontWeight(.semibold)
Text("请将面部对准摄像头以验证身份")
.foregroundColor(.secondary)
.multilineTextAlignment(.center)
.padding(.horizontal)
if viewModel.showError {
Text(viewModel.errorMessage)
.foregroundColor(.red)
.multilineTextAlignment(.center)
.padding()
}
Spacer()
Button("取消") {
isPresented = false
}
.buttonStyle(SecondaryButtonStyle())
}
.padding()
.onAppear {
viewModel.authenticate { result in
switch result {
case .success:
onAuthSuccess()
isPresented = false
case .failure(let error):
viewModel.handleError(error)
}
}
}
}
}
认证图标资源
iOS端使用的Face ID认证图标位于app-ios/Sources/AuthFeature/Resources/Media.xcassets/face_id_auth.imageset: Face ID认证图标
跨平台认证架构设计
项目采用Kotlin Multiplatform (KMP)实现跨平台开发,生物识别功能通过以下架构实现平台统一调用:
共享接口定义
core/common/src/commonMain/kotlin/io/droidkaigi/core/common/auth/BiometricAuthService.kt定义统一接口:
expect interface BiometricAuthService {
suspend fun authenticate(reason: String): Result<Unit>
fun isBiometricAvailable(): Boolean
fun getBiometricType(): BiometricType
}
enum class BiometricType {
NONE,
FINGERPRINT,
FACE,
IRIS
}
平台实现类图
依赖注入配置
通过依赖注入框架实现平台服务自动选择: core/di/src/commonMain/kotlin/io/droidkaigi/core/di/AuthModule.kt:
val authModule = module {
single<BiometricAuthService> {
when (Platform.current) {
is Platform.Android -> AndroidBiometricAuthService(
context = get(),
keyManager = get()
)
is Platform.Ios -> IosBiometricAuthService(
authenticator = get()
)
else -> error("Biometric auth not supported on this platform")
}
}
}
安全性最佳实践
生物识别安全机制对比
| 安全机制 | Android实现 | iOS实现 |
|---|---|---|
| 加密存储 | AndroidKeyStore系统密钥库 | Keychain Services |
| 认证级别 | BIOMETRIC_STRONG级别 | LAPolicy.deviceOwnerAuthenticationWithBiometrics |
| 密钥失效策略 | 生物特征变更自动失效 | 依赖系统自动管理 |
| 错误处理 | 自定义错误码映射 | 系统错误码转换 |
数据加密实现
敏感数据加密通过core/data/src/commonMain/kotlin/io/droidkaigi/core/data/security/SecureDataManager.kt实现:
class SecureDataManager(
private val biometricAuthService: BiometricAuthService,
private val secureStorage: SecureStorage
) {
suspend fun encryptAndStore(
key: String,
data: String,
requireAuth: Boolean = true
): Result<Unit> {
return if (requireAuth) {
biometricAuthService.authenticate("加密数据访问").mapCatching {
val encryptedData = encrypt(data)
secureStorage.save(key, encryptedData)
}
} else {
runCatching {
val encryptedData = encrypt(data)
secureStorage.save(key, encryptedData)
}
}
}
private fun encrypt(data: String): String {
// 平台特定加密实现
}
}
功能使用指南
用户可在应用设置中启用生物识别:
- 打开应用"设置"页面(feature/settings/src/commonMain/kotlin/io/droidkaigi/feature/settings/SettingsScreen.kt)
- 选择"安全与隐私"选项
- 启用"生物识别认证"开关
- 按照引导完成生物特征录入
未来功能规划
- 多因素认证:结合生物识别与设备PIN码
- 生物特征多样性支持:增加虹膜识别等新型生物特征
- 连续认证模式:会议期间周期性身份验证
项目生物识别模块持续迭代,欢迎通过CONTRIBUTING.md文档提交改进建议或PR。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



