首页 文章

OWIN认证管道,以及如何正确使用Katana中间件?

提问于
浏览
33

我最近开始研究新的ASP.Net Identity框架和Katana中间件,那里有大量的代码和文档,但我看到的是很多相互矛盾的信息,我想这是一个代码更新频率增加的结果 .

我希望有人可以提供一些 definitive 信息 .

具体来说,我感兴趣的是应该连接中间件的顺序以及在各种场景中需要哪些模块,我想摆脱任何不需要的东西,同时确保过程尽可能安全 .

例如,似乎 UseWsFederationAuthentication 应该与 UseCookieAuthentication 一起使用,但我不确定正确的 AuthenticationType 会是什么(this帖子表明它的值是显着的?)或者即使我们仍然需要使用 SetDefaultSignInAsAuthenticationType .

我还注意到Katana项目讨论板上的this线程,Tratcher提到了一个常见的错误,但是对于哪部分代码出错是不是很具体 .

就个人而言,我现在使用以下(使用自定义SAML令牌处理程序将令牌字符串读入有效的XML文档),它对我有用,但它是否最佳?

var appURI = ConfigurationManager.AppSettings["app:URI"];
var fedPassiveTokenEndpoint = ConfigurationManager.AppSettings["wsFederation:PassiveTokenEndpoint"];
var fedIssuerURI = ConfigurationManager.AppSettings["wsFederation:IssuerURI"];
var fedCertificateThumbprint = ConfigurationManager.AppSettings["wsFederation:CertificateThumbprint"];

var audienceRestriction = new AudienceRestriction(AudienceUriMode.Always);

audienceRestriction.AllowedAudienceUris.Add(new Uri(appURI));

var issuerRegistry = new ConfigurationBasedIssuerNameRegistry();

issuerRegistry.AddTrustedIssuer(fedCertificateThumbprint, fedIssuerURI);

app.UseCookieAuthentication(
    new CookieAuthenticationOptions
    {
        AuthenticationType = WsFederationAuthenticationDefaults.AuthenticationType // "Federation"
    }
);

app.UseWsFederationAuthentication(
    new WsFederationAuthenticationOptions
    {
        Wtrealm = appURI,
        SignOutWreply = appURI,
        Configuration = new WsFederationConfiguration
        {
            TokenEndpoint = fedPassiveTokenEndpoint
        },
        TokenValidationParameters = new TokenValidationParameters
        {
            AuthenticationType = WsFederationAuthenticationDefaults.AuthenticationType
        },
        SecurityTokenHandlers = new SecurityTokenHandlerCollection
        {                        
            new SamlSecurityTokenHandlerEx
            {
                CertificateValidator = X509CertificateValidator.None,
                Configuration = new SecurityTokenHandlerConfiguration
                {
                    AudienceRestriction = audienceRestriction,
                    IssuerNameRegistry = issuerRegistry
                }
            }
        }
    }
);

非常感谢您提供的任何帮助,以帮助我解决这个困惑 .

