首页 > 解决方案 > 如何从 Flutter 中的 RSA 私钥生成令牌?

问题描述

嗨,伙计们,我真的对很多事情感到困惑。我所知道的是,我必须在一天结束时生成一个令牌。我得到了一些 RSA 私钥,它是一些“XYZ............ ...dsdsfm”,(显然由于安全问题我无法透露它),从那里我必须生成一些令牌,它将作为我的 API http 请求授权的标头。

问题是 JsonWebKey 的这些与互联网相关的东西,所有这些都不在我的域中,但我仍然尝试学习它们,但不是很清楚。我尝试实现一些由某人用 Java 编写的代码(那个人只知道Java而不是颤动),颤动。

对于 Flutter 实现,我在 pub.dev 中尝试了两个插件......但我没有得到正确的输出。

第一个是https://pub.dev/packages/jose > 我在它的示例页面中尝试了类似的内容,如下所示:

import 'dart:convert';
import 'dart:io';

import 'package:crypto_keys/crypto_keys.dart';
import 'package:jose/jose.dart';
import 'package:x509/x509.dart';

String pkey="XXXXXXXXXXXXXsfds";

void keyGenerator() async {
 //await example1();
  await example2();
//  await example3();
//  await example4();
//  await example5();
 // await example6();
//  await example7();
//  await example8();
}

// decode and verify a JWS
void example1() async {
  var encoded = pkey;

  // create a JsonWebSignature from the encoded string
  var jws = JsonWebSignature.fromCompactSerialization(encoded);

  // extract the payload
  var payload = jws.unverifiedPayload;

  print('content of jws: ${payload.stringContent}');
  print('protected parameters: ${payload.protectedHeader.toJson()}');

  // create a JsonWebKey for verifying the signature
  var jwk = JsonWebKey.fromJson({
    'kty': 'RSA',
    'alg': 'RS256',

  });
  var keyStore = JsonWebKeyStore()..addKey(jwk);

  // verify the signature
  var verified = await jws.verify(keyStore);
  print('signature verified: $verified');
}

// create a JWS
void example2() async {
  // create a builder
  var builder = JsonWebSignatureBuilder();

  // set the content
  builder.stringContent = 'It is me';

  // set some protected header
  builder.setProtectedHeader('createdAt', DateTime.now().toIso8601String());

  // add a key to sign, you can add multiple keys for different recipients
  builder.addRecipient(
      JsonWebKey.fromJson({
        'kty': 'RSA',
        'kid': pkey,
      }),
      algorithm: 'RS256');

  // build the jws
  var jws = builder.build();

  // output the compact serialization
  print('jws compact serialization: ${jws.toCompactSerialization()}');

  // output the json serialization
  print('jws json serialization: ${jws.toJson()}');
}

