Flutter JWT管理插件simple_jwt_manager的使用

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

Flutter JWT管理插件simple_jwt_manager的使用

(日语版本可见此处)。

概述

这是一个支持使用JWT进行身份验证的软件包。目前,它支持使用在RFC 6749中定义的“资源所有者密码凭据授权”,以及一般的注册功能。登出处理遵循RFC 7009。

使用方法

请参阅pub.dev上的示例标签。

支持

基本上不提供支持。如果你有任何问题,请在GitHub上打开一个issue。这个包优先级较低,但可能会被修复。

版本控制

当版本升级时,C部分会发生变化。然而,小于1.0.0的版本可能不受以下规则的约束。

  • 添加变量、导致读取先前文件出现问题的结构更改。
    • C.X.X
  • 添加方法等。
    • X.C.X
  • 小修改和错误修复。
    • X.X.C

许可证

版权所有 2024 Masahide Mori

根据Apache许可证2.0版(“许可证”)获得许可; 你不能使用此文件,除非遵守许可证。 你可以在以下网址获得许可证的副本:

   http://www.apache.org/licenses/LICENSE-2.0

除非适用法律要求或书面同意,否则根据许可证分发的软件是按“原样”分发的,没有任何明示或暗示的保证或条件。请参阅许可证以获取特定的语言规定权限和限制。

版权声明

“Dart”名称和“Flutter”名称是Google LLC的商标。 *该软件包的开发者不是Google LLC。

完整示例代码

import 'package:flutter/material.dart';
import 'package:simple_jwt_manager/simple_jwt_manager.dart';
import 'dart:convert';

// TODO 选择客户端版本。
late final ROPCClient ropcClient; // web 或 native
// late final ROPCClientForNative
//     ropcClient; // native,使用自签名证书

// TODO: 请确保重写此URL。
const String registerURL = "https://your end point url";
const String signInURL = "https://your end point url";
const String refreshURL = "https://your end point url";
const String signOutURL = "https://your end point url";
const String deleteUserURL = "https://your end point url";
// 包含JWT的认证头的POST数据的URL。
const String postingDataURL = "https://your end point url";

