通过提供代理令牌来处理来自 webapi 的长持有者令牌

本文关键字:令牌 webapi 持有者 处理 代理 | 更新日期: 2023-09-27 18:33:37

我正在使用声明身份验证 ASP.NET WebApi 2 构建一个 Web api,我的用户可以拥有非常多的声明。由于有大量的声明,持有者令牌增长得非常快,所以我试图找到一种方法来返回一个更短的持有者令牌。

到目前为止,我发现我可以提供对OAuth选项OAuthAuthorizationServerOptions.AccessTokenProvider属性的IAuthenticationTokenProvider

OAuthOptions = new OAuthAuthorizationServerOptions
{
    TokenEndpointPath = new PathString("/Token"),
    Provider = new ApplicationOAuthProvider(PublicClientId),
    AccessTokenExpireTimeSpan = TimeSpan.FromHours(12),
    AccessTokenProvider = new GuidProvider() // <-- here
};

这使我有机会拦截AuthenticationTicket并将其藏匿起来,将其替换为更简单的东西 - 在我的示例中,下面是一个散列的 guid。(注意:目前,这个类只是对我的会话进行ConcurrentDictionary<string,AuthenticationTicket> - 在实际示例中,我打算将会话存储在一些持久存储中(

public class GuidProvider : IAuthenticationTokenProvider
{
    private static ConcurrentDictionary<string, AuthenticationTicket> tokens 
        = new ConcurrentDictionary<string, AuthenticationTicket>();
    public void Create(AuthenticationTokenCreateContext context)
    {
        throw new NotImplementedException();
    }
    public async System.Threading.Tasks.Task CreateAsync(AuthenticationTokenCreateContext context)
    {
        var guid = Guid.NewGuid().ToString();
        var ticket = Crypto.Hash(guid);
        tokens.TryAdd(ticket, context.Ticket);
        context.SetToken(ticket);
    }
    public void Receive(AuthenticationTokenReceiveContext context)
    {
        throw new NotImplementedException();
    }
    public async System.Threading.Tasks.Task ReceiveAsync(AuthenticationTokenReceiveContext context)
    {
        AuthenticationTicket ticket;
        if (tokens.TryGetValue(context.Token, out ticket))
        {
            if (ticket.Properties.ExpiresUtc.Value < DateTime.UtcNow)
            {
                tokens.TryRemove(context.Token, out ticket);
            }
            context.SetTicket(ticket);
        }
    }
}

所以我的问题:

  • 这是提供代理项密钥来代替我的长声明生成的令牌的适当(且安全!(方法吗?
  • 也许有一个更好/更容易的地方,我应该在webapi/OAuth堆栈中执行此操作?

需要注意的另一件事是,我打算支持刷新令牌,实际上上面的示例是从对刷新令牌使用这种机制的示例中提取的 - 除了使用刷新令牌,它们似乎是一次性的,因此ReceiveAsync方法通常总是会删除从ConcurrentDictionary提供的刷新令牌, 我不完全确定我明白为什么?

通过提供代理令牌来处理来自 webapi 的长持有者令牌

我不建议这样做,因为您最终会将身份验证票证存储到数据库或 Redis 服务器中,这里的缺点是,对于每个包含持有者令牌的请求,您将检查此永久存储以解析 Guid 并再次获取票证来构造它。

我建议您使用 JSON Web 令牌 JWT 而不是默认的持有者访问令牌格式,为此,您需要在属性Provider OAuthAuthorizationServerOptions中实现自定义访问令牌格式CustomOAuthProvider,如下代码:

 OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
        {
            //For Dev enviroment only (on production should be AllowInsecureHttp = false)
            AllowInsecureHttp = true,
            TokenEndpointPath = new PathString("/oauth2/token"),
            AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(30),
            Provider = new CustomOAuthProvider(),
            AccessTokenFormat = new CustomJwtFormat("http://jwtauthzsrv.azurewebsites.net")
        };

我注意到,向 JWT 令牌添加更多声明不会像默认访问令牌格式那样显着增加其大小。

在 2 个 JWT 的样本下方,每个 JWT 内部都有不同的声明,第二个仅比第一个大 50 个字符。我建议您使用 jwt.io 检查每个编码内容第一届智威汤逊:

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1bmlxdWVfbmFtZSI6InRhaXNlZXIiLCJzdWIiOiJ0YWlzZWVyIiwicm9sZSI6WyJNYW5hZ2VyIiwiU3VwZXJ2aXNvciJdLCJpc3MiOiJodHRwOi8vand0YXV0aHpzcnYuYXp1cmV3ZWJzaXRlcy5uZXQiLCJhdWQiOiIwOTkxNTNjMjYyNTE0OWJjOGVjYjNlODVlMDNmMDAyMiIsImV4cCI6MTQxODY0NzMyNywibmJmIjoxNDE4NjQ1NTI3fQ.vH9XPtjtAv2-6SwlyX4fKNJfm5ZTVHd_9a3bRgkA_LI

第二个JWT(更多索赔(:

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1bmlxdWVfbmFtZSI6InRhaXNlZXIiLCJzdWIiOiJ0YWlzZWVyIiwicm9sZSI6WyJNYW5hZ2VyIiwiU3VwZXJ2aXNvciIsIlN1cGVydmlzb3IxIiwiU3VwZXJ2aXNvcjIiLCJTdXBlcnZpc29yMyJdLCJpc3MiOiJodHRwOi8vand0YXV0aHpzcnYuYXp1cmV3ZWJzaXRlcy5uZXQiLCJhdWQiOiIwOTkxNTNjMjYyNTE0OWJjOGVjYjNlODVlMDNmMDAyMiIsImV4cCI6MTQxODY0NzQ1NiwibmJmIjoxNDE4NjQ1NjU2fQ.TFEGDtz1RN8VmCQu7JH4Iug0B8UlWDLVrIlvc-7IK3E

JWT 格式正在成为发行 OAuth 2.0 持有者令牌的标准方式,并且它将与刷新令牌授予一起使用。但请记住,JWT 只是签名令牌,不会像默认访问令牌格式那样加密,因此不要在其中存储机密数据。

我已经写了关于如何在 Web API 中使用 JWT 令牌 ASP.NET bitoftech.net 的详细博客文章,以及 GIthub 上的实时演示 API 和源代码,请随时检查它,如果您需要更多帮助,请告诉我。

祝你好运!