// decode and decrypt a JWE
void example3() async {
  var encoded = 'eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.'
      'UGhIOguC7IuEvf_NPVaXsGMoLOmwvc1GyqlIKOK1nN94nHPoltGRhWhw7Zx0-kFm'
      '1NJn8LE9XShH59_i8J0PH5ZZyNfGy2xGdULU7sHNF6Gp2vPLgNZ__deLKxGHZ7Pc'
      'HALUzoOegEI-8E66jX2E4zyJKx-YxzZIItRzC5hlRirb6Y5Cl_p-ko3YvkkysZIF'
      'NPccxRU7qve1WYPxqbb2Yw8kZqa2rMWI5ng8OtvzlV7elprCbuPhcCdZ6XDP0_F8'
      'rkXds2vE4X-ncOIM8hAYHHi29NX0mcKiRaD0-D-ljQTP-cFPgwCp6X-nZZd9OHBv'
      '-B3oWh2TbqmScqXMR4gp_A.'
      'AxY8DCtDaGlsbGljb3RoZQ.'
      'KDlTtXchhZTGufMYmOYGS4HffxPSUrfmqCHXaI9wOGY.'
      '9hH0vgRfYgPnAHOd8stkvw';

  // create a JsonWebEncryption from the encoded string
  var jwe = JsonWebEncryption.fromCompactSerialization(encoded);

  // create a JsonWebKey for decrypting the signature
  var jwk = JsonWebKey.fromJson(
    {
      'kty': 'RSA',
      'n': 'sXchDaQebHnPiGvyDOAT4saGEUetSyo9MKLOoWFsueri23bOdgWp4Dy1Wl'
          'UzewbgBHod5pcM9H95GQRV3JDXboIRROSBigeC5yjU1hGzHHyXss8UDpre'
          'cbAYxknTcQkhslANGRUZmdTOQ5qTRsLAt6BTYuyvVRdhS8exSZEy_c4gs_'
          '7svlJJQ4H9_NxsiIoLwAEk7-Q3UXERGYw_75IDrGA84-lA_-Ct4eTlXHBI'
          'Y2EaV7t7LjJaynVJCpkv4LKjTTAumiGUIuQhrNhZLuF_RJLqHpM2kgWFLU'
          '7-VTdL1VbC2tejvcI2BlMkEpk1BzBZI0KQB0GaDWFLN-aEAw3vRw',
      'e': 'AQAB',
      'd': 'VFCWOqXr8nvZNyaaJLXdnNPXZKRaWCjkU5Q2egQQpTBMwhprMzWzpR8Sxq'
          '1OPThh_J6MUD8Z35wky9b8eEO0pwNS8xlh1lOFRRBoNqDIKVOku0aZb-ry'
          'nq8cxjDTLZQ6Fz7jSjR1Klop-YKaUHc9GsEofQqYruPhzSA-QgajZGPbE_'
          '0ZaVDJHfyd7UUBUKunFMScbflYAAOYJqVIVwaYR5zWEEceUjNnTNo_CVSj'
          '-VvXLO5VZfCUAVLgW4dpf1SrtZjSt34YLsRarSb127reG_DUwg9Ch-Kyvj'
          'T1SkHgUWRVGcyly7uvVGRSDwsXypdrNinPA4jlhoNdizK2zF2CWQ',
      'p': '9gY2w6I6S6L0juEKsbeDAwpd9WMfgqFoeA9vEyEUuk4kLwBKcoe1x4HG68'
          'ik918hdDSE9vDQSccA3xXHOAFOPJ8R9EeIAbTi1VwBYnbTp87X-xcPWlEP'
          'krdoUKW60tgs1aNd_Nnc9LEVVPMS390zbFxt8TN_biaBgelNgbC95sM',
      'q': 'uKlCKvKv_ZJMVcdIs5vVSU_6cPtYI1ljWytExV_skstvRSNi9r66jdd9-y'
          'BhVfuG4shsp2j7rGnIio901RBeHo6TPKWVVykPu1iYhQXw1jIABfw-MVsN'
          '-3bQ76WLdt2SDxsHs7q7zPyUyHXmps7ycZ5c72wGkUwNOjYelmkiNS0',
      'dp': 'w0kZbV63cVRvVX6yk3C8cMxo2qCM4Y8nsq1lmMSYhG4EcL6FWbX5h9yuv'
          'ngs4iLEFk6eALoUS4vIWEwcL4txw9LsWH_zKI-hwoReoP77cOdSL4AVcra'
          'Hawlkpyd2TWjE5evgbhWtOxnZee3cXJBkAi64Ik6jZxbvk-RR3pEhnCs',
      'dq': 'o_8V14SezckO6CNLKs_btPdFiO9_kC1DsuUTd2LAfIIVeMZ7jn1Gus_Ff'
          '7B7IVx3p5KuBGOVF8L-qifLb6nQnLysgHDh132NDioZkhH7mI7hPG-PYE_'
          'odApKdnqECHWw0J-F0JWnUd6D2B_1TvF9mXA2Qx-iGYn8OVV1Bsmp6qU',
      'qi': 'eNho5yRBEBxhGBtQRww9QirZsB66TrfFReG_CcteI1aCneT0ELGhYlRlC'
          'tUkTRclIfuEPmNsNDPbLoLqqCVznFbvdB7x-Tl-m0l_eFTj2KiqwGqE9PZ'
          'B9nNTwMVvH3VRRSLWACvPnSiwP8N5Usy-WRXS-V7TbpxIhvepTfE0NNo'
    },
  );
  var keyStore = JsonWebKeyStore()..addKey(jwk);

  // decrypt the payload
  var payload = await jwe.getPayload(keyStore);
  print('decrypted content: ${payload.stringContent}');
}