void main() async {
  Map<String, dynamic>? savedData;
  // TODO: 如果有必要,以自己的方式恢复存储的令牌。
  // savedData = jsonDecode(从存储中获取的令牌);
  // 在实际应用中,可以将ROPCClient封装在一个单例类中。
  // 因为ROPCClient类不是一个单例,
  // 所以可以在多个ROPCClient中分别管理多个令牌。

  // 对于web或native设备。
  ropcClient = ROPCClient(
      registerURL: registerURL,
      signInURL: signInURL,
      refreshURL: refreshURL,
      signOutURL: signOutURL,
      deleteUserURL: deleteUserURL,
      savedData: savedData);

  // 仅适用于native设备。
  // 这个版本可以支持自签名证书。
  // ropcClient = ROPCClientForNative(
  //     registerURL: registerURL,
  //     signInURL: signInURL,
  //     refreshURL: refreshURL,
  //     signOutURL: signOutURL,
  //     deleteUserURL: deleteUserURL,
  //     badCertificateCallback: (X509Certificate cert, String host, int port) {
  //       // TODO
  //       // 这里检查条件,如果返回true,则允许自签名证书。
  //       return true;
  //     },
  //     savedData: savedData);

  runApp(const MyApp());
}

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

  [@override](/user/override)
  State<StatefulWidget> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final TextEditingController _tecID = TextEditingController();
  final TextEditingController _tecPW = TextEditingController();

  [@override](/user/override)
  void dispose() {
    _tecID.dispose();
    _tecPW.dispose();
    super.dispose();
  }

  // TODO 请注意,这只是使用示例,并不会像这样布局。
  [@override](/user/override)
  Widget build(BuildContext context) {
    // TODO 你可以这样获取signIn状态:
    // final bool isSignedIn = ropcClient.isSignedIn();
    return MaterialApp(
      title: 'Simple JWT Manager Example',
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Simple JWT Manager Example'),
          backgroundColor: const Color.fromARGB(255, 0, 255, 0),
        ),
        backgroundColor: const Color.fromARGB(255, 255, 255, 255),
        body: Row(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            Column(
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.center,
              children: [
                Container(
                    width: 320,
                    margin: const EdgeInsets.fromLTRB(0, 0, 0, 0),
                    child: TextField(
                      controller: _tecID,
                      decoration:
                          const InputDecoration(hintText: "User ID (e-mail)"),
                    )),
                Container(
                    width: 320,
                    margin: const EdgeInsets.fromLTRB(0, 12, 0, 0),
                    child: TextField(
                      controller: _tecPW,
                      decoration:
                          const InputDecoration(hintText: "User password"),
                    )),
                Container(
                    margin: const EdgeInsets.fromLTRB(0, 48, 0, 0),
                    child: ElevatedButton(
                      onPressed: () {
                        ropcClient
                            .register(_tecID.text, _tecPW.text)
                            .then((ServerResponse v) {
                          debugPrint(v.toString());
                          switch (v.resultStatus) {
                            case EnumSeverResponseStatus.success:
                              // TODO: 如果后端返回令牌,可以在这里存储。
                              // final String serializedClients = jsonEncode(ropcClient.toDict());
                              // TODO 如果你想,可以以自己的方式保存它。
                              // TODO 请添加用户注册完成后的处理过程。
                              break;
                            case EnumSeverResponseStatus.timeout:
                              // TODO: 处理超时情况。
                              break;
                            case EnumSeverResponseStatus.serverError:
                              // TODO: 处理服务器端错误。
                              break;
                            case EnumSeverResponseStatus.otherError:
                              // TODO: 处理其他错误。
                              break;
                            case EnumSeverResponseStatus.signInRequired:
                              // 通常不会发生在这里。
                              throw Exception();
                          }
                        });
                      },
                      child: const Text('注册'),
                    )),
                Container(
                    margin: const EdgeInsets.fromLTRB(0, 12, 0, 0),
                    child: ElevatedButton(
                      onPressed: () {
                        ropcClient
                            .signIn(_tecID.text, _tecPW.text)
                            .then((ServerResponse v) {
                          debugPrint(v.toString());
                          switch (v.resultStatus) {
                            case EnumSeverResponseStatus.success:
                              // TODO: 如果后端返回令牌,可以在这里存储。
                              // final String serializedClients =
                              jsonEncode(ropcClient.toDict());
                              // TODO 如果你想,可以以自己的方式保存它。
                              // TODO 请添加用户注册完成后的处理过程。
                              break;
                            case EnumSeverResponseStatus.timeout:
                              // TODO: 处理超时情况。
                              break;
                            case EnumSeverResponseStatus.serverError:
                              // TODO: 处理服务器端错误。
                              break;
                            case EnumSeverResponseStatus.otherError:
                              // TODO: 处理其他错误。
                              break;
                            case EnumSeverResponseStatus.signInRequired:
                              // 通常不会发生在这里。
                              throw Exception();
                          }
                        });
                      },
                      child: const Text('登录'),
                    )),
                Container(
                    margin: const EdgeInsets.fromLTRB(0, 12, 0, 0),
                    child: ElevatedButton(
                      onPressed: () {
                        ropcClient.signOutAllTokens().then((ServerResponse v) {
                          debugPrint(v.toString());
                          switch (v.resultStatus) {
                            case EnumSeverResponseStatus.success:
                              // 登出完成。
                              break;
                            case EnumSeverResponseStatus.timeout:
                              // TODO: 处理超时情况。
                              break;
                            case EnumSeverResponseStatus.serverError:
                              // TODO: 处理服务器端错误。
                              break;
                            case EnumSeverResponseStatus.otherError:
                              // TODO: 处理其他错误。
                              break;
                            case EnumSeverResponseStatus.signInRequired:
                              // 通常不会发生在这里。
                              throw Exception();
                          }
                        });
                      },
                      child: const Text('登出'),
                    )),
                Container(
                    margin: const EdgeInsets.fromLTRB(0, 12, 0, 0),
                    child: ElevatedButton(
                      onPressed: () {
                        ropcClient
                            .deleteUser(_tecID.text, _tecPW.text)
                            .then((ServerResponse v) {
                          debugPrint(v.toString());
                          switch (v.resultStatus) {
                            case EnumSeverResponseStatus.success:
                              // 删除用户完成。
                              break;
                            case EnumSeverResponseStatus.timeout:
                              // TODO: 处理超时情况。
                              break;
                            case EnumSeverResponseStatus.serverError:
                              // TODO: 处理服务器端错误。
                              break;
                            case EnumSeverResponseStatus.otherError:
                              // TODO: 处理其他错误。
                              break;
                            case EnumSeverResponseStatus.signInRequired:
                              // 通常不会发生在这里。
                              throw Exception();
                          }
                        });
                      },
                      child: const Text('删除用户'),
                    )),
                Container(
                    margin: const EdgeInsets.fromLTRB(0, 12, 0, 0),
                    child: ElevatedButton(
                      onPressed: () {
                        ropcClient
                            .refreshAndGetNewToken()
                            .then((ServerResponse v) {
                          debugPrint(v.toString());
                          switch (v.resultStatus) {
                            case EnumSeverResponseStatus.success:
                              // 完成。
                              break;
                            case EnumSeverResponseStatus.timeout:
                              // TODO: 处理超时情况。
                              break;
                            case EnumSeverResponseStatus.serverError:
                              // TODO: 处理服务器端错误。
                              break;
                            case EnumSeverResponseStatus.otherError:
                              // TODO: 处理其他错误。
                              break;
                            case EnumSeverResponseStatus.signInRequired:
                              // TODO:
                              debugPrint("登录所需");
                              break;
                          }
                        });
                      },
                      child: const Text('刷新令牌(仅调试)'),
                    )),
                Container(
                    margin: const EdgeInsets.fromLTRB(0, 12, 0, 0),
                    child: ElevatedButton(
                      onPressed: () async {
                        String? jwt = await ropcClient.getToken();
                        debugPrint("令牌: ${jwt ?? "null"}");
                        if (jwt != null) {
                          // TODO 添加你的实现以在后端执行某些操作。

                          // 对于web或native设备。
                          final ServerResponse res = await UtilHttps.post(
                              postingDataURL,
                              {"test": "test params"},
                              EnumPostEncodeType.json,
                              jwt: jwt);

                          // 仅适用于native设备。
                          // 这个版本可以支持自签名证书。
                          // final ServerResponse res =
                          //     await UtilHttpsForNative.post(
                          //         postingDataURL,
                          //         {"test": "test params"},
                          //         EnumPostEncodeType.json,
                          //         jwt: jwt, badCertificateCallback:
                          //             (X509Certificate cert, String host,
                          //                 int port) {
                          //   // TODO
                          //   // 这里检查条件,如果返回true,则允许自签名证书。
                          //   return true;
                          // });

                          // 服务器响应
                          debugPrint("服务器响应: $res");
                          switch (res.resultStatus) {
                            case EnumSeverResponseStatus.success:
                              // TODO: 处理这个情况。
                              break;
                            case EnumSeverResponseStatus.timeout:
                              // TODO: 处理这个情况。
                              break;
                            case EnumSeverResponseStatus.serverError:
                              // TODO: 处理这个情况。
                              break;
                            case EnumSeverResponseStatus.otherError:
                              // TODO: 处理这个情况。
                              break;
                            case EnumSeverResponseStatus.signInRequired:
                              // TODO: 处理这个情况。
                              break;
                          }
                        } else {
                          // TODO 令牌已过期或未获得,请转到登录屏幕。
                          debugPrint("令牌为空。");
                        }
                      },
                      child: const Text('向EndPoints发送数据'),
                    )),
              ],
            )
          ],
        ),
      ),
    );
  }
}

