在 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 客户端代码。
据我所知,最佳解决方案将满足这些要求:
- 相同代码适用于所有提供商
- 客户从我的服务器收到我的自定义票证(例如,没有图像声明)
- 客户端从未从我的服务器收到其他格式的票证
- 身份验证过程需要尽可能少的 HTTP 往返
- 令牌刷新和其他核心身份功能仍然可用
- 用户
[Authorize]
d 后,无需进一步的帐户转换
- database/repository 生成票据时访问是可行的
我正在研究的一些页面,作为我自己的笔记:
- How do I access Microsoft.Owin.Security.xyz OnAuthenticated context AddClaims values?
- https://katanaproject.codeplex.com/SourceControl/latest#src/Microsoft.Owin.Security.Facebook/FacebookAuthenticationHandler.cs
- https://katanaproject.codeplex.com/workitem/82
- https://www.simple-talk.com/dotnet/.net-framework/creating-custom-oauth-middleware-for-mvc-5/
您必须实施 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);
}
}
ClaimsAuthenticationManager
class就是专门针对这个的
来自该参考的代码示例:
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;
}
}
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 客户端代码。
据我所知,最佳解决方案将满足这些要求:
- 相同代码适用于所有提供商
- 客户从我的服务器收到我的自定义票证(例如,没有图像声明)
- 客户端从未从我的服务器收到其他格式的票证
- 身份验证过程需要尽可能少的 HTTP 往返
- 令牌刷新和其他核心身份功能仍然可用
- 用户
[Authorize]
d 后,无需进一步的帐户转换 - database/repository 生成票据时访问是可行的
我正在研究的一些页面,作为我自己的笔记:
- How do I access Microsoft.Owin.Security.xyz OnAuthenticated context AddClaims values?
- https://katanaproject.codeplex.com/SourceControl/latest#src/Microsoft.Owin.Security.Facebook/FacebookAuthenticationHandler.cs
- https://katanaproject.codeplex.com/workitem/82
- https://www.simple-talk.com/dotnet/.net-framework/creating-custom-oauth-middleware-for-mvc-5/
您必须实施 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);
}
}
ClaimsAuthenticationManager
class就是专门针对这个的
来自该参考的代码示例:
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;
}
}