我正在使用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);
}
}
}
所以我的问题:
需要注意的另一件事是我打算支持刷新令牌,事实上上面的示例是从使用这种机制的示例中提取的刷新令牌 - 除了刷新令牌它们似乎是单用的,所以ReceiveAsync
方法通常会删除ConcurrentDictionary
提供的刷新令牌,我不完全确定我理解为什么?
答案 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,请随时查看并让它我知道你是否需要更多帮助。
祝你好运!