【问题标题】:How to expire/update ClaimsIdentity Claims stored in a Web API SessionToken如何过期/更新存储在 Web API SessionToken 中的 ClaimsIdentity 声明
【发布时间】:2025-11-23 19:25:01
【问题描述】:

我正在使用出色的 Thinktecture.IdentityModel 库在 ASP.NET Web API 项目中执行身份验证/授权,该项目将从移动设备和可能的 Web 客户端使用。我正在使用基本身份验证来验证移动客户端以访问 Web api,并利用 Thinktecture.IdentityModel 呈现的内置 SessionToken 生成。但是,我对如何撤销添加到 ClaimsIdentity 声明集合中的声明有些担心,然后(我认为)将其编码到提供给客户端的 SessionToken 中......

这是我目前所拥有的:

按照 IdentityModel 示例项目中的示例,我创建了以下类

public static class  SecurityConfig
{
  public static void ConfigureGlobal(HttpConfiguration globalConfig)
  {
      globalConfig.MessageHandlers.Add(new AuthenticationHandler(CreateConfiguration()));
  }

  public static AuthenticationConfiguration CreateConfiguration()
  {
      var authentication = new AuthenticationConfiguration()
          {
              ClaimsAuthenticationManager = new MyClaimsTransformer(),
              RequireSsl = false, //TODO:TESTING only
              EnableSessionToken = true,
              SessionToken = new SessionTokenConfiguration()
              {
                  EndpointAddress = "/Authenticate"
              }
          };
       authentication.AddBasicAuthentication(Membership.ValidateUser);

      return authentication;
   }
}

像这样从我的 Global.asax 类中调用它

SecurityConfig.ConfigureGlobal(GlobalConfiguration.Configuration);

移动设备从个人那里收集用户名和密码,并正确设置身份验证标头并将凭据提供给必要的 Web 端点http://myhost/api/Authenticate

在服务器上,我的 Membership.ValidatUser 使用用户名/密码调用,如果验证通过,则调用 MyClaimsTransformer 的 Authenticate 方法。

public class ClaimsTransformer : ClaimsAuthenticationManager
{
   public override ClaimsPrincipal Authenticate(string resourceName, ClaimsPrincipal incomingPrincipal)
   {
     if (!incomingPrincipal.Identity.IsAuthenticated)
     {
        return base.Authenticate(resourceName, incomingPrincipal);
     }
     return incomingPrincipal;
   }
}

然后,移动客户端会收到一个令牌,它可以在任何后续请求的身份验证标头中传递该令牌。

这一切都很好。

现在我想做的是,在 ClaimsTransformer 中,添加一些类似以下伪代码的代码。

var nameClaim = incomingPrincipal.Claims.First(c => c.Type == ClaimTypes.Name);

//Using value in nameClaim lookup roles or permissions for this user.
var someListofRoles = SomeMethodToGetRoles(nameClaim.Value);

//Add user roles to the Claims collection of the ClaimsPrincipal.
foreach(var role in someListOfRoles)
{
   incomingPrincipal.Identities.First().AddClaim(new Claim("Role", role.Name));
}

我希望限制我需要从数据库请求给定用户的角色或权限列表的次数,并方便在自定义 AuthorizeAttribute 中检查这些角色/权限。

但是,当我开始添加此内容时,我开始考虑用户可能已登录并收到此令牌的情况,但通过系统的其他用户的某些操作,他们的角色可能会更改或撤销.初始用户仍将拥有此令牌,其中包含现已过期的角色/权限列表,并且在令牌过期之前可以访问任何内容,或者将获得对某些内容的新访问权限,但在他们以某种方式注销之前实际上不会收到该访问权限。

是否有使以这种方式创建的 SessionToken 无效的机制?或者,如果我找到某种方式知道用户角色/权限已发生更改,我将如何修改声明并以无缝方式重新颁发 SessionToken?

另外,如何完全撤销 SessionToken,即如果我想“注销”用户,那将如何工作?

【问题讨论】:

    标签: c# asp.net-web-api claims-based-identity thinktecture-ident-model


    【解决方案1】:

    会话令牌工具没有该功能。我们希望保持简单,以解决“在每次应用程序启动时输入密码”问题。如果没有完整的数据存储后端(可以在网络农场等中使用),撤销是很难实现的。

    您不应将可能随会话时间更改的数据存储在会话令牌中。

    【讨论】:

      【解决方案2】:

      数据库更改通知设计完全取决于您。 我的建议就像使用时间戳/行版本来检查数据(用户/角色)是否过时。 您可以将此数据时间戳/行版本存储在服务器上,例如用户会话或客户端的 cookie/标头。我推荐前一种方法。

      如果已过时,我建议您可以重新执行您的 CreateConfiguration() 方法,该方法应重新创建反映与令牌相关的最新数据更改的所有必要信息。

      【讨论】:

      • 感谢您的回复。我绝对可以通过数据库查找来检测角色或权限是否已为特定用户更新/删除/添加,我们已经为这些对象添加时间戳。重新执行 CreateConfiguration 的建议似乎不正确。据我了解,这是一个一次性的“设置”过程,将 thinktecture 对象连接到我的本地声明转换器和成员身份验证方法。如果我要重新执行它,它可能会使每个已通过身份验证的用户 SessionToken 失效,而不仅仅是那个。