【问题标题】:Asp.Net Web API - Asp.Net Identity and Owin vs HttpModule AuthenticateRequestAsp.Net Web API - Asp.Net Identity and Owin vs HttpModule AuthenticateRequest
【发布时间】:2015-03-04 17:14:41
【问题描述】:

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

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

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

而响应消息是:

此请求的授权已被拒绝

如果我从控制器中删除 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 模块来实现这一点?

【问题讨论】:

    标签: asp.net asp.net-web-api asp.net-identity owin


    【解决方案1】:

    好的,我已经实现了一个自定义的 owin 身份验证中间件,只是为了发现它也不起作用。这样做的原因是几个月前我已将此行添加到我的 WebApi.config 文件中,以避免对我的 Web 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") 授权我的任何 Web api 操作

    【讨论】:

      猜你喜欢
      • 2013-10-30
      • 1970-01-01
      • 2015-08-09
      • 2016-04-12
      • 2015-01-09
      • 1970-01-01
      • 1970-01-01
      • 2023-04-08
      • 2020-03-05
      相关资源
      最近更新 更多