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

时间:2014-12-08 15:35:16

标签: c# asp.net-web-api oauth bearer-token

我正在使用ASP.NET WebApi 2使用声明身份验证构建Web api,我的用户可以拥有大量的声明。由于大量声明,承载令牌会迅速增长,因此我试图找到一种返回更短的承载令牌的方法。

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

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提供的刷新令牌,我不完全确定我理解为什么?

1 个答案:

答案 0 :(得分:7)

我不建议这样做,因为您最终要将身份验证票证存储到数据库或Redis服务器中,这里的描述是每个包含持票人令牌的请求,您将按顺序检查此永久存储解决Guid并再次获得票证来构建它。

我建议您使用JSON Web令牌 JWT 而不是默认的承载访问权限格式,为此,您需要在属性{{1}中实现自定义访问令牌格式CustomOAuthProvider } Provider中的代码如下:

OAuthAuthorizationServerOptions

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

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

 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(更多声明):

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1bmlxdWVfbmFtZSI6InRhaXNlZXIiLCJzdWIiOiJ0YWlzZWVyIiwicm9sZSI6WyJNYW5hZ2VyIiwiU3VwZXJ2aXNvciJdLCJpc3MiOiJodHRwOi8vand0YXV0aHpzcnYuYXp1cmV3ZWJzaXRlcy5uZXQiLCJhdWQiOiIwOTkxNTNjMjYyNTE0OWJjOGVjYjNlODVlMDNmMDAyMiIsImV4cCI6MTQxODY0NzMyNywibmJmIjoxNDE4NjQ1NTI3fQ.vH9XPtjtAv2-6SwlyX4fKNJfm5ZTVHd_9a3bRgkA_LI

JWT格式正在成为发布OAuth 2.0承载令牌的标准方式,并且它将与刷新令牌授权一起使用。但请记住,JWT只是签名的令牌,而不是默认访问令牌格式的加密,所以不要存储机密数据。

我已经在bitoftech.net上写了detailed blog post关于如何在ASP.NET Web API中使用JWT令牌以及现场演示API和source code on GIthub,请随时查看并让它我知道你是否需要更多帮助。

祝你好运!