// create a JWE
void example4() async {
  // create a builder
  var builder = JsonWebEncryptionBuilder();

  // set the content
  builder.stringContent = 'This is my bigest secret';

  // set some protected header
  builder.setProtectedHeader('createdAt', DateTime.now().toIso8601String());

  // add a key to encrypt the Content Encryption Key
  var jwk = JsonWebKey.fromJson(
    {
      'kty': 'RSA',
      'n': 'sXchDaQebHnPiGvyDOAT4saGEUetSyo9MKLOoWFsueri23bOdgWp4Dy1Wl'
          'UzewbgBHod5pcM9H95GQRV3JDXboIRROSBigeC5yjU1hGzHHyXss8UDpre'
          'cbAYxknTcQkhslANGRUZmdTOQ5qTRsLAt6BTYuyvVRdhS8exSZEy_c4gs_'
          '7svlJJQ4H9_NxsiIoLwAEk7-Q3UXERGYw_75IDrGA84-lA_-Ct4eTlXHBI'
          'Y2EaV7t7LjJaynVJCpkv4LKjTTAumiGUIuQhrNhZLuF_RJLqHpM2kgWFLU'
          '7-VTdL1VbC2tejvcI2BlMkEpk1BzBZI0KQB0GaDWFLN-aEAw3vRw',
      'e': 'AQAB',
      'd': 'VFCWOqXr8nvZNyaaJLXdnNPXZKRaWCjkU5Q2egQQpTBMwhprMzWzpR8Sxq'
          '1OPThh_J6MUD8Z35wky9b8eEO0pwNS8xlh1lOFRRBoNqDIKVOku0aZb-ry'
          'nq8cxjDTLZQ6Fz7jSjR1Klop-YKaUHc9GsEofQqYruPhzSA-QgajZGPbE_'
          '0ZaVDJHfyd7UUBUKunFMScbflYAAOYJqVIVwaYR5zWEEceUjNnTNo_CVSj'
          '-VvXLO5VZfCUAVLgW4dpf1SrtZjSt34YLsRarSb127reG_DUwg9Ch-Kyvj'
          'T1SkHgUWRVGcyly7uvVGRSDwsXypdrNinPA4jlhoNdizK2zF2CWQ',
      'p': '9gY2w6I6S6L0juEKsbeDAwpd9WMfgqFoeA9vEyEUuk4kLwBKcoe1x4HG68'
          'ik918hdDSE9vDQSccA3xXHOAFOPJ8R9EeIAbTi1VwBYnbTp87X-xcPWlEP'
          'krdoUKW60tgs1aNd_Nnc9LEVVPMS390zbFxt8TN_biaBgelNgbC95sM',
      'q': 'uKlCKvKv_ZJMVcdIs5vVSU_6cPtYI1ljWytExV_skstvRSNi9r66jdd9-y'
          'BhVfuG4shsp2j7rGnIio901RBeHo6TPKWVVykPu1iYhQXw1jIABfw-MVsN'
          '-3bQ76WLdt2SDxsHs7q7zPyUyHXmps7ycZ5c72wGkUwNOjYelmkiNS0',
      'dp': 'w0kZbV63cVRvVX6yk3C8cMxo2qCM4Y8nsq1lmMSYhG4EcL6FWbX5h9yuv'
          'ngs4iLEFk6eALoUS4vIWEwcL4txw9LsWH_zKI-hwoReoP77cOdSL4AVcra'
          'Hawlkpyd2TWjE5evgbhWtOxnZee3cXJBkAi64Ik6jZxbvk-RR3pEhnCs',
      'dq': 'o_8V14SezckO6CNLKs_btPdFiO9_kC1DsuUTd2LAfIIVeMZ7jn1Gus_Ff'
          '7B7IVx3p5KuBGOVF8L-qifLb6nQnLysgHDh132NDioZkhH7mI7hPG-PYE_'
          'odApKdnqECHWw0J-F0JWnUd6D2B_1TvF9mXA2Qx-iGYn8OVV1Bsmp6qU',
      'qi': 'eNho5yRBEBxhGBtQRww9QirZsB66TrfFReG_CcteI1aCneT0ELGhYlRlC'
          'tUkTRclIfuEPmNsNDPbLoLqqCVznFbvdB7x-Tl-m0l_eFTj2KiqwGqE9PZ'
          'B9nNTwMVvH3VRRSLWACvPnSiwP8N5Usy-WRXS-V7TbpxIhvepTfE0NNo'
    },
  );
  builder.addRecipient(jwk, algorithm: 'RSA1_5');

  // set the content encryption algorithm to use
  builder.encryptionAlgorithm = 'A128CBC-HS256';

  // build the jws
  var jwe = builder.build();

  // output the compact serialization
  print('jwe compact serialization: ${jwe.toCompactSerialization()}');

  // output the json serialization
  print('jwe json serialization: ${jwe.toJson()}');
}

