Flutter密码凭证管理插件password_credential的使用

发布于 1周前 作者 itying888 来自 Flutter

Flutter密码凭证管理插件 password_credential 的使用

password_credential 是一个用于访问密码凭证的Flutter插件。它支持在Web(Chrome)和Android平台上使用,分别通过Credentials Management API和Smartlock for Password进行密码凭证的存储和读取。

平台支持

当用户使用相同的Google账户登录到Chrome或Android设备时,存储在这些系统中的ID和密码会自动同步。

示例项目

Web 示例项目

Web 示例

Android 示例项目

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

1 回复

更多关于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 方法用于检索凭证。

请确保在实际应用中处理凭证时遵循最佳安全实践,例如使用加密技术来存储敏感信息。

回到顶部