Flutter一次性密码(TOTP)认证插件auth_totp的使用

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

Flutter一次性密码(TOTP)认证插件auth_totp的使用

auth_totp 是一个快速且易于使用的基于时间的一次性密码(TOTP)认证包,适用于你的Flutter应用。它与 Google Authenticator1PasswordLastPassMicrosoft Authenticator 以及其他各种认证应用程序兼容。

Get Started

Create Secret Key 🔑

生成一个随机的秘密密钥,用于从认证应用程序创建验证码。

String secret = AuthTOTP.createSecret(
    length: 16,
    autoPadding: true,
    secretKeyStyle: SecretKeyStyle.upperLowerCase
);

// 输出示例:xHu6 nh7I D8uI s9B1
  • length: 密钥长度,默认值为32,范围在16到255之间。
  • autoPadding: 是否自动填充,将密钥分为每4个字符一组,默认为false。
  • secretKeyStyle: 密钥风格,可以是大写、小写或大小写混合。

Verify TOTP Code ✔️

验证用户输入的TOTP代码是否正确。

bool checkOTP = AuthTOTP.verifyCode({
    secretKey: "secret_key_here",
    totpCode: "totp_code_here_by_user",
    interval: 30
});
  • secretKey: 使用createSecret方法生成的秘密密钥。
  • totpCode: 用户输入的TOTP代码。
  • interval: 时间间隔,默认为30秒。

Generate TOTP Code 🚀

根据秘密密钥和时间间隔生成TOTP代码。

String generatedTOTPCode = AuthTOTP.generateTOTPCode(
    secretKey: 'secret_key_here',
    interval: 30
);

Get QR Code to Scan 📸

返回一个二维码URL,用户可以通过认证应用程序扫描该二维码。

String qrCodeUrl =  AuthTOTP.getQRCodeUrl({
    appName: "your app name",
    secretKey: "secret_key_here",
    issuer:"auth_totp"
});

// Image.Network(qrCodeUrl);

Full Example

以下是一个完整的示例,展示了如何使用auth_totp插件。

import 'package:auth_totp/auth_totp.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(
    const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: QRCodePage(),
    ),
  );
}

class QRCodePage extends StatefulWidget {
  const QRCodePage({super.key});

  @override
  State<QRCodePage> createState() => _QRCodePageState();
}

class _QRCodePageState extends State<QRCodePage> {
  String secret = AuthTOTP.createSecret(
      length: 16,
      autoPadding: true,
      secretKeyStyle: SecretKeyStyle.upperLowerCase);
  String appName = "TOTP"; // 给出你的应用名称

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("Auth TOTP Flutter Package", style: TextStyle(color: Colors.white)),
        centerTitle: true,
        backgroundColor: Colors.green,
        elevation: 0,
        shadowColor: Colors.transparent,
      ),
      body: ListView(
        padding: const EdgeInsets.all(16.0),
        children: [
          const Center(
            child: Text("扫描此二维码或将秘密代码复制到您的认证应用中。点击继续进行验证。"),
          ),
          Image.network(AuthTOTP.getQRCodeUrl(appName: appName, secretKey: secret)),
          Padding(
            padding: const EdgeInsets.all(8.0),
            child: TextField(
              controller: TextEditingController(text: secret),
              decoration: const InputDecoration(
                border: OutlineInputBorder(),
                labelText: 'Secret Code',
              ),
              readOnly: true,
            ),
          ),
          ElevatedButton(
            onPressed: () {
              Navigator.push(
                context,
                MaterialPageRoute(
                  builder: (context) => VerificationPage(secret: secret),
                ),
              );
            },
            child: const Text("Continue to Verify"),
          ),
        ],
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          setState(() {
            secret = AuthTOTP.createSecret(
                length: 16,
                autoPadding: true,
                secretKeyStyle: SecretKeyStyle.upperLowerCase);
            print(AuthTOTP.generateTOTPCode(secretKey: secret, interval: 30));
          });
        },
        child: const Icon(Icons.refresh),
      ),
    );
  }
}

class VerificationPage extends StatefulWidget {
  final String secret;
  const VerificationPage({super.key, required this.secret});

  @override
  State<VerificationPage> createState() => _VerificationPageState();
}

class _VerificationPageState extends State<VerificationPage> {
  String code = "";

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("Verify TOTP", style: TextStyle(color: Colors.white)),
        centerTitle: true,
        backgroundColor: Colors.green,
        elevation: 0,
        shadowColor: Colors.transparent,
      ),
      body: Center(
        child: ListView(
          padding: const EdgeInsets.all(16.0),
          children: [
            Padding(
              padding: const EdgeInsets.all(8.0),
              child: TextField(
                keyboardType: TextInputType.number,
                decoration: const InputDecoration(
                  border: OutlineInputBorder(),
                  labelText: 'Enter TOTP Code',
                ),
                onChanged: (value) {
                  setState(() {
                    code = value;
                  });
                },
              ),
            ),
            ElevatedButton(
              onPressed: () {
                setState(() {
                  if (AuthTOTP.verifyCode(secretKey: widget.secret, totpCode: code)) {
                    ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
                      content: Text("Congratulations, TOTP is correct"),
                      backgroundColor: Colors.green,
                      behavior: SnackBarBehavior.floating,
                      margin: EdgeInsets.all(10),
                      shape: RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(10))),
                    ));
                  } else {
                    ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
                      content: Text("Opps, TOTP is incorrect"),
                      backgroundColor: Colors.red,
                      behavior: SnackBarBehavior.floating,
                      margin: EdgeInsets.all(10),
                      shape: RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(10))),
                    ));
                  }
                });
              },
              child: const Text("Verify"),
            ),
          ],
        ),
      ),
    );
  }
}

