使用Owin Middleware添加声明

Mat*_*ell 8 c# claims-based-identity asp.net-web-api owin owin-middleware

是否可以使用Owin Middleware实现在执行Web API控制器之前添加声明?

创建了OwinMiddleware实现并添加了一个标识:

 var id = new ClaimsIdentity();
 id.AddClaim(new Claim("Whatever", "is possible"));
 context.Authentication.User.AddIdentity(id);

 await Next.Invoke(context);
Run Code Online (Sandbox Code Playgroud)

但是,即使这个Invoke方法调用身份也不会更新(只是内部声明数组).并且控制器在执行时当然永远不会获得新的虚拟声明.

想法?

Pau*_*her 5

已经有一个类可以提供声明丰富 ClaimsAuthenticationManager,您可以扩展该类,以便它处理特定于域的声明,例如......

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

        return AddApplicationClaims(incomingPrincipal);
    }

    private ClaimsPrincipal AddApplicationClaims(ClaimsPrincipal principal)
    {
        // TODO: Add custom claims here based on current principal.

        return principal;
    }
}
Run Code Online (Sandbox Code Playgroud)

下一个任务是提供适当的中间件来调用它。对于我的项目,我编写了以下课程......

/// <summary>
/// Middleware component to apply claims transformation to current context
/// </summary>
public class ClaimsTransformationMiddleware
{
    private readonly Func<IDictionary<string, object>, Task> next;
    private readonly IServiceProvider serviceProvider;

    public ClaimsTransformationMiddleware(Func<IDictionary<string, object>, Task> next, IServiceProvider serviceProvider)
    {
        this.next = next;
        this.serviceProvider = serviceProvider;
    }

    public async Task Invoke(IDictionary<string, object> env)
    {
        // Use Katana's OWIN abstractions
        var context = new OwinContext(env);

        if (context.Authentication != null && context.Authentication.User != null)
        {
            var manager = serviceProvider.GetService<ClaimsAuthenticationManager>();
            context.Authentication.User = manager.Authenticate(context.Request.Uri.AbsoluteUri, context.Authentication.User);
        }

        await next(env);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后是延长线...

public static class AppBuilderExtensions
{
    /// <summary>
    /// Add claims transformation using <see cref="ClaimsTransformationMiddleware" /> any depdendency resolution is done via IoC
    /// </summary>
    /// <param name="app"></param>
    /// <param name="serviceProvider"></param>
    /// <returns></returns>
    public static IAppBuilder UseClaimsTransformation(this IAppBuilder app, IServiceProvider serviceProvider)
    {
        app.Use<ClaimsTransformationMiddleware>(serviceProvider);

        return app;
    }
}
Run Code Online (Sandbox Code Playgroud)

我知道这是服务定位器反模式,但使用 IServiceProvider 是容器中立的,并且似乎是将依赖项放入 Owin 中间件的可接受方式。

最后,您需要在启动中将其连接起来,下面的示例假定 Unity 并注册/公开 IServiceLocator 属性...

// Owin config
app.UseClaimsTransformation(UnityConfig.ServiceLocator);
Run Code Online (Sandbox Code Playgroud)


Dal*_*rzo 1

您可能会发现继承授权属性并扩展它以满足您的要求很有用:

public class DemoAuthorizeAttribute : AuthorizeAttribute
    {     

        public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext){
            if (Authorize(actionContext)){
                return;
            }
            HandleUnauthorizedRequest(actionContext);
        }

        protected override void HandleUnauthorizedRequest(System.Web.Http.Controllers.HttpActionContext actionContext){
            var challengeMessage = new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized;

//Adding your code here
 var id = new ClaimsIdentity();
 id.AddClaim(new Claim("Whatever", "is possible"));
 context.Authentication.User.AddIdentity(id);

            challengeMessage.Headers.Add("WWW-Authenticate", "Basic");
            throw new HttpResponseException(challengeMessage);
        }

        private bool Authorize(System.Web.Http.Controllers.HttpActionContext actionContext){
            try{
                var someCode = (from h in actionContext.Request.Headers where h.Key == "demo" select h.Value.First()).FirstOrDefault();

                 // or check for the claims identity property.
                return someCode == "myCode";
            }
            catch (Exception){
                return false;
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

在你的控制器中:

[DemoAuthorize]
public class ValuesController : ApiController{
Run Code Online (Sandbox Code Playgroud)

以下是有关 WebApi 授权的其他自定义实现的链接:

http://www.piotrwalat.net/basic-http-authentication-in-asp-net-web-api-using-membership-provider/