Android
对应的官方页面地址
Passwordless.dev Android 客户端 SDK 使用户能够利用设备的内置指纹传感器和/或 FIDO 安全密钥,对支持 FIDO2 协议的网站和本机应用程序进行安全的无密码访问。
要求
Android 9.0(API 级别 28)或更高版本
Java 8 或更高版本
安装
<dependency>
<groupId>com.bitwarden</groupId>
<artifactId>passwordless-android</artifactId>
<version>1.0.1</version>
</dependency>
权限
在您的 AndroidManifest.xml
中,添加以下权限:
<uses-permission android:name="android.permission.INTERNET" />
配置(Android 应用程序)
在 Android 应用程序的某个位置,配置 PasswordlessOptions
。
data class PasswordlessOptions(
// Your public API key
val apiKey: String,
// Identifier for your server, for example 'example.com' if your backend is hosted at https://example.com.
val rpId: String,
// This is where your Facet ID goes
val origin: String,
// Where your backend is hosted
val backendUrl:String,
// Passwordless.dev server, change for self-hosting
val apiUrl: String = "https://v4.passwordless.dev"
)
.well-known/assetlinks.json
在应用程序的 AndroidManifest.xml
中,在 manifest::application
下添加以下标记:
<meta-data
android:name="asset_statements"
android:resource="@xml/assetlinks" />
在应用程序的 res/xml/assetlinks.xml
中,您需要添加以下内容。这将告诉我们的 Android 应用程序您的 .well-known/assetlinks.json
文件的托管位置。
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="assetlinks">https://yourexample.com/.well-known/assetlinks.json</string>
</resources>
配置(您的后端)
获取 SHA-256 证书指纹
要配置后端,您需要在域的根目录托管一个 .well-known/assetlinks.json
文件。此文件包含允许通过后端进行身份验证的 SHA-256 证书指纹列表。
以下命令将打印有关具有指定别名的密钥库条目的详细信息,包括有关证书、其有效性和其他详细信息的信息。它通常在 Android 开发中用于验证调试密钥库的属性以及开发期间用于签名应用程序的关联密钥。
从终端进入项目根目录并运行以下命令:
./gradlew signingReport
将此 SHA256 与您的根 Android 包名称一起放入后端,以便在 https://yourexample.com/.well-known/assetlinks.json
处为您的应用生成 assetlinks.json
。
如果您使用 example-nodejs-backend
,则只需将这 2 个值放入您的 .env
文件中即可。
托管 ~/.wellknown/assetlinks.json
您需要将以下文件存储在 https://<your-domain>/.well-known/assetlinks.json
处。要生成 SHA256 哈希,请阅读代码片段下方的链接。
您可能还需要更改 'target::namespace' 和 'target::package_name' 属性以匹配您的应用程序。
[
{
"relation": [
"delegate_permission/common.handle_all_urls",
"delegate_permission/common.get_login_creds"
],
"target": {
"namespace": "web"
}
},
{
"relation": [
"delegate_permission/common.handle_all_urls",
"delegate_permission/common.get_login_creds"
],
"target": {
"namespace": "android_app",
"package_name": "com.example.myapplication",
"sha256_cert_fingerprints": [
"3C:E2:29:94:E2:DE:1E:EB:E5:F9:70:10:72:41:F4:0F:06:38:61:BD:72:76:79:CA:72:68:67:FA:38:9B:65:B9"
]
}
}
]
使用 PasswordlessClient
您可以通过注入 Dagger Hilt 来设置 ActivityContext
和 CoroutineScope
,方法如下:
@Module
@InstallIn(ActivityComponent::class)
class PasswordlessModule {
@Provides
fun provideLifecycleCoroutineScope(activity: Activity): LifecycleCoroutineScope =
(activity as AppCompatActivity).lifecycleScope
@Provides
@ActivityScoped
fun providePasswordlessClient(
@ActivityContext activity: Context, scope: LifecycleCoroutineScope): PasswordlessClient {
val options = PasswordlessOptions(
DemoPasswordlessOptions.API_KEY,
DemoPasswordlessOptions.RP_ID,
DemoPasswordlessOptions.ORIGIN,
DemoPasswordlessOptions.API_URL
)
return PasswordlessClient(options, activity, scope)
}
}
注册
用户界面 (UI):
(必填)指定凭据的用户名。
(可选)如果是不可发现的凭据,则将用户作为别名输入。
调用
your backend
实现的POST /register/token
:您的后端应调用 Passwordless.de API 生成注册令牌。参阅 API 文档
调用
PasswordlessClient.register()
:
// 将注册令牌传递给 PasswordlessClient.register()
_passwordless.register(
token = responseToken,
nickname = nickname
) { success, exception, result ->
if (success) {
Toast.makeText(context, result.toString(), Toast.LENGTH_SHORT).show()
} else {
Toast.makeText(context, "Exception: " + getPasskeyFailureMessage(exception as Exception), Toast.LENGTH_SHORT).show()
}
}
登录
用户界面 (UI):(可选)如果是不可发现的凭据,则将用户作为别名输入。
调用
PasswordlessClient.login()
:使用(可选)别名和响应回调启动登录过程。调用
your backend
实现的POST /register/token
:您的后端应调用 Passwordless.de API 生成注册令牌。参阅 API 文档
// 使用别名调用 PasswordlessClient.login()
_passwordless.login(alias) { success, exception, result ->
if (success) {
lifecycleScope.launch {
// 成功后,调用后端验证令牌,例如返回一个 JWT 令牌。
val clientDataResponse = httpClient.login(UserLoginRequest(result?.token!!))
if (clientDataResponse.isSuccessful) {
// 登录成功。 解析响应或 JWT 令牌并继续。
val data = clientDataResponse.body()
showText(data.toString())
}
}
} else {
showException(exception)
}
}
示例
您可以在这里找到示例应用程序的源代码。
参考
最后更新于