一尘不染

OWIN安全性-如何实现OAuth2刷新令牌

c#

我正在使用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
 };

这不适合我的最新项目。我想分发短暂的bearer_tokens,可以使用refresh_token

我已经进行了大量谷歌搜索,找不到任何有用的信息。

这就是我设法取得的成就。我现在已经达到“现在就做WTF”这一点。

我写了一个RefreshTokenProvider实现类IAuthenticationTokenProviderRefreshTokenProvider属性OAuthAuthorizationServerOptions

    public class SimpleRefreshTokenProvider : IAuthenticationTokenProvider
    {
       private static ConcurrentDictionary<string, AuthenticationTicket> _refreshTokens = new ConcurrentDictionary<string, AuthenticationTicket>();

        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

我真的可以使用一些阅读材料/文档,因为我不想弄错这一点,而是想遵循某种标准。


阅读 593

收藏
2020-05-19

共1个答案

一尘不染

刚刚使用Bearer(以下称为access_token)和Refresh
Tokens实现了我的OWIN服务。我对此的见解是,您可以使用不同的流程。因此,这取决于您要使用的流程来设置access_token和refresh_token到期时间。

我将在下面描述两个 流程 AB (我建议您要拥有的是流程B):

A)
access_token和refresh_token的到期时间与默认情况下的1200秒或20分钟相同。此流程需要您的客户端首先发送带有登录数据的client_id和client_secret以获得access_token,refresh_token和expiration_time。借助refresh_token,现在可以在20分钟内获取一个新的access_token(或在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个链接…。

我希望这可以帮助其他人在尝试实现OAuth2.0时的空闲时间,而OAuth2.0的refresh_token过期时间与access_token过期时间不同。我无法在网络上找到示例实现(除了上面链接的thinktecture之一),这花了我几个小时的研究才对我有用。

新信息:就我而言,我有两种不同的接收令牌的可能性。一种是接收有效的access_token。在这里,我必须发送一个带有String主体的POST调用,格式为application
/ x-www-form-urlencode,并带有以下数据

client_id=YOURCLIENTID&grant_type=password&username=YOURUSERNAME&password=YOURPASSWORD

其次是如果access_token不再有效,我们可以尝试通过发送POST调用来尝试refresh_token,该调用的字符串格式application/x-www- form- urlencoded为以下数据grant_type=refresh_token&client_id=YOURCLIENTID&refresh_token=YOURREFRESHTOKENGUID

2020-05-19