更多关于Flutter JWT管理插件simple_jwt_manager的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter JWT管理插件simple_jwt_manager的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter项目中使用simple_jwt_manager插件进行JWT(JSON Web Token)管理的示例代码。simple_jwt_manager插件可以帮助你轻松地在Flutter应用中处理JWT的存储、解析和验证等操作。

首先,确保你的Flutter项目中已经添加了simple_jwt_manager依赖。你可以在你的pubspec.yaml文件中添加以下依赖:

dependencies:
  flutter:
    sdk: flutter
  simple_jwt_manager: ^最新版本号  # 请替换为实际的最新版本号

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

示例代码

1. 导入必要的包

在你的Dart文件中导入simple_jwt_manager包:

import 'package:simple_jwt_manager/simple_jwt_manager.dart';

2. 配置JWT Manager

配置JWT Manager实例,通常你会在应用的初始化阶段进行配置:

void configureJwtManager() {
  // 配置JWT存储策略,这里使用内存存储作为示例
  JwtStorage jwtStorage = new MemoryJwtStorage();

  // 初始化JWT Manager
  JwtManager jwtManager = new JwtManager(jwtStorage);

  // 可选:设置JWT解析和验证规则
  jwtManager.jwtParser = new JwtParser(
    secret: 'your-secret-key', // 替换为你的密钥
    issuer: 'your-issuer',     // 替换为你的发行者
    audience: 'your-audience'  // 替换为你的受众
  );

  // 将JWT Manager实例保存到全局变量或依赖注入容器中
  // 例如:
  // globalJwtManager = jwtManager;
}

