在 WebAPI 应用程序中在哪里过滤 Identity 2.0 声明票?

Where to filter Identity 2.0 claim ticket in a WebAPI app?

ASP.NET 使用 OWIN 的应用允许多个身份源(Facebook、Google 等)。这些来源提供的大多数特定于提供商的信息与我的应用程序无关,甚至可能很大,我不希望它在我的所有会话中都出现在我的 cookie 中。我的应用程序主要是 WebAPI,但我怀疑这个问题同样适用于 MVC 和 WebForms。

现在,我只需要一个整数帐户 ID。 Where/when外部认证后是否需要重建身份?

例如,这是我可以过滤声明的一种方法:

public ReplaceExistingClaims(ClaimsIdentity identity) {
{
    Claim customClaim = GetCustomClaimFromDbForIdentity(identity);
    foreach (Claim claim in ClaimsIdentity.Claims) ClaimsIdentity.RemoveClaim(claim);
    ClaimsIdentity.AddClaim(customClaim);
}

下面是我可以注入这些声明更改的两个不同地方:

var facebookAuthenticationOptions = new FacebookAuthenticationOptions
{
    Provider = new FacebookAuthenticationProvider
    {
        OnAuthenticated = context =>
        {
            ReplaceExistingClaims(context.Identity);
            return Task.FromResult(0);
        }
    }
};

以上,我知道如果它提供 Authenticated 事件,我可以从 Startup 挂钩一个单独的提供者。我对此有两个概念上的问题。第一:它要求我为我插入的每个提供者分别编写和连接我的代码。第二:没有要求提供者提供此事件。这两个让我觉得我的代码必须有一个不同的预期插入点。

public ActionResult ExternalLoginCallback(string returnUrl)
{
    ReplaceExistingClaims((ClaimsIdentity)User.Identity);
    new RedirectResult(returnUrl);
}

以上,我知道我可以把代码放在ExternalLoginCallback。但由于两个原因,这发生得太晚了。一:用户已经收到一张我认为无效的票,但默认的 [Authorized] 认为有效,因为它是我签名的,现在他们正在用它向我的站点发出请求。这里甚至可能存在竞争条件。二:不能保证浏览器会访问此重定向,如果不需要,我更愿意从设计的角度来看,例如简化我的 WebAPI 客户端代码。

据我所知,最佳解决方案将满足这些要求:

  1. 相同代码适用于所有提供商
  2. 客户从我的服务器收到我的自定义票证(例如,没有图像声明)
  3. 客户端从未从我的服务器收到其他格式的票证
  4. 身份验证过程需要尽可能少的 HTTP 往返
  5. 令牌刷新和其他核心身份功能仍然可用
  6. 用户 [Authorize]d 后,无需进一步的帐户转换
  7. database/repository 生成票据时访问是可行的

我正在研究的一些页面,作为我自己的笔记:

您必须实施 DelegationHandler 并将所有身份验证例程放入其中。

在应用程序启动时注册(启用 DI 使用):

private static void RegisterHandlers(HttpConfiguration config)
{
    var authHandler = new MyFacebookAuthHandler();
    config.MessageHandlers.Add(authHandler);
}

这是一个实施示例:

public class MyFacebookAuthHandler : DelegationHandler
{
    public override sealed Task<HttpResponseMessage> OnSendAsync(HttpRequestMessage request,
                                                                 CancellationToken cancellationToken)
    {
        try
        {
            // Process credentials
            // Probably you have to save some auth information to HttpContext.Current
            // Or throw NotAuthorizedException
        }
        catch(NotAuthorizedException ex)
        {
            return request.CreateErrorResponse(HttpStatusCode.Unauthorized, ex).ToCompletedTask();
        }
        catch (Exception ex)
        {
            return request.CreateErrorResponse(HttpStatusCode.InternalServerError, ex).ToCompletedTask();
        }

        return base.OnSendAsync(request, cancellationToken);
    }
}

ClaimsAuthenticationManagerclass就是专门针对这个的

https://msdn.microsoft.com/en-us/library/system.security.claims.claimsauthenticationmanager(v=vs.110).aspx

来自该参考的代码示例:

class SimpleClaimsAuthenticatonManager : ClaimsAuthenticationManager
{
    public override ClaimsPrincipal Authenticate(string resourceName, ClaimsPrincipal incomingPrincipal)
    {
        if (incomingPrincipal != null && incomingPrincipal.Identity.IsAuthenticated == true)
        {
            ((ClaimsIdentity)incomingPrincipal.Identity).AddClaim(new Claim(ClaimTypes.Role, "User"));
        }
        return incomingPrincipal; 
    }
}