简体   繁体   English

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

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

I have an Asp.Net Web API project hosted in a Web Role (IIS 8.5), and I'm following the steps of this post to use Azure Scheduler to send a request to my app every some time to do some work. 我有一个托管在Web角色(IIS 8.5)中的Asp.Net Web API项目,我按照这篇文章的步骤使用Azure Scheduler每隔一段时间向我的应用程序发送一个请求来完成一些工作。

The problem is that the HttpModule responsible for authenticating the scheduler's requests, is being loaded but its result is being ignored afterwards when the request hits the ApiController. 问题是正在加载负责验证调度程序请求的HttpModule,但是当请求到达ApiController时,其结果将被忽略。

I'm using POSTMAN to test the REST endpoint and this is what I see in the http module when debugging: 我正在使用POSTMAN来测试REST端点,这是我在调试时在http模块中看到的:

Http模块

And the response message is: 并且响应消息是:

Authorization has been denied for this request 此请求已被拒绝授权

If I remove the Authorize attribute from the controller, this is what I see when the request hits it: 如果我从控制器中删除了Authorize属性,这就是我在请求命中时看到的内容:

SchedulerController

Relevant part of Startup.Auth.cs: Startup.Auth.cs的相关部分:

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

Is it possible to use an HttpModule to authenticate the request when using Asp.Net Identity and Owin, or I must implement an Owin AuthenticationMiddleware module to achieve this? 使用Asp.Net Identity和Owin时是否可以使用HttpModule来验证请求,或者我必须实现Owin AuthenticationMiddleware模块才能实现此目的?

Ok, I had implemented a custom owin authentication middleware just to find out that it also wouldn't work. 好吧,我已经实现了一个自定义owin身份验证中间件,只是为了发现它也行不通。 There reason for this is that I had added this line to my WebApi.config file some months ago to avoid unintentional cookie authentication for my web api controllers: 原因是我几个月前将这行添加到我的WebApi.config文件中,以避免对我的web api控制器进行无意的cookie身份验证:

        config.SuppressDefaultHostAuthentication();

This also suppressed my new owin auth middleware. 这也抑制了我的新owin auth中间件。 To enable it I had to add this line: 要启用它,我必须添加以下行:

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

Completely removing the SuppressDefaultHostAuthentication() makes the HttpModule to work but in that case I have the disadvantage of implicitly enabling other authentication mechanisms other than bearer tokens for the REST endpoints. 完全删除SuppressDefaultHostAuthentication()使HttpModule工作,但在这种情况下,我的缺点是隐式启用除端点的承载令牌之外的其他身份验证机制。

The functionally corresponding Owin Auth Middleware of the HttpModule looks as follows: 功能相应的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;
        }
    }
}

At last, I can authorize any of my web api actions using Authorize(Roles = "scheduler") 最后,我可以使用Authorize(Roles = "scheduler")我的任何web api操作

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM