为什么在OAuthAuthorizationServerProvider.GrantRefreshToken中添加声明?

时间:2016-05-19 16:19:26

标签: asp.net asp.net-web-api oauth oauth-2.0 asp.net-web-api2

我正在使用承载令牌为OAuth 2配置AspNet.Identity,我已经看到了实现OAuthAuthorizationServerProvider.GrantRefreshToken方法的多个示例,其中作者演示了向new ClaimsIdentity添加声明的能力如下所示。

我试图在我的单服务器(即我的Web API项目同时是授权+资源服务器)的上下文中理解这一点,如果需要,我可以在以后将其拆分为单独的服务器。

public override Task GrantRefreshToken(OAuthGrantRefreshTokenContext context)
{
    var originalClient = context.Ticket.Properties.Dictionary["as:client_id"];
    var currentClient = context.ClientId;

    if (originalClient != currentClient)
    {
        context.SetError("invalid_clientId", "Refresh token is issued to a different clientId.");
        return Task.FromResult<object>(null);
    }

    // Change auth ticket for refresh token requests
    var newIdentity = new ClaimsIdentity(context.Ticket.Identity);

    // CONSIDER: I don't know why you would add a claim here, but here's an example.
    //var newClaim = newIdentity.Claims.Where(c => c.Type == "newClaim").FirstOrDefault();
    //if (newClaim != null)
    //{
    //    newIdentity.RemoveClaim(newClaim);
    //}
    //newIdentity.AddClaim(new Claim("newClaim", "newValue"));

    var newTicket = new AuthenticationTicket(newIdentity, context.Ticket.Properties);
    context.Validated(newTicket);

    return Task.FromResult<object>(null);
}

The documentation州:

“应用程序必须调用context.Validated指示Authorization Server中间件根据这些声明和属性发出访问令牌。”

我不明白这一点。我以为我们正在分发刷新令牌,而不是访问令牌。

此外,“对context.Validated的调用可能会被赋予不同的AuthenticationTicket或ClaimsIdentity,以便控制哪些信息从刷新令牌流向访问令牌。”

我认为所有声明都存储在我的签名和加密访问令牌中,该令牌传递为Authorization: Bearer XXXXXX。但是,我对ClaimsIdentityAuthenticationTicket与OAuth 2.0流程中的任何内容实际相关的方式都有一个微妙的把握。

我最好的猜测是GrantRefreshToken需要获取已经过身份验证和授权的身份(context.Ticket.Identity),并通过调用context.Validated验证是否应该向其添加刷新令牌。

1 个答案:

答案 0 :(得分:5)

OAuth2中的刷新标记只是另一种类型的授权:获取新access_token的另一种方法。

因此,必须验证RefreshToken才能为用户发出新的access_token

当将刷新令牌持久化到底层存储(例如数据库)时,必须将整个用户身份与其一起存储(通常使用SerializeTicket()对象的AuthenticationTokenCreateContext方法)。这意味着在第一代access_token生成期间获得的声明中的任何更改都不会在默认情况下使用access_token授权传播到其他RefreshToken排放(您需要再次重新加载这些声明如果您需要在access_token)中更新它们。

我认为这是许多示例显示如何在GrantRefreshToken方法中的新标识中添加/替换声明的主要原因。

我将尝试进一步澄清支持RefreshTokenGrant时通常会发生的事情:

  1. 用户使用任何类型的支持授权(例如ResourceOwnerCredentials);
  2. 对自己进行身份验证
  3. 我们创建一个与此特定用户绑定的标识(我们可以在此处添加声明)并使用它创建新的AuthenticationTicket(我们通过在特定{{1上调用Validated(ticket)来验证对象)将用于创建context;
  4. 框架会在提供的access_token上生成一个名为CreateAsync的新刷新令牌。在此方法中,我们必须检索故障单并将其存储到某种持久性存储(例如数据库)以及唯一的IAuthenticationTokenProvider和一些有用的元数据中。这个Id是用户观点的Id
  5. 我们向用户返回refresh_token(其中包含用户的序列化声明)和access_token(仅作为参考)。
  6. 一段时间后,用户必须再次进行身份验证(例如refresh_token已过期),因此他将使用access_token向令牌端点发送请求。
  7. 我们从持久存储中检索refresh_token记录,并反序列化将用于创建新标识的故障单。此票证包含我们在第一次身份验证时添加的所有声明(这几乎是第一次refresh_token的精确副本):如果在当前时刻和第一次身份验证之间的间隔期间任何声明发生了更改(例如,新的角色已添加到用户,电子邮件已更改等。)我们现在有机会修改新身份并添加/替换这些声明,以便新access_token将反映更改。
  8. 流程会继续验证故障单(如前所述)并生成一对access_tokenaccess_token以发送给用户。