Flutter密码凭证管理插件password_credential的使用
Flutter密码凭证管理插件 password_credential
的使用
password_credential
是一个用于访问密码凭证的Flutter插件。它支持在Web(Chrome)和Android平台上使用,分别通过Credentials Management API和Smartlock for Password进行密码凭证的存储和读取。
平台支持
- Web (Chrome): 使用 Credentials Management API
- Android: 使用 Smartlock for Password
当用户使用相同的Google账户登录到Chrome或Android设备时,存储在这些系统中的ID和密码会自动同步。
示例项目
Web 示例项目
Android 示例项目
用户设置
重要提示
- 如果用户在系统范围内禁用了密码存储功能,或者针对特定应用禁用了该功能,则存储操作将失败且不会有任何用户交互。
- 如果用户在系统范围内禁用了自动登录功能,则静默读取操作将失败,并且其他读取操作将要求用户选择密码条目。
在Android中,每个应用的拒绝设置会保存在所有已登录Google账户中。只有当所有Google账户都没有拒绝该应用时,才会显示存储权限对话框。如果用户看不到任何对话框并且无法存储凭据,请检查所有Google账户的自动填充设置,并允许您的应用存储凭据。
示例代码
以下是一个完整的示例Demo,展示了如何使用password_credential
插件进行密码凭证的存储、读取和删除操作。
import 'package:flutter/material.dart';
import 'package:password_credential/entity/mediation.dart';
import 'package:provider/provider.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(App());
}
class App extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
return MultiProvider(
providers: [ChangeNotifierProvider<Model>(create: (_) => Model())],
child: Consumer<Model>(builder: (context, model, _) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(body: Builder(builder: (context) {
void snackbar(String message) {
Scaffold.of(context)
.showSnackBar(SnackBar(content: Text(message)));
}
return SafeArea(
child: Column(children: [
Container(
child: Column(children: [
Row(
children: [
Container(width: 80, child: Text("ID")),
Expanded(child: TextField(controller: model.idEdit))
],
),
Row(
children: [
Container(width: 80, child: Text("Password")),
Expanded(
child:
TextField(controller: model.passwordEdit))
],
),
]),
margin: EdgeInsets.only(left: 20, right: 20)),
Expanded(
child: ListView(children: <Widget>[
ListTile(
title: Text("输入示例ID/密码"),
onTap: () async {
model.idEdit.text = "my_id";
model.passwordEdit.text = "my_password";
},
),
ListTile(
title: Text("清除输入"),
onTap: () async {
model.idEdit.text = "";
model.passwordEdit.text = "";
},
),
ListTile(
title: Text("静默存储"),
subtitle: Text(
"Android: 仅当用户已经允许存储该ID时成功。Web: 忽略静默参数,对于更新密码的操作是静默的,对于新条目则会询问用户是否保存。如果用户拒绝一次或禁用密码保存,则此操作总是失败且不显示对话框。"),
onTap: () async {
try {
var result = await model.store(Mediation.Silent);
snackbar(result.toString());
} catch (e) {
snackbar(e.toString());
}
},
),
ListTile(
title: Text("可选存储"),
subtitle: Text(
"Android/Web: 对于更新密码的操作是静默的,对于新条目则会询问用户是否保存。如果用户拒绝一次或禁用密码保存,则此操作总是失败且不显示对话框。"),
onTap: () async {
try {
var result = await model.store(Mediation.Optional);
snackbar(result.toString());
} catch (e) {
snackbar(e.toString());
}
},
),
ListTile(
title: Text("强制存储"),
subtitle: Text(
"Android: 删除现有条目后始终询问用户是否允许。Web: 忽略必需参数,对于更新密码的操作是静默的,对于新条目则会询问用户是否保存。如果用户拒绝一次或禁用密码保存,则此操作总是失败且不显示对话框。"),
onTap: () async {
try {
var result = await model.store(Mediation.Required);
snackbar(result.toString());
} catch (e) {
snackbar(e.toString());
}
},
),
ListTile(
title: Text("静默获取"),
subtitle: Text(
"Android/Web: 仅当用户已经允许存储或读取该条目时成功。如果禁用了自动登录,此操作总是失败。"),
onTap: () async {
var result = await model.get(Mediation.Silent);
snackbar(result.toString());
},
),
ListTile(
title: Text("可选获取"),
subtitle: Text(
"Android/Web: 当用户已经允许存储或读取该条目时成功,否则会显示账户选择界面。如果禁用了自动登录,总是会显示账户选择界面。"),
onTap: () async {
var result = await model.get(Mediation.Optional);
snackbar(result.toString());
},
),
ListTile(
title: Text("强制获取"),
subtitle: Text(
"Android/Web: 总是会显示账户选择界面。"),
onTap: () async {
var result = await model.get(Mediation.Required);
snackbar(result.toString());
},
),
ListTile(
title: Text("删除"),
subtitle: Text(
"Android: 总是成功且无需用户交互。Web: 当用户已经允许存储或读取该条目时成功。"),
onTap: () async {
try {
await model.delete();
snackbar("完成");
} catch (e) {
snackbar(e.toString());
}
},
),
ListTile(
title: Text("hasCredentialFeature"),
subtitle: Text(model.hasCredentialFeature.toString()),
),
ListTile(
title: Text("preventSilentAccess"),
subtitle: Text(
"Android/Web: 强制忘记用户的过去选择。"),
onTap: () async {
await model.preventSilentAccess();
snackbar("完成");
},
),
ListTile(
title: Text("openPlatformCredentialSettings"),
subtitle: Text(
"Android: 打开Google账户设置。Web: 出于Chrome安全原因未实现。"),
onTap: () async {
try {
await model.openPlatformCredentialSettings();
snackbar("完成");
} catch (e) {
snackbar(e.toString());
}
},
),
]))
]));
})));
}));
}
}
更多关于Flutter密码凭证管理插件password_credential的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter密码凭证管理插件password_credential的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是一个关于如何在Flutter应用中使用password_credential
插件进行密码凭证管理的示例代码。password_credential
插件允许你以更安全的方式存储和检索用户凭证。
首先,确保你已经在pubspec.yaml
文件中添加了password_credential
依赖:
dependencies:
flutter:
sdk: flutter
password_credential: ^x.y.z # 请替换为最新版本号
然后运行flutter pub get
来安装依赖。
接下来,你可以在你的Flutter应用中按如下方式使用password_credential
插件:
import 'package:flutter/material.dart';
import 'package:password_credential/password_credential.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Password Credential Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final _formKey = GlobalKey<FormState>();
String _username = '';
String _password = '';
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Password Credential Demo'),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Form(
key: _formKey,
child: Column(
children: <Widget>[
TextFormField(
decoration: InputDecoration(labelText: 'Username'),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter a username';
}
return null;
},
onSaved: (value) {
_username = value;
},
),
TextFormField(
decoration: InputDecoration(labelText: 'Password'),
obscureText: true,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter a password';
}
return null;
},
onSaved: (value) {
_password = value;
},
),
SizedBox(height: 20),
ElevatedButton(
onPressed: () async {
if (_formKey.currentState.validate()) {
_formKey.currentState.save();
// Store the credentials
await PasswordCredential.store(
serviceName: 'MyAppService',
username: _username,
password: _password,
);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Credentials saved')),
);
}
},
child: Text('Save Credentials'),
),
SizedBox(height: 20),
ElevatedButton(
onPressed: () async {
try {
// Retrieve the credentials
final credential = await PasswordCredential.retrieve(
serviceName: 'MyAppService',
);
if (credential != null) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
'Retrieved Credentials: Username - ${credential.username}, Password - ${credential.password}',
),
),
);
} else {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('No credentials found')),
);
}
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error retrieving credentials')),
);
}
},
child: Text('Retrieve Credentials'),
),
],
),
),
),
);
}
}
在这个示例中,我们创建了一个简单的Flutter应用,其中包含一个表单,用于输入用户名和密码。用户可以通过点击“Save Credentials”按钮将凭据存储起来,并通过点击“Retrieve Credentials”按钮来检索存储的凭据。
注意:
PasswordCredential.store
方法用于存储凭证。PasswordCredential.retrieve
方法用于检索凭证。
请确保在实际应用中处理凭证时遵循最佳安全实践,例如使用加密技术来存储敏感信息。