// decode and verify and validate a JWT
void example5() async {
  var encoded = 'eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.'
      'eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFt'
      'cGxlLmNvbS9pc19yb290Ijp0cnVlfQ.'
      'dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk';

  // decode the jwt, note: this constructor can only be used for JWT inside JWS
  // structures
  var jwt = JsonWebToken.unverified(encoded);

  // output the claims
  print('claims: ${jwt.claims}');

  // create key store to verify the signature
  var keyStore = JsonWebKeyStore()
    ..addKey(JsonWebKey.fromJson({
      'kty': 'oct',
      'k':
      'AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow'
    }));

  var verified = await jwt.verify(keyStore);
  print('verified: $verified');

  // alternatively, create and verify the JsonWebToken together, this is also
  // applicable for JWT inside JWE
  jwt = await JsonWebToken.decodeAndVerify(encoded, keyStore);

  // validate the claims
  var violations = jwt.claims.validate(issuer: Uri.parse('alice'));
  print('violations: $violations');
}

// create a JWT
void example6() async {
  var claims = JsonWebTokenClaims.fromJson({
    'exp': Duration(hours: 4).inSeconds,
    'aud':"live-tv",
    'iat':DateTime.now().toString(),

  });

  // create a builder, decoding the JWT in a JWS, so using a
  // JsonWebSignatureBuilder
  var builder = JsonWebSignatureBuilder();

  // set the content
  builder.jsonContent = claims.toJson();

  // add a key to sign, can only add one for JWT
  builder.addRecipient(
      JsonWebKey.fromJson({
        'kty': 'RSA',
        'kid':pkey,
         }),

      algorithm: 'HS256');

  // build the jws
  var jws = builder.build();

  // output the compact serialization
  print('jwt compact serialization: ${jws.toCompactSerialization()}');
}

// create a JWT, sign with RS512
void example7() async {
  var claims = JsonWebTokenClaims.fromJson({
    'exp': Duration(hours: 4).inSeconds,
    'iss': 'alice',
  });

  // create a builder, decoding the JWT in a JWS, so using a
  // JsonWebSignatureBuilder
  var builder = JsonWebSignatureBuilder();

  // set the content
  builder.jsonContent = claims.toJson();

  // add a key to sign, can only add one for JWT
  var key = JsonWebKey.fromPem(File('example/jwtRS512.key').readAsStringSync());
  builder.addRecipient(key, algorithm: 'RS512');

  // build the jws
  var jws = builder.build();

  // output the compact serialization
  print('jwt compact serialization: ${jws.toCompactSerialization()}');
}

