通过提供代理令牌处理来自 webapi 的长不记名令牌
Posted
技术标签:
【中文标题】通过提供代理令牌处理来自 webapi 的长不记名令牌【英文标题】:Dealing with long bearer tokens from webapi by providing a surrogate token 【发布时间】:2015-02-06 07:22:14 【问题描述】:我正在使用声明身份验证使用 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
提供的刷新令牌,我不完全确定我理解为什么?
【问题讨论】:
因为授权可以与客户端应用程序隔离,您无法从代理令牌推断出声明。 @jamiec 我使用 JWT 的回答是否帮助您缩短了充满声明的访问令牌? @TaiseerJoudeh - 有也没有。虽然它没有直接回答我的问题,但它给了我一个新的探索途径,我几乎没有遇到过。感谢您的回答,我希望此时可以接受一半的赏金。我可能会考虑在新的一年里对这个问题进行奖励。 【参考方案1】:我不建议这样做,因为您最终会将身份验证票证存储到数据库或 Redis 服务器中,这里的缺点是,对于每个包含不记名令牌的请求,您将按顺序检查此永久存储解决 Guid 并再次获取票证以构建它。
我建议您使用 JSON Web Token JWT 而不是默认的不记名访问令牌格式,为此您需要在 @987654326 中的属性 Provider
中实现自定义访问令牌格式 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 只是签名令牌,并没有像默认访问令牌格式那样加密,所以不要在其中存储机密数据。
我已经在 bitoftech.net 上写了 detailed blog post 关于如何在 ASP.NET Web API 中使用 JWT 令牌以及现场演示 API 和 source code on GIthub,如果您需要更多信息,请随时查看并告诉我帮助。
祝你好运!
【讨论】:
您提到 JWT 使用 refresh_tokens。你能详细说明吗?现在,我有一个实现,它将给我一个 JWT 作为我的 access_token,并且在同一个响应中,它包含一个小得多的令牌(一个 guid),即我的 refresh_token。这是正确的过程还是 refresh_token 也应该是寿命更长的 JWT? 不,刷新令牌只是存储在数据库中的受保护票证的标识符,您使用 grant_type=refresh_token 表示此标识符,如果它有效(未从数据库中删除且未过期),您将收到新的 JWT 访问令牌,希望清楚。 这是有道理的。谢谢。以上是关于通过提供代理令牌处理来自 webapi 的长不记名令牌的主要内容,如果未能解决你的问题,请参考以下文章
用于多个 WebApi 端点的 Azure AD 不记名令牌?
使用 OAuth 令牌生成 WebApi 将更多数据返回给带有不记名令牌的客户端