3. 存储JWT

在用户登录成功后,你可以将JWT存储起来:

void storeJwt(String jwtToken) {
  JwtManager jwtManager = getJwtManagerInstance(); // 获取你之前配置的JWT Manager实例
  jwtManager.storeToken(jwtToken);
}

4. 获取JWT

在需要的时候,你可以从存储中获取JWT:

String? retrieveJwt() {
  JwtManager jwtManager = getJwtManagerInstance(); // 获取你之前配置的JWT Manager实例
  return jwtManager.retrieveToken();
}

5. 解析JWT

你可以解析JWT以获取其中的信息:

void parseJwt() {
  JwtManager jwtManager = getJwtManagerInstance(); // 获取你之前配置的JWT Manager实例
  String? jwtToken = jwtManager.retrieveToken();

  if (jwtToken != null) {
    try {
      JwtDecoded jwtDecoded = jwtManager.decodeToken(jwtToken);
      print('JWT Payload: ${jwtDecoded.payload}');
    } catch (e) {
      print('Failed to decode JWT: $e');
    }
  } else {
    print('No JWT token found.');
  }
}

6. 验证JWT

在需要验证JWT有效性的时候,你可以进行验证:

bool verifyJwt() {
  JwtManager jwtManager = getJwtManagerInstance(); // 获取你之前配置的JWT Manager实例
  String? jwtToken = jwtManager.retrieveToken();

  if (jwtToken != null) {
    try {
      bool isValid = jwtManager.verifyToken(jwtToken);
      return isValid;
    } catch (e) {
      print('Failed to verify JWT: $e');
      return false;
    }
  } else {
    print('No JWT token found.');
    return false;
  }
}

7. 移除JWT

当用户注销时,你可以移除存储的JWT:

void removeJwt() {
  JwtManager jwtManager = getJwtManagerInstance(); // 获取你之前配置的JWT Manager实例
  jwtManager.clearToken();
}

注意事项

  • 确保你的密钥(secret)、发行者(issuer)和受众(audience)与服务器端的配置相匹配。
  • 在生产环境中,建议使用更安全的JWT存储方式,比如Keychain(iOS)或KeyStore(Android)。
  • 定期检查JWT的有效性,并在必要时刷新JWT。

通过这些代码示例,你可以在Flutter应用中有效地使用simple_jwt_manager插件来管理JWT。

回到顶部