1 回答

  • 47

    正如@Tratcher所说, Microsoft.Owin.Security 使用 AuthenticationType 参数作为查找身份验证中间件实例的密钥 .

    下面的代码将使用以下简单的帮助程序方法来要求对所有请求进行身份验证 . 在实践中,您更可能在敏感控制器上使用 [Authorize] 属性,但我想要一个不依赖于任何框架的示例:

    private static void AuthenticateAllRequests(IAppBuilder app, params string[] authenticationTypes)
    {
        app.Use((context, continuation) =>
        {
            if (context.Authentication.User != null &&
                context.Authentication.User.Identity != null &&
                context.Authentication.User.Identity.IsAuthenticated)
            {
                return continuation();
            }
            else
            {
                context.Authentication.Challenge(authenticationTypes);
                return Task.Delay(0);
            }
        });
    }
    

    context.Authentication.Challenge(authenticationTypes) 呼叫将从每个提供的身份验证类型发出身份验证质询 . 我们将提供一个我们的WS-Federation身份验证类型 .

    正确代码

    首先,这里是一个简单使用WS-Federation的站点的“最佳”Owin Startup配置示例,如下所示:

    public void Configuration(IAppBuilder app)
    {
        app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
    
        app.UseCookieAuthentication(new CookieAuthenticationOptions());
    
        app.UseWsFederationAuthentication(new WsFederationAuthenticationOptions
        {
            AuthenticationType = "WS-Fed Auth (Primary)",
            Wtrealm = ConfigurationManager.AppSettings["app:URI"],
            MetadataAddress = ConfigurationManager.AppSettings["wsFederation:MetadataEndpoint"]
        });
    
        AuthenticateAllRequests(app, "WS-Fed Auth (Primary)");
    
        app.UseWelcomePage();
    }
    

    请注意使用 "WS-Fed Auth (Primary)" AuthenticationType 来唯一标识我们已配置的WS-Federation中间件实例 . 这意味着,如果您有此要求,您可以使用带有单独的WS-Federation服务器的 "WS-Fed Auth (Secondary)" 作为后备 .

    此配置将执行以下操作:

    • 首先,告诉Owin安全管道,默认情况下我们要使用 the default CookeAuthentication AthenticationType value 验证请求 . (这只是 CookieAuthenticationDefaults 类上的一个常量字符串,它是 CookieAuthenticationOptions.AuthenticationType 属性使用的默认值 . )

    • 接下来,使用所有默认选项注册cookie身份验证中间件实例,因此它对应于我们在步骤1中设置为默认值的 AuthenticationType 键 .

    • 接下来,使用我们在Web.config文件 and with a custom AuthenticationType value so we can refer to it later 中定义的选项注册WS-Federation身份验证中间件实例 .

    • 完成所有身份验证中间件注册后,我们告诉管道对所有请求进行身份验证(通过调用 Microsoft.Owin.Security 方法的自定义帮助器方法向任何未经身份验证的请求发出质询)

    • 最后,如果用户已通过身份验证,请显示欢迎页面!

    代码错误

    所以有几种方法你可以在这里出错 .

    未提供默认身份验证类型

    为了实验,我尝试这样做,你会马上看到问题所在:

    public void Configuration(IAppBuilder app)
    {
        var x = app.GetDefaultSignInAsAuthenticationType();
    
        app.SetDefaultSignInAsAuthenticationType(x);
    }
    

    第一次通话将为您提供您在第一条评论中提到的例外情况:

    “在IAppBuilder属性中找不到SignInAsAuthenticationType的默认值 . 如果您的身份验证中间件以错误的顺序添加,或者如果缺少一个,则会发生这种情况 . ”

    正确 - 因为默认情况下 Microsoft.Owin.Security 管道不会使用(即, Microsoft.Owin.Security.Cookies isn 't even known to be present), so it doesn' t知道什么应该是默认值 .

    使用错误的默认验证类型

    这花了我很多时间今天,因为我真的不知道我在做什么:

    public void Configuration(IAppBuilder app)
    {
        app.SetDefaultSignInAsAuthenticationType("WS-Fed AAD Auth");
    
        // ... remainder of configuration
    }
    

    因此,这将继续尝试在每次调用时使用WS-Federation对调用者进行身份验证 . 它是非常昂贵的,它是WS-Federation中间件实际上会对每个请求发出挑战 . 因此,您无法进入,并且您看到大量登录URL飞过您的身边 . :P

    可能性

    拥有这一切有什么好处管道的灵活性是你可以做一些非常酷的事情 . 例如,我有一个域内有两个不同的Web应用程序,在不同的子路径下运行,如: example.com/fooexample.com/bar . 您可以使用Owin的映射功能(如在 app.Map(...) 中)为每个应用程序设置完全不同的身份验证管道 . 在我的例子中,一个使用WS-Federation,而另一个使用客户端证书 . 试图在单一的 System.Web 框架中做到这一点将是可怕的 . :P

相关问题