我使用Visual Studio 2013附带的Web Api 2模板有一些OWIN中间件来进行用户身份验证等.
在OAuthAuthorizationServerOptions
我注意到,OAuth2服务器设置为分发在14天后到期的令牌
OAuthOptions = new OAuthAuthorizationServerOptions { TokenEndpointPath = new PathString("/api/token"), Provider = new ApplicationOAuthProvider(PublicClientId,UserManagerFactory) , AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"), AccessTokenExpireTimeSpan = TimeSpan.FromDays(14), AllowInsecureHttp = true };
这不适合我的最新项目.我想分发可以使用a刷新的短暂bearer_tokensrefresh_token
我做了很多谷歌搜索,找不到任何有用的东西.
所以这就是我设法得到的.我现在已经达到了"WTF do I now"的地步.
我写了一个根据类的属性RefreshTokenProvider
实现:IAuthenticationTokenProvider
RefreshTokenProvider
OAuthAuthorizationServerOptions
public class SimpleRefreshTokenProvider : IAuthenticationTokenProvider { private static ConcurrentDictionary_refreshTokens = new ConcurrentDictionary (); public async Task CreateAsync(AuthenticationTokenCreateContext context) { var guid = Guid.NewGuid().ToString(); _refreshTokens.TryAdd(guid, context.Ticket); // hash?? context.SetToken(guid); } public async Task ReceiveAsync(AuthenticationTokenReceiveContext context) { AuthenticationTicket ticket; if (_refreshTokens.TryRemove(context.Token, out ticket)) { context.SetTicket(ticket); } } public void Create(AuthenticationTokenCreateContext context) { throw new NotImplementedException(); } public void Receive(AuthenticationTokenReceiveContext context) { throw new NotImplementedException(); } } // Now in my Startup.Auth.cs OAuthOptions = new OAuthAuthorizationServerOptions { TokenEndpointPath = new PathString("/api/token"), Provider = new ApplicationOAuthProvider(PublicClientId,UserManagerFactory) , AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"), AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(2), AllowInsecureHttp = true, RefreshTokenProvider = new RefreshTokenProvider() // This is my test };
所以现在当有人要求bearer_token
我现在发送一个refresh_token
,这很好.
那么现在我如何使用这个refresh_token来获取一个新的bearer_token
,大概是我需要向我的令牌端点发送请求并设置一些特定的HTTP头?
我输入时只是大声思考......我应该处理我的refresh_token到期SimpleRefreshTokenProvider
吗?客户如何获得新的refresh_token
?
我真的可以使用一些阅读材料/文档,因为我不想弄错,并希望遵循某种标准.
您需要实现RefreshTokenProvider.首先为RefreshTokenProvider创建类,即.
public class ApplicationRefreshTokenProvider : AuthenticationTokenProvider { public override void Create(AuthenticationTokenCreateContext context) { // Expiration time in seconds int expire = 5*60; context.Ticket.Properties.ExpiresUtc = new DateTimeOffset(DateTime.Now.AddSeconds(expire)); context.SetToken(context.SerializeTicket()); } public override void Receive(AuthenticationTokenReceiveContext context) { context.DeserializeTicket(context.Token); } }
然后将实例添加到OAuthOptions.
OAuthOptions = new OAuthAuthorizationServerOptions { TokenEndpointPath = new PathString("/authenticate"), Provider = new ApplicationOAuthProvider(), AccessTokenExpireTimeSpan = TimeSpan.FromSeconds(expire), RefreshTokenProvider = new ApplicationRefreshTokenProvider() };
我不认为你应该使用数组来维护令牌.你也不需要guid作为代币.
您可以轻松使用context.SerializeTicket().
请参阅下面的代码.
public class RefreshTokenProvider : IAuthenticationTokenProvider { public async Task CreateAsync(AuthenticationTokenCreateContext context) { Create(context); } public async Task ReceiveAsync(AuthenticationTokenReceiveContext context) { Receive(context); } public void Create(AuthenticationTokenCreateContext context) { object inputs; context.OwinContext.Environment.TryGetValue("Microsoft.Owin.Form#collection", out inputs); var grantType = ((FormCollection)inputs)?.GetValues("grant_type"); var grant = grantType.FirstOrDefault(); if (grant == null || grant.Equals("refresh_token")) return; context.Ticket.Properties.ExpiresUtc = DateTime.UtcNow.AddDays(Constants.RefreshTokenExpiryInDays); context.SetToken(context.SerializeTicket()); } public void Receive(AuthenticationTokenReceiveContext context) { context.DeserializeTicket(context.Token); if (context.Ticket == null) { context.Response.StatusCode = 400; context.Response.ContentType = "application/json"; context.Response.ReasonPhrase = "invalid token"; return; } if (context.Ticket.Properties.ExpiresUtc <= DateTime.UtcNow) { context.Response.StatusCode = 401; context.Response.ContentType = "application/json"; context.Response.ReasonPhrase = "unauthorized"; return; } context.Ticket.Properties.ExpiresUtc = DateTime.UtcNow.AddDays(Constants.RefreshTokenExpiryInDays); context.SetTicket(context.Ticket); } }
刚刚使用Bearer实现了我的OWIN服务(在下面称为access_token)和Refresh Tokens.我对此的见解是您可以使用不同的流程.因此,它取决于您要使用的流程如何设置access_token和refresh_token到期时间.
我将在后面描述两个流程 A和B(我建议你想要的是流程B):
A) access_token和refresh_token的到期时间与默认的1200秒或20分钟相同.此流程需要您的客户端首先发送带有登录数据的client_id和client_secret以获取access_token,refresh_token和expiration_time.使用refresh_token,现在可以获得新的access_token 20分钟(或者在OAuthAuthorizationServerOptions中设置AccessTokenExpireTimeSpan的任何内容).由于access_token和refresh_token的到期时间相同,您的客户端有责任在到期时间之前获取新的access_token!例如,您的客户端可以使用正文向您的令牌端点发送刷新POST调用(注释:您应该在生产中使用https)
grant_type=refresh_token&client_id=xxxxxx&refresh_token=xxxxxxxx-xxxx-xxxx-xxxx-xxxxx
在例如19分钟之后获得新令牌以防止令牌到期.
B)在此流程中,您希望access_token的短期到期以及refresh_token的长期到期.让我们假设出于测试目的,您将access_token设置为10秒(AccessTokenExpireTimeSpan = TimeSpan.FromSeconds(10)
)过期,并将refresh_token设置为5分钟.现在谈到设置refresh_token的到期时间的有趣部分:你在SimpleRefreshTokenProvider类的createAsync函数中这样做:
var guid = Guid.NewGuid().ToString(); //copy properties and set the desired lifetime of refresh token var refreshTokenProperties = new AuthenticationProperties(context.Ticket.Properties.Dictionary) { IssuedUtc = context.Ticket.Properties.IssuedUtc, ExpiresUtc = DateTime.UtcNow.AddMinutes(5) //SET DATETIME to 5 Minutes //ExpiresUtc = DateTime.UtcNow.AddMonths(3) }; /*CREATE A NEW TICKET WITH EXPIRATION TIME OF 5 MINUTES *INCLUDING THE VALUES OF THE CONTEXT TICKET: SO ALL WE *DO HERE IS TO ADD THE PROPERTIES IssuedUtc and *ExpiredUtc to the TICKET*/ var refreshTokenTicket = new AuthenticationTicket(context.Ticket.Identity, refreshTokenProperties); //saving the new refreshTokenTicket to a local var of Type ConcurrentDictionary<string,AuthenticationTicket> // consider storing only the hash of the handle RefreshTokens.TryAdd(guid, refreshTokenTicket); context.SetToken(guid);
现在,您的客户端能够在access_token
过期时向您的令牌端点发送带有refresh_token的POST调用.呼叫的正文部分可能如下所示:grant_type=refresh_token&client_id=xxxxxx&refresh_token=xxxxxxxx-xxxx-xxxx-xxxx-xx
一个重要的事情是,您可能不仅要在CreateAsync函数中使用此代码,还要在Create函数中使用此代码.因此,您应该考虑使用您自己的函数(例如,名为CreateTokenInternal)来实现上述代码. 在这里,您可以找到不同流的实现,包括refresh_token流(但不设置refresh_token的到期时间)
以下是github上IAuthenticationTokenProvider的一个示例实现(设置了refresh_token的到期时间)
很抱歉,我无法提供比OAuth规范和Microsoft API文档更多的材料.我会在这里发布链接,但我的声誉不允许我发布超过2个链接....
我希望这可以帮助其他人在尝试使用与access_token到期时间不同的refresh_token到期时间来实现OAuth2.0时节省时间.我在网上找不到一个示例实现(除了上面链接的一个thinktecture),它花了我几个小时的调查,直到它对我有用.
新信息:在我的情况下,我有两种不同的可能性来接收令牌.一种是接收有效的access_token.在那里,我必须发送一个带有String主体的POST调用,格式为application/x-www-form-urlencoded,其中包含以下数据
client_id=YOURCLIENTID&grant_type=password&username=YOURUSERNAME&password=YOURPASSWORD
第二,如果access_token不再有效,我们可以通过发送application/x-www-form-urlencoded
带有以下数据格式的String主体的POST调用来尝试refresh_tokengrant_type=refresh_token&client_id=YOURCLIENTID&refresh_token=YOURREFRESHTOKENGUID