JwtSecurityTokenHandler 线程安全吗

问题描述 投票:0回答:3

我正在使用

JwtSecurityTokenHandler
在 aspnet core web api 应用程序中发行令牌:

JwtSecurityToken token = BuildJwtSecurityToken(...);
public string toks = new JwtSecurityTokenHandler().WriteToken(token);

每次请求和创建令牌时,都会实例化一个新的 JwtSecurityTokenHandler,我可以使用它的全局实例并将其用于每次令牌生成吗?

private JwtSecurityTokenHandler handler = new JwtSecurityTokenHandler();
private GenToken(JwtSecurityToken token) => handler.WriteToken(token);

这样使用有什么问题吗?

c# asp.net-core asp.net-identity jwt
3个回答
6
投票

文档说

JwtSecurityTokenHandler
的实例成员不能保证线程安全。

https://msdn.microsoft.com/en-us/library/system.identitymodel.tokens.jwtsecuritytokenhandler(v=vs.114).aspx


2
投票

我看到的大多数示例,例如 blog.wille-zone.de 上的这个示例,为每个请求单独创建它。

我不会在这方面变得太聪明;即使它当前是线程安全的,这里没有人可以承诺微软保持这种状态。

如果您确实希望他们做出承诺,您可以首先在 https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet 提出问题。他们可以将其写入规范/代码/文档中。


0
投票

看来最重要的两个函数都是线程安全的!

我在高并发系统中也遇到了同样的问题,并分析了它以揭开真相。

我们正在讨论的代码:

using System.IdentityModel.Tokens.Jwt;

namespace SafeTokenHandler;

public static class JwtSecurityTokenHandlerExtensions
{
    private static readonly JwtSecurityTokenHandler JwtSecurityTokenHandlerShared = new();
    
    public static string CompileToString(this JwtSecurityToken token) => JwtSecurityTokenHandlerShared.WriteToken(token);

    public static JwtSecurityToken ToJwtSecurityToken(this string token) => JwtSecurityTokenHandlerShared.ReadJwtToken(token);
}

基准结果

写入令牌


BenchmarkDotNet v0.13.11, macOS Sonoma 14.0 (23A344) [Darwin 23.0.0]
Apple M2 Pro, 1 CPU, 10 logical and 10 physical cores
.NET SDK 8.0.100
  [Host]     : .NET 8.0.0 (8.0.23.53103), Arm64 RyuJIT AdvSIMD
  DefaultJob : .NET 8.0.0 (8.0.23.53103), Arm64 RyuJIT AdvSIMD


方法 意思是 错误 标准偏差 比率 0代 第一代 已分配 分配比例
Jwt实例 1,403.7 纳秒 5.11纳秒 4.27 纳秒 1.00 0.9537 0.0172 7.8 KB 1.00
Jwt静态 479.9 纳秒 1.39 纳秒 1.16纳秒 0.34 0.3195 - 2.62 KB 0.34

读取JwtToken


BenchmarkDotNet v0.13.11, macOS Sonoma 14.0 (23A344) [Darwin 23.0.0]
Apple M2 Pro, 1 CPU, 10 logical and 10 physical cores
.NET SDK 8.0.100
  [Host]     : .NET 8.0.0 (8.0.23.53103), Arm64 RyuJIT AdvSIMD
  DefaultJob : .NET 8.0.0 (8.0.23.53103), Arm64 RyuJIT AdvSIMD


方法 意思是 错误 标准偏差 比率 0代 第一代 已分配 分配比例
Jwt实例 1,806.3 纳秒 7.24 纳秒 6.78 纳秒 1.00 0.8755 0.0095 7.16 KB 1.00
Jwt静态 869.9 纳秒 1.79 纳秒 1.40 纳秒 0.48 0.2403 0.0010 1.97 KB 0.28

WriteToken 方法测试

代码片段:

[Fact]
public void CompileToString_MultiThread()
{
    var expected = new Dictionary<int, string>();

    var upper = Random.Shared.Next(1000, 10000);
    
    for (var i = 0; i < upper; i++)
    {
        var token = new JwtSecurityToken(
            issuer: "me",
            audience: "you",
            new[] { new Claim("sub", i.ToString()) });
        
        expected.Add(i, JwtUtility.CompileToString(token));
    }

    var actual = new ConcurrentDictionary<int, string>();   
    
    Parallel.For(0, upper, i =>
    {
        var token = new JwtSecurityToken(
            issuer: "me",
            audience: "you",
            new[] { new Claim("sub", i.ToString()) });

        var addResult = actual.TryAdd(i, token.CompileToString());
        Assert.True(addResult, $"Failed to add {i} to actual");
        
    });
    
    Assert.Equal(expected, actual);
    
    foreach (var (expectedKey, expectedValue) in expected)
    {
        Assert.Equal(expectedValue, actual[expectedKey]);
    }
}

ReadJwtToken 方法测试

代码片段:

[Fact]
public void ToJwtSecurityToken_MultiThread()
{
    var expected = new Dictionary<int, string>();

    var upper = Random.Shared.Next(1000, 10000);
    
    for (var i = 0; i < upper; i++)
    {
        var token = new JwtSecurityToken(
            issuer: "me",
            audience: "you",
            new[] { new Claim("sub", i.ToString()) });
        
        expected.Add(i, JwtUtility.CompileToString(token));
    }
    
    var actual = new ConcurrentDictionary<int, JwtSecurityToken>();
    
    Parallel.For(0, upper, i =>
    {
        var addResult = actual.TryAdd(i, expected[i].ToJwtSecurityToken());
        Assert.True(addResult, $"Failed to add {i} to actual");
    });
    
    foreach (var (expectedKey, expectedValue) in expected)
    {
        Assert.Equal(expectedValue, actual[expectedKey].CompileToString());
    }
}

结论

进行的基准测试和功能测试表明,

WriteToken
ReadJwtToken
方法是线程安全的。 这些结果对于需要高并发的应用程序至关重要,确保在各种负载条件下获得可靠且一致的性能。

© www.soinside.com 2019 - 2024. All rights reserved.