以上示例展示了如何生成密钥、显示二维码、获取用户输入并验证TOTP代码。你可以根据需要调整和扩展这个示例。


更多关于Flutter一次性密码(TOTP)认证插件auth_totp的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter一次性密码(TOTP)认证插件auth_totp的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter项目中使用auth_totp插件来实现一次性密码(TOTP)认证的代码案例。这个插件允许你生成和验证基于时间的一次性密码(TOTP)。

1. 添加依赖

首先,在你的pubspec.yaml文件中添加auth_totp依赖:

dependencies:
  flutter:
    sdk: flutter
  auth_totp: ^x.y.z  # 请将x.y.z替换为最新版本号

然后运行flutter pub get来安装依赖。

2. 导入插件

在你的Dart文件中导入插件:

import 'package:auth_totp/auth_totp.dart';

3. 生成TOTP URI

要生成一个用于配置TOTP应用的URI,你需要提供密钥(通常是Base32编码的)、账户名(可选)、发行者名(可选)以及时间步长(默认为30秒)。

void generateTotpUri() {
  String secret = 'JBSWY3DPEHPK3PXP'; // 示例密钥(Base32编码)
  String accountName = 'user@example.com';
  String issuer = 'MyApp';
  int timeStep = 30; // 时间步长,单位秒

  String uri = TOTP.generateTotpURI(
    secret: secret,
    issuer: issuer,
    accountName: accountName,
    timeStep: timeStep,
  );

  print('TOTP URI: $uri');
}

4. 生成和验证TOTP

使用生成的密钥,你可以生成当前时间的TOTP,并验证用户输入的TOTP是否正确。

void generateAndVerifyTotp() async {
  String secret = 'JBSWY3DPEHPK3PXP'; // 示例密钥(Base32编码)
  int timeStep = 30; // 时间步长,单位秒
  int digits = 6; // TOTP长度,通常为6位

  // 生成当前时间的TOTP
  String generatedTotp = await TOTP.generateTotp(
    secret: secret,
    timeStep: timeStep,
    digits: digits,
  );

  print('Generated TOTP: $generatedTotp');

  // 用户输入的TOTP
  String userInputTotp = '123456'; // 假设用户输入了这个TOTP

  // 验证TOTP
  bool isValid = await TOTP.verifyTotp(
    secret: secret,
    timeStep: timeStep,
    digits: digits,
    totp: userInputTotp,
    window: 1, // 验证的时间窗口大小,允许前后偏差的时间步长数
  );

  print('Is TOTP valid? $isValid');
}

5. 完整示例

将上述代码整合到一个完整的示例中:

import 'package:flutter/material.dart';
import 'package:auth_totp/auth_totp.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('TOTP Example'),
        ),
        body: Center(
          child: ElevatedButton(
            onPressed: () async {
              // 生成TOTP URI
              String secret = 'JBSWY3DPEHPK3PXP';
              String accountName = 'user@example.com';
              String issuer = 'MyApp';
              int timeStep = 30;

              String uri = TOTP.generateTotpURI(
                secret: secret,
                issuer: issuer,
                accountName: accountName,
                timeStep: timeStep,
              );

              print('TOTP URI: $uri');

              // 生成和验证TOTP
              String generatedTotp = await TOTP.generateTotp(
                secret: secret,
                timeStep: timeStep,
                digits: 6,
              );

              print('Generated TOTP: $generatedTotp');

              // 假设用户输入了这个TOTP
              String userInputTotp = generatedTotp; // 在实际应用中,这将是用户输入的值

              bool isValid = await TOTP.verifyTotp(
                secret: secret,
                timeStep: timeStep,
                digits: 6,
                totp: userInputTotp,
                window: 1,
              );

              print('Is TOTP valid? $isValid');

              // 显示结果(仅用于示例)
              ScaffoldMessenger.of(context).showSnackBar(
                SnackBar(
                  content: Text('TOTP Valid: $isValid'),
                ),
              );
            },
            child: Text('Generate and Verify TOTP'),
          ),
        ),
      ),
    );
  }
}

这个示例展示了如何在Flutter应用中生成TOTP URI、生成TOTP以及验证用户输入的TOTP。你可以根据实际需求进一步定制和扩展这个示例。

回到顶部