You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于adaviddesmet/paseto-dotnet NuGet包创建一致的PasetoSymmetricKey

解决PASETO跨实例令牌解码失败的问题

问题根源

你的代码中调用GenerateSymmetricKey()方法会生成随机的对称密钥,两个独立运行的实例会各自生成完全不同的密钥。PASETO Local模式要求令牌生成和解码必须使用完全一致的密钥,这就是解码时提示"Invalid Token"的核心原因。

另外你的解码逻辑同时调用了WithSharedKey和WithKey,这会导致密钥冲突,进一步加剧验证失败的问题。

解决方案

直接使用固定的共享密钥创建PasetoSymmetricKey实例,确保两个实例使用完全相同的密钥。同时注意PASETO v4 Local模式要求密钥长度为32字节(256位),如果你的原始密钥不足32字节,需要用密钥派生函数(如HKDF)生成符合要求的密钥,避免弱密钥风险。

修改后的代码

TokenUtils类

using System.Text;
using System.Text.Json;
using FluentResults;
using Paseto;
using Paseto.Builder;
using Paseto.Cryptography.Key;
using Paseto.Protocol;
using System.Security.Cryptography;

public static class TokenUtils
{
    // 直接使用固定共享密钥创建PasetoSymmetricKey,确保跨实例一致
    private static readonly PasetoSymmetricKey _pasetoSymmetricKey = CreateSymmetricKey();

    private static PasetoSymmetricKey CreateSymmetricKey()
    {
        var rawSecret = "DummySecret";
        var secretBytes = Encoding.UTF8.GetBytes(rawSecret);
        
        // 如果原始密钥不足32字节,用HKDF派生32字节的合规密钥
        if (secretBytes.Length != 32)
        {
            using var hkdf = new Hkdf(HashAlgorithmName.SHA256);
            secretBytes = hkdf.DeriveKey(secretBytes, null, "PASETO v4 Local", 32);
        }
        
        return new PasetoSymmetricKey(V4.Local, secretBytes);
    }

    public static string GenerateLocalToken(TokenPayload tokenPayload)
    {
        return new PasetoBuilder()
            .UseV4(Purpose.Local)
            .WithKey(_pasetoSymmetricKey)
            .AddClaim("UserId", tokenPayload.UserId) // 修正原代码笔误:将AppId改为UserId
            .IssuedAt(DateTime.UtcNow)
            .Expiration(tokenPayload.ExpiresAt)
            .Encode();
    }

    public static Result<TokenPayload> DecodeLocalToken(string token)
    {
        try
        {
            var decodedResult = new PasetoBuilder()
                .UseV4(Purpose.Local)
                .WithKey(_pasetoSymmetricKey) // 只使用统一的密钥实例
                .Decode(token);
                
            if (decodedResult is null) 
                return Result.Fail("Failed to Decode Token");
                
            if (!decodedResult.IsValid) 
                return Result.Fail("Invalid Token");
                
            var tokenPayload = JsonSerializer.Deserialize<TokenPayload>(decodedResult.Paseto.RawPayload);
            if (tokenPayload is null) 
                return Result.Fail("Failed to Deserialize TokenPayload");
                
            // 填充自动生成的iat和exp声明
            tokenPayload.IssuedAt = decodedResult.Paseto.GetClaim<DateTime>("iat");
            tokenPayload.ExpiresAt = decodedResult.Paseto.GetClaim<DateTime>("exp");
                
            return Result.Ok(tokenPayload);
        }
        catch (Exception exception)
        {
            return Result.Fail(exception.Message);
        }
    }
}

TokenPayload类

using System.Text.Json.Serialization;

public class TokenPayload
{
    public string UserId { get; set; } = default!;
    [JsonPropertyName("iat")]
    public DateTime IssuedAt { get; set; } = default!;
    [JsonPropertyName("exp")]
    public DateTime ExpiresAt { get; set; } = default!;
}

额外注意事项

  • 生产环境绝对不要硬编码密钥,应该从环境变量、配置中心或安全密钥管理服务中读取。
  • 确保所有实例使用完全相同的密钥和密钥派生参数(如果使用HKDF),否则仍会出现验证失败。

内容的提问来源于stack exchange,提问作者meightythree

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 23:13:32