首页 文章

Webapi委托处理程序返回401响应被Owin Auth覆盖

提问于
浏览
0

我已经审查了类似的帖子,其解决方案对我不起作用 .

我有一个在IIS 7.x中托管的MVC 5站点,它提供web ui - https://www.example.com . 呼叫者还可以访问api(Webapi 2.2) endpoints 以执行某些功能 - https://www.example.com/api/x . 有些页面/ apis是安全的,而有些则不是 . mvc / web ui安全性由使用UseCookieAuthentication和UseWsFederationAuthentication配置的owin中间件管理 .

当用户尚未拥有有效的SAML令牌时,webui中的安全页面将自动重定向到ADFS登录屏幕 - 根据需要 .

安全的Web apis需要在Auth头中传递单独的JWT令牌 .

Webapi与MVC托管在同一个应用程序池中 . Webapi没有控制器,而webapiconfig具有利用DelegatingHandler路由/传递api调用的路由 . 委托处理程序是检查JWT是否包含在Auth标头中的处理程序,如果是,则允许它继续使用验证JWT的不同内部webapi . 如果JWT不存在,则DelegatingHandler返回401 .

401返回曾经工作,因为它短路了请求的延续,因此绕过任何owin管道的东西 . 但是,现在当短路开火时401没有返回 . 相反,请求继续并传递到Owin auth,然后重定向(302)到ADFS登录 . 我不知道为什么 . If I change the response status code to something other than 401 then Owin Auth ignores it.

请参阅以下代码:

Global.asax.cs

public class Global : HttpApplication
{
    protected void Application_Start(object sender, EventArgs e)
    {
        // Code that runs on application startup
        AreaRegistration.RegisterAllAreas();
        GlobalConfiguration.Configure(WebApiConfig.Register);
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);        
    }
}

WebApiConfig.cs

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        config.Routes.MapHttpRoute(
            name: "Apis",
            routeTemplate: "api/{*path}",
            handler: HttpClientFactory.CreatePipeline
            (
                innerHandler: new HttpClientHandler(),
                handlers: new DelegatingHandler[] { new ApiHandler() }
            ),
            defaults: new { path = RouteParameter.Optional },
            constraints: null
        );
    }
}

ApiHandler.cs

internal class ApiHandler : DelegatingHandler
{
    protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.Unauthorized);

        try
        {
            // get jwt from header
            var jwt = GetJWTFromHeader(request.Headers);

            if (jwt == null)
            {
                response.ReasonPhrase = "Token required";
                return await Task.FromResult<HttpResponseMessage>(response);
            }
            else if (!IsValidJWT(jwt))
            {
                response.ReasonPhrase = "Invalid token";
                return await Task.FromResult<HttpResponseMessage>(response);
            }

            response = await base.SendAsync(request, cancellationToken);

        }
        catch (Exception ex)
        {
            // log error
            response = new HttpResponseMessage(HttpStatusCode.InternalServerError);
        }

        // return result
        return response;
    }
}

Startup.Auth.cs

public partial class Startup
{
    public void ConfigureAuth(IAppBuilder app)
    {
        ServicePointManager.ServerCertificateValidationCallback += ValidateServerCertificate;

        app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);

        app.UseCookieAuthentication(
            new CookieAuthenticationOptions()
            {
                SlidingExpiration = false
            }
        );

        app.UseWsFederationAuthentication(
            new WsFederationAuthenticationOptions
            {
                Wtrealm = ADFS_REALM,
                MetadataAddress = ADFS_METADATA,
                UseTokenLifetime = true,
                TokenValidationParameters = new TokenValidationParameters
                {
                    SaveSigninToken = true
                },

                Notifications = new WsFederationAuthenticationNotifications
                {
                    RedirectToIdentityProvider = async r =>
                    {
                        // do stuff                         
                    },
                    SecurityTokenValidated = async s =>
                    {
                        // if we get here, then UI user has valid saml token
                        // do stuff
                    }
                }
            }
        });

}

我感谢任何帮助 . 如果需要更多细节,请告诉我!

2 回答

  • 1
  • 1

    感谢Finallz我能够优化我的搜索并找到答案 - 找到here . 在我的情况下,我没有't need any special authentication config since I' m在apihandler中手动检查了JWT . 但是,通过简单地将 Map 包含到我的api路径中,它自然会覆盖Owin安全性:

    app.Map("/api", inner =>
    {
         // nothing to do here since we don't have any concrete controllers to manage special authorization for
         // we're using apihandlers to pass api traffic through to next stop
    });
    

相关问题