【问题标题】:How to update Owin access tokens with refresh tokens without creating new refresh token?如何在不创建新的刷新令牌的情况下使用刷新令牌更新 Owin 访问令牌?
【发布时间】:2016-06-15 02:42:07
【问题描述】:

我已经设法获得了一个简单的示例代码,它可以创建一个不记名令牌,还可以通过阅读 stackoverflow 上的其他论坛来通过刷新令牌请求新的令牌。

启动类是这样的

public class Startup
{
    public static void Configuration(IAppBuilder app)
    {
        app.UseOAuthBearerAuthentication(
                      new OAuthBearerAuthenticationOptions());

        app.UseOAuthAuthorizationServer(
                      new OAuthAuthorizationServerOptions
                      {
                          TokenEndpointPath = new PathString("/Token"),
                          Provider = new OAuthAuthorizationServerProvider()
                          {
                              OnValidateClientAuthentication = async c =>
                              {
                                  c.Validated();
                              },
                              OnGrantResourceOwnerCredentials = async c =>
                              {
                                  if (c.UserName == "alice" && c.Password == "supersecret")
                                  {
                                      Claim claim1 = new Claim(ClaimTypes.Name, c.UserName);
                                      Claim[] claims = new Claim[] { claim1 };
                                      ClaimsIdentity claimsIdentity =
                                          new ClaimsIdentity(
                                             claims, OAuthDefaults.AuthenticationType);
                                      c.Validated(claimsIdentity);
                                  }
                              }
                          },
                          AccessTokenExpireTimeSpan = TimeSpan.FromSeconds(40),
                          AllowInsecureHttp = true,
                          RefreshTokenProvider = new ApplicationRefreshTokenProvider()
                      });
    }
}

我还有一个刷新令牌的类,如下所示:

public class ApplicationRefreshTokenProvider : AuthenticationTokenProvider
{
    public override void Create(AuthenticationTokenCreateContext context)
    {
        // Expiration time in seconds
        int expire = 2 * 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);
    }
}

我的理解是通过提供一个刷新令牌,你应该得到一个新的访问令牌。然而,这段代码中发生的事情是,当我提供 refresh token 时,也会创建并返回一个新的 refresh token。我希望它在第一次提供用户名/密码时同时创建 accessrefresh token,但创建新的 refresh tokens 每次使用 刷新令牌 请求新的访问令牌

例如,如果我给定我的代码,访问令牌有 20 分钟的时间跨度,刷新令牌有两周的时间,新的 访问令牌 可以每 20 分钟创建一次,这很好,但是新的 刷新令牌 也将每 20 分钟创建一次,但持续两周。然后会创建很多刷新令牌,但不会使用。

问题:

我几个小时前才开始阅读/了解这个,所以我很不确定,但这是正确的行为还是我应该以某种方式更改我的代码以仅创建和返回一个新的 访问令牌 当一个 refresh token 被提供并且不创建和返回一个新的 refresh token 时?非常感谢任何帮助或输入,谢谢!

【问题讨论】:

  • 刷新令牌替换您的凭据,因此基本上第一次使用您的凭据进行身份验证,然后每次需要再次进行身份验证时使用刷新令牌。作为身份验证的结果,您将获得一个包含身份和声明的身份验证令牌。希望这能澄清这个概念。

标签: c# asp.net-web-api token owin


【解决方案1】:

由于没有人回答,我将提供我所做的以及正在做我正在寻找的东西。因此,我现在要接受这个答案。

public class Startup
{
public static void Configuration(IAppBuilder app)
{
    app.UseOAuthBearerAuthentication(
                  new OAuthBearerAuthenticationOptions());

    app.UseOAuthAuthorizationServer(
                  new OAuthAuthorizationServerOptions
                  {
                      TokenEndpointPath = new PathString("/Token"),
                      Provider = new OAuthAuthorizationServerProvider()
                      {
                          OnValidateClientAuthentication = async c =>
                          {
                              c.Validated();
                          },
                          OnGrantResourceOwnerCredentials = async c =>
                          {
                           //Add a string with the current date
                            string dateNow = DateTime.UtcNow.ToString();

                              if (c.UserName == "alice" && c.Password == "supersecret")
                              {
                                  Claim claim1 = new Claim(ClaimTypes.Name, c.UserName);
                                  Claim[] claims = new Claim[] { claim1 };
                                  ClaimsIdentity claimsIdentity =
                                      new ClaimsIdentity(
                                         claims, OAuthDefaults.AuthenticationType);

                                  //Add a claim with the creationdate of the token
                                  claimsIdentity.AddClaim(new Claim("creationDate", dateNow));

                                  c.Validated(claimsIdentity);
                              }
                          }
                      },
                      AccessTokenExpireTimeSpan = TimeSpan.FromSeconds(40),
                      AllowInsecureHttp = true,
                      RefreshTokenProvider = new ApplicationRefreshTokenProvider()
                  });
}
}

在 ApplicationRefreshTokenProvider 中我做了这些更改

public class ApplicationRefreshTokenProvider : AuthenticationTokenProvider
{
    public override void Create(AuthenticationTokenCreateContext context)
    {
    //Get the claim which holds creation date
     DateTime creationDate = Convert.ToDateTime(clientid.Claims.Where(c => c.Type == "creationDate").Single().Value);
     //Create a variable holding current time minus 30 seconds(This is how long time you can create new refresh tokens by providing your original refresh token)
     DateTime now = DateTime.UtcNow.AddSeconds(-30);


    //If the time has passed more than 30 seconds from the time you got your original access and refresh token by providing credentials
    //you may not create and return new refresh tokens(Obviously the 30  seconds could be changed to something less or more aswell)
    if(now < ceationDate)
    {
    // Expiration time in seconds
    int expire = 2 * 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);
    }
}

【讨论】:

  • 你给自己开了一罐虫子。您现在基本上可以说您没有任何形式的保护,即使是暂时的针对中间人的攻击,这就是刷新令牌的用途。一个更好的方法是将您的令牌设置为 10 分钟,并将令牌访问时间设置为一两个小时,具体取决于您希望留给客户的闲置时间。刷新令牌会生成一个新的刷新令牌,因此拦截您的请求的任何人都无法在您没有注意到的情况下获得新的访问令牌。现在您的代码将假定您的令牌已过期并忽略刷新。
  • @MarinoŠimić - 我认为你的代币生命周期是错误的。访问令牌应该是短暂的(几秒钟到几分钟),而刷新令牌应该是长期存在的(1 小时 - 1 年,具体取决于要求)。这减少了中间人攻击的攻击面,因为他们拦截的任何令牌在短时间内都是有用的。因为刷新令牌用于获取新的访问令牌,所以如果用户认为刷新令牌已被泄露,他们可以注销导致刷新令牌失效。应小心处理刷新令牌的存储。
猜你喜欢
  • 2020-07-12
  • 2014-09-13
  • 2022-01-21
  • 2019-06-29
  • 2018-10-14
  • 2016-08-13
  • 2020-02-27
  • 2022-10-31
  • 2022-12-23
相关资源
最近更新 更多