// generate a key for use with ES256 signing
void example8() async {
  var alg = JsonWebAlgorithm.getByName('ES256');

  var key = alg.generateRandomKey();
  print(JsonEncoder.withIndent(' ').convert(key));

  final hash = utf8.encode('TEST');

  var sig = key.sign(hash);
  final valid = key.verify(hash, sig);

  print('valid? $valid');
}

我一次尝试了每个示例来修改其中的每一个。很少有人说“紧凑序列化应该有 3 个部分”,然后我做了一些研究并意识到要生成的令牌应该有 3 个部分。另一个错误在示例 2 是 JSONWebKey 无法签名。

我使用了另一个库,那就是https://pub.dev/packages/corsac_jwt

代码如下:

import 'package:corsac_jwt/corsac_jwt.dart';
//  ..setClaim('13', {'userId': 'xxxx'})

String pkey="sdfdsfdsfds";

void tokenGenerator() {

  var builder = new JWTBuilder();
  var token = builder
    ..audience="live-tv"
    ..issuedAt= new DateTime.now()
    ..expiresAt = new DateTime.now().add(new Duration(minutes: 3))

    ..getToken(); // returns token without signature

 var signer = new JWTRsaSha256Signer(privateKey: pkey);

  var signedToken = builder.getSignedToken(signer);
  print("token");
      print(signedToken); // prints encoded JWT
  var stringToken = signedToken.toString();

  var decodedToken = new JWT.parse(stringToken);
  // Verify signature:
  print(decodedToken.verify(signer)); // true

  // Validate claims:
//  var validator = new JWTValidator() ;// uses DateTime.now() by default
//   // set claims you wish to validate
//  Set<String> errors = validator.validate(decodedToken);
//  print(errors); // (empty list)
}

但是在这里我得到了错误无效的私钥。如果我把它改成公共的,我也得到了无效的公钥。

老实说,我的精神状态非常混乱,实施的时间不多了。我的队友只知道一件事,我只知道颤抖而已。

顺便说一下,我们尝试在 Flutter 中实现的 Java 代码如下所示。基本上它的作用是需要一个 StringKey,转换为 PrivateKey,然后转换为令牌

import android.util.Log;

import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Date;
import java.util.concurrent.TimeUnit;


public class RSAKeyGenerator {
    private static PrivateKey getPrivateKey() throws GeneralSecurityException {
        String pKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
        KeyFactory kf = KeyFactory.getInstance("RSA");
        byte[] decode;
        decode = android.util.Base64.decode(pKey, android.util.Base64.DEFAULT);
        PKCS8EncodedKeySpec keySpecPKCS8 = new PKCS8EncodedKeySpec(decode);
        return kf.generatePrivate(keySpecPKCS8);
    }
    public static String getJwtToken() {
        final long VALIDITY_MS = TimeUnit.MINUTES.toMillis(60);
        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);
        Date exp = new Date(nowMillis + VALIDITY_MS);
        PrivateKey privateKey = null;
        try {
            privateKey = getPrivateKey();
        } catch (GeneralSecurityException e) {
            e.printStackTrace();
        }
        String jws = Jwts.builder()
                .claim("version", "13")
                .claim("user_id", "xxxxxxxxxxxxxxxxxxx")
                .setIssuedAt(now)
                .setExpiration(exp)
                .signWith(privateKey, SignatureAlgorithm.RS256)
                .setAudience("live-tv")
                .compact();
        Log.d("111__", jws);
        SpUtil.Companion.getInstance().putString(J_TOKEN, jws);
        return jws;
    }
}

标签: javaflutterdartjwt

解决方案


经过数小时的研究、试验和错误以及咨询我的队友,我得出了最终结论。这行得通。我犯的错误是 RSA 密钥,我将它作为字符串传递,如 key="xxxxxxxxxxxx",但它应该采用以下格式

