如何在Web API SessionToken中过期/更新ClaimsIdentity Claims

6
我正在使用优秀的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?例如,如果我想“注销”用户,该怎么做?
2个回答

4
会话令牌功能没有这个功能。 我们希望保持简单,以解决“在每次应用程序启动时输入密码”问题。 没有完整的数据存储后端是难以实现撤销的(无论在 Web Farm 等环境中是否可行)。
不应将可能会在会话期间发生更改的数据存储在会话令牌中。

0

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

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


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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接