我正在使用声明身份验证使用 ASP.NET WebApi 2 构建 Web api,我的用户可以拥有大量声明。随着大量索赔,不记名令牌会迅速增长,因此我试图找到一种返回更短的不记名令牌的方法。
到目前为止,我发现我可以为IAuthenticationTokenProvider
OAuth 选项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
,我不完全确定我理解为什么?