希望这可以帮助某人

import 'package:dart_jsonwebtoken/dart_jsonwebtoken.dart';

String token;

String dartJsonWebTokenGenerator() {
  Duration delay = new Duration(minutes: 300);
  final jwt = JWT(
    payload: {
      'version': '13',
      'user_id': 'xxxxxxxxxxxxxxxxx',
    },
    audience: 'live-tv',
  );

// Sign it (default with HS256 algorithm)
  token = jwt.sign(PrivateKey('''-----BEGIN RSA PRIVATE KEY-----
                      xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx7
                      wIxAoKDcHD7mv2R//I0QncGzT1I7cccrhIUB1gXH9wWdTXrafhACXrJ2Drfjg/YN
                      9q4TiKH1k2+zTfdU1IDxd6OX2cPNkwn/vpZeZ1pZqVoimRRJbJg8RhXYvZgd6Nfj
                      Zdw6LY3Zzm3XbLbTUmbVM5ARDweksnr6cg7HmR2OQ5j5UFuhRyIUTSCDbAmDeyHS
                      xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx70YmgZPR
                      PIncbKBjLzQe5RB/szyswCAiLxfk7rCrUhPpvdJ4fnDgdXQE26t/CBFb8fpOHtiL
                      1FtxgURmX/Nh+OhO7pPvK4X7g2GarMdQ3Y6288/STQu/d8yEQDwcro6X9ribay46
                      Ss69AGJxGJbazUI9fNMETLpR6kIHKli7G7gtTFVY02YPKpqgYs1HFbIgV++gHTaw
                      XLU3PqroxKkhTuI8JCei1pphS/PAc3S/o0mPxTYLfiojYG/6IDd8WsGonwwk2hqd
                      e3ad0S56JZNN812vshc8NFMbEU2UzA7L0INf6X+GAhoZojUjZciKwAN/iF9YV0cU
                      XorRDXcXrXn7hpqAzDq/jMQO78jr2MyaY/dfiSVp6sTS8gNMCuz0g3I7gSkCAwEA
                      AQKCAgEAiPWqK/qdrFYR4unJwU9ouonlMWGl0BAndIUEcjIt4cPCVwtfuL+aE98q
                      J8MJYINVTgaJ7VbnKnSkARQkuUYWCLhYF8z9hq+h3Ce2QPJMhwC1GCT3MFGMQQRD
                      wP/U8q99k9xljOAckw6TnxjTFJCoFUQrbA9QcXb9ypSMvvorMDGzR+5X99IMsGFj
                      elwJJS4v7fV3oWZsoMcfAcuFlrAETNPjkaX0CmaIru/CaMupq7YQUa6CmMhwQwUJ
                      p/V+aD9OdndhGmTVtHvDq0bew8wHCLxKdQCOUjzHx9Itli1zUthbaZDKkuoH1cyR
                      JyoVkCJ5FV6y5ShN8KzF7UXzZqaEMrTRNF42O1w933CWj3Pm1+PQdHQJXeMvOtWv
                      QTjd1+OtDckREA5W8oiuPnF+RtTHpzXjPtnLNf5yszq2HOkFplqLmLhkN2GDqQib
                      8DjIo+tyF3yHKuVOya21JC1SYDO412nh3GzbttASBcfeas+6v75gB8Eb4IKRO7mj
                      HaN5BGf/XKORp6v95pTv2OAPqnvIimLOe6TNzlPoVedK90CwPwHEan/ooFZI9b9j
                      UlMLynJHQo6rSvmzoa5d1QuEcAjHVJdjfmvXeQaZs3o1Ajk/HbNBrV3Gr69CcHDO
                      vd960cvRZS/9oNloUdzT/3fOND+6DU/iDrTd1TVWt9nfBb9njv0CggEBAPChGrzL
                      s5xLhoh4Ogr6FQZcCvaURhtRI7jz4WrF8dVVtlwTbZSRn1fSCCwwm3lnGRTMZrzh
                      SYzFgzZ753MQPREm+46Swpe8N6XsMFYubmlhAEK8Z7MgJLwKswadxBsMEj7dqPBu
                      1Fezx9vFZO79MNFAzVBS74mXfLC7NVfIZe+Id53RzoDF5t8rGlo4owxRAySRllJU
                      F2UQrBMRf21aqvvdwJSWiFsCuJ2VJTE/N2iS9A6ISdvYWO+ZJPPqffRmpt6T3tIB
                      uOnf4LG1MSG1UyHpQ15BErwJ6M3CMRzRnjlhtI87xXOXsD39QOTd5QnwXETUYGRi
                      Yvj0JmozTlXCCQMCggEBAOqzcuIdix5kvU871T0m1vpMXYIA5+0NolqW/PNQYzQj
                      f55Kwyzlx6BNBKxCvgCoo9YYKRWKq0wN1H0CUvOFxBwu4h/XJqDtc6yM58UYImTG
                      ZWFVJI4GvB0jdTw3F4LMOnEgl2zMQB17Yf7p2WUIFpUowQC5ZEvFa16cYMKRCoPz
                      4RH1p83eDEok2XQSHlZH1hZHG6YlBlMiBPW0904xICnm8dT73jTijaNKrlV5E9FQ
                      IS0tl3Gc6aVEdd/r89ArHYByjRdLN3IXzy8BOLGFtT8/+PB7egdUPEejTNiIGKWo
                      hvWVp6wEyjdOh+zI1X4L1oVXqxBVajTSFk0qxqW2V2MCggEAJK4KK1lJybthiI/7
                      GQ1CAzQon6m+fg+CSIE0jVgbIw/rumFjxM/l4Dct8759FKZ4lkkKKCSXV5QMClQc
                      xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxW
                      Qq/prxwXr/TUer7SzQXcfcMYdsjwougGeG6yYLZrT/FuOURoHDztEyOqZUeDU2zJ
                      Zdv6UGZfIsdHhcgGaE8B2l3ujkxIU6bGy3JRLETF80B9brHvIeKchpqom037LFuY
                      X7EKORMbp9R3jJ5eFG9TmTcCzXBtW6Aa2yH2RZzDNZ/1d+xhxEQzZVnyCEz/RhUI
                      Dd6EDQKCAQEAmpjDpt/xAH85F9UAvDw2RT9CJN016Dcf524nhppADlsHuBvk/lEJ
                      MrUoy9NW1pY+/UqC3XavKPS/L+z0+QX2zN2xA2o0PrLKjDFwhapFFX59zyRHZOpY
                      xRTTJ2vep8ChCl1+gSL1ZLYeMcyV72/peC0VHMYBo8uR0wtMzTy+4XYmni7jbr7B
                      96DYQBWjOBAvnBMQylr/FImHHNYsRKwlVJSUXUfe8ZT92T7bIOAVRr3ybJDofeTv
                      Hna+8lW5DzknQLGz8FESX6wBRCQY1Q6O+e/IqZecJPG+ly2g88yJ96zP4TrH7I5n
                      KREohbcwsctYbhL2UlcBE3QDTqdLnGJEowKCAQBwlBtw/BD5cefTcUB90XtuUpLG
                      xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
                      moP4L4wBlad2aZYKnkZ87RZIa09wyf5hnPXQkQAHMRYxuaxvQUq/bSDO6JUbrGMp
                      J2LQgCreNAF7MsIDU2ijVHJNWp9m6LC1Osb1iMp/fZDy+hkAAHP5xDfDedwKmXLV
                      2kSdWPZebq1iIRyJ+BlbXAEgDMkp+k6mebq+kyH4+3odWvw8bRkmD/g1t/bS
                      -----END RSA PRIVATE KEY-----'''),
      algorithm: JWTAlgorithm.RS256, expiresIn: delay);
  print('Signed token: $token\n');
  return token;
}

推荐阅读