Asp.Net Web API - Asp.Net 身份和 Owin 与 HttpModule AuthenticateRequest

Asp.Net Web API - Asp.Net Identity and Owin vs HttpModule AuthenticateRequest

我有一个 Asp.Net Web API 项目托管在 Web 角色 (IIS 8.5) 中,我正在按照 this post 的步骤使用 Azure Scheduler 发送一个每隔一段时间请求我的应用程序做一些工作。

问题是负责验证调度程序请求的 HttpModule 正在加载,但是当请求到达 ApiController 时其结果被忽略。

我正在使用 POSTMAN 测试 REST 端点,这是我在调试时在 http 模块中看到的:

响应消息是:

Authorization has been denied for this request

如果我从控制器中删除 Authorize 属性,这就是我在请求命中时看到的内容:

Startup.Auth.cs的相关部分:

        app.UseCookieAuthentication(cookieOptions);
        app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);  
        app.UseOAuthBearerTokens(OAuthBearerOptions);
        app.UseLinkedInAuthentication("777777", "8888888");

在使用 Asp.Net Identity 和 Owin 时是否可以使用 HttpModule 对请求进行身份验证,或者我必须实施 Owin AuthenticationMiddleware 模块才能实现此目的?

好的,我实现了一个自定义的 owin 身份验证中间件,只是发现它也不起作用。这样做的原因是几个月前我将这一行添加到我的 WebApi.config 文件中,以避免对我的网络 api 控制器进行无意的 cookie 身份验证:

        config.SuppressDefaultHostAuthentication();

这也抑制了我的新 owin auth 中间件。要启用它,我必须添加这一行:

        config.Filters.Add(new HostAuthenticationFilter(SchedulerAuthenticationMiddlewareConstants.DefaultAuthenticationType));

完全删除 SuppressDefaultHostAuthentication() 使 HttpModule 工作 但在那种情况下,我的缺点是隐式启用除承载令牌之外的其他身份验证机制 REST 端点.

HttpModule功能对应的Owin Auth中间件如下:

using System.Collections.Generic;
using System.IO;
using System.Security.Claims;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Microsoft.Owin;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Infrastructure;
using Owin;

namespace SchedulerAuthenticationMiddleware
{
    public static class SchedulerAuthenticationExtensions
    {
        public static IAppBuilder UseSchedulerAuthentication(this IAppBuilder app, SchedulerAuthenticationOptions options)
        {
            return app.Use(typeof(SchedulerAuthenticationMiddleware), app, options);
        }
    }

    public static class SchedulerAuthenticationMiddlewareConstants
    {
        public const string DefaultAuthenticationType = "Scheduler";
    }

    public class SchedulerAuthenticationOptions : AuthenticationOptions
    {
        public SchedulerAuthenticationOptions(string schedulerSharedSecret)
            : base(SchedulerAuthenticationMiddlewareConstants.DefaultAuthenticationType)
        {
            Description.Caption = SchedulerAuthenticationMiddlewareConstants.DefaultAuthenticationType;

            // http://brockallen.com/2013/10/27/host-authentication-and-web-api-with-owin-and-active-vs-passive-authentication-middleware/
            // Active middleware always look at every incoming request and attempt to authenticate the call and if successful 
            // they create a principal that represents the current user and assign that principal to the hosting environment. 
            // Passive middleware, on the other hand, only inspects the request when asked to. 
            AuthenticationMode = AuthenticationMode.Passive;

            SchedulerSharedSecret = schedulerSharedSecret;
        }

        public string SchedulerSharedSecret { get; set; }
    }

    // One instance is created when the application starts.
    public class SchedulerAuthenticationMiddleware : AuthenticationMiddleware<SchedulerAuthenticationOptions>
    {
        public SchedulerAuthenticationMiddleware(OwinMiddleware next, IAppBuilder app, SchedulerAuthenticationOptions options)
            : base(next, options)
        {
        }

        // Called for each request, to create a handler for each request.
        protected override AuthenticationHandler<SchedulerAuthenticationOptions> CreateHandler()
        {
            return new SchedulerAuthenticationHandler();
        }
    }

    class SchedulerAuthenticationHandler : AuthenticationHandler<SchedulerAuthenticationOptions>
    {
        protected override Task<AuthenticationTicket> AuthenticateCoreAsync()
        {
            AuthenticationTicket ticket = null;
            if (Context.Request.Headers.ContainsKey("x-ms-scheduler-jobid"))
            {
                using (StreamReader sr = new StreamReader(Context.Request.Body))
                {
                    string bodyContent = sr.ReadToEnd();
                    var match = new Regex(@"secret:(\d*)").Match(bodyContent);
                    if (match.Success && match.Groups[1].Value == Options.SchedulerSharedSecret)
                    {
                        ticket = CreateTicket();
                    }
                }
            }

            return Task.FromResult(ticket);
        }

        private AuthenticationTicket CreateTicket()
        {
            AuthenticationProperties properties = new AuthenticationProperties();
            ClaimsIdentity claimIdentity = CreateSchedulerIdentity();
            return new AuthenticationTicket(claimIdentity, properties);
        }

        private ClaimsIdentity CreateSchedulerIdentity()
        {
            // ASP.Net Identity requires the NameIdentifier field to be set or it won't  
            // accept the external login (AuthenticationManagerExtensions.GetExternalLoginInfo)
            Claim nameIdentifier = new Claim(ClaimTypes.NameIdentifier, "scheduler", null, Options.AuthenticationType);
            Claim nameIdClaim = new Claim(ClaimTypes.Name, "scheduler", null, Options.AuthenticationType);
            Claim schedulerRoleClaim = new Claim(ClaimTypes.Role, "scheduler");
            Claim identificatorClaim = new Claim("http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider", "application");

            ClaimsIdentity claimIdentity = new ClaimsIdentity(new List<Claim>
                            {
                                nameIdentifier,
                                nameIdClaim,
                                schedulerRoleClaim,
                                identificatorClaim
                            }, "custom", ClaimTypes.Name, ClaimTypes.Role);
            return claimIdentity;
        }
    }
}

最后,我可以使用 Authorize(Roles = "scheduler")

授权我的任何网络 api 操作