在MVC应用程序中使用WIF创建自定义标识的位置?

Aar*_*nLS 10 wif

在WIF之前,Application_PostAcquireRequestState是创建自定义标识的好地方,但需要大量框架来确保您正在进行的每种类型的身份验证都已正确映射.通过自定义标识,我的意思是继承自Identity的类,例如下面的SomeIdentity,这样我们就可以拥有一个特定的属性,我们可能需要所有经过身份验证的用户拥有.

PostAcquirerequestState仍然可用,但是有很多新方法可以挂钩进行身份验证.此外,支持多种身份验证方法时,旧方法变得复杂.

我想知道在WIF中是否有比下面更好的方法来实现这一点.主要是我想将处理映射声明的代码分离出来.这个想法是代码对于其他身份验证类型/提供者而言是不同的,因为它检索该属性值的方式可能不是来自诸如SAML的声明,而是来自其他地方的其他类型的身份验证方法.我Kentor.AuthServices目前正在使用SAML支持.虽然可能有不同的代码用于根据提供程序映射这些值,但最终结果是已创建SomeIdentity实例并且将设置SomeProperty和其他属性.这样,应用程序的其余部分总是可以依赖/假设已经处理过.

我的MVC项目想出了一个AccountController即有ExternalLoginCallback其隐含的可能是,当外部认证结束一个良好的钩的名字(这对我SAML是"外部"认证).但是,在SAML身份验证期间/之后的任何时候似乎都没有受到攻击.

可能答案是我们仍然需要以旧方式将它们拼凑在一起,但我希望WIF有一些更好的框架钩子来使这更容易.

public sealed class SomeIdentity : Identity
{
  ...
  // Some custom properties
  public string SomeProperty { get;set;}
}

protected void Application_PostAcquireRequestState(object sender, EventArgs e)
{
  ...
  identity = new SomeIdentity(id, userId);
  // map a claim to a specific property
  identity.SomeProperty = ...Claims[IdpSomePropertyKey];
  ///...

  GenericPrincipal newPrincipal = new GenericPrincipal(identity , null);
  HttpContext.Current.User = newPrincipal;
  System.Threading.Thread.CurrentPrincipal = newPrincipal;
}
Run Code Online (Sandbox Code Playgroud)

现在我正在使用WIF,我应该在哪里放置特定于特定身份验证类型的代码(即Kentor.AuthServices SAML)来创建自定义SomeIdentity?

我的想法是,SomeIdentity将是我的应用程序中随处使用的标识类,但是填充它的属性的代码将需要专门针对每种身份验证类型编写,例如使用SAML来提取声明并使用它们的值来设置proeprties.即它是映射发生的地方.

Mat*_*ice 4

好吧,我将对此进行尝试,希望我能理解您的问题,并且不会对您的代码做出太多假设。我要做的假设是,这是一个全新的 MVC 应用程序,使用 Visual Studio ASP.NET 4.6 模板创建,并带有“无身份验证”选项(根据我对您的情况的了解,您不希望存储此数据就像从权利要求中读到的一样)。

将名为 Started 的类添加到项目的根目录

using Microsoft.Owin;
using Owin;

[assembly: OwinStartup(typeof(WebApplication1.Startup))]

namespace WebApplication1
{
    public partial class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            ConfigureAuth(app);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,正如您可能猜到的那样,它将在“启动”时运行,就像 global.asax.cs 文件一样。

现在我们需要实际创建ConfigureAuth() 方法。这通常是在 App_Start 文件夹中使用名为“Startup.Auth.cs”的文件完成的。该文件当前不存在,因此请继续使用此模板创建它

using Owin;
using Kentor.AuthServices.Owin;

namespace WebApplication1
{
    public partial class Startup
    {
        private void ConfigureAuth(IAppBuilder app)
        {
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我们将进行身份验证逻辑/设置的地方。OWIN 附带了相当多的开箱即用的身份验证策略,并且有一些库提供了更多。如果您打算编写自己的OwinOAuthProviders,我建议您查看一下OwinOAuthProviders。

继续安装 NuGet 包 Kentor.AuthServices.Owin 包和依赖项。这也应该可以修复您目前遇到的任何编译错误。您还需要将对 System.IdentityModel 的引用添加到您的项目中以供稍后使用。

现在,在 Startup.Auth.cs 内的 ConfigureAuth 方法中,您可以通过执行以下操作将 Kentor 添加到您的应用程序中。

Public void ConfigureAuth(IAppBuilder app)
{
    var kentorOptions = new KentorAuthServicesAuthenticationOptions(true);
}
Run Code Online (Sandbox Code Playgroud)

现在,自从我将其传递为 true 以来,您的变量 kentorOptions 将从您的 WebConfig 中读取您的设置。不过,您也可以在这里手动配置它们。

我们感兴趣的部分是 kentorOptions.SPOptions.SystemIdentityModelIdentityConfiguration.ClaimsAuthenticationManager 属性。我们想要创建一个自定义的 ClaimsAuthenticationManager 来根据传入的声明提供身份。

创建一个继承自 ClaimsAuthenticationManager 的新类

using System.Security.Claims;

namespace WebApplication5 {
    public class CustomClaimsAuthManager : ClaimsAuthenticationManager {
        public override ClaimsPrincipal Authenticate( string resourceName, ClaimsPrincipal incomingPrincipal ) {
            ClaimsIdentity ident = (ClaimsIdentity) incomingPrincipal.Identity;
            //Use incomingPrincipal.Identity.AuthenticationType to determine how they got auth'd
            //Use incomingPrincipal.Identity.IsAuthenticated to make sure they are authenticated.
            //Use ident.AddClaim to add a new claim to the user
             ...
            identity = new SomeIdentity( id, userId );
            // map a claim to a specific property
            identity.SomeProperty = ...Claims[IdpSomePropertyKey];
            ///...

            GenericPrincipal newPrincipal = new GenericPrincipal( identity, null );
            return newPrincipal;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这就是您的身份代码。现在最后我们需要将其设置为要实际使用的 ClaimsAuthenticationManager,并告诉您的应用程序在 OWIN 管道中使用 Kentor。这一切都回到了 Startup.Auth.cs 文件中。

private void ConfigureAuth( IAppBuilder app ) {
            var kentorOptions = new KentorAuthServicesAuthenticationOptions(true);
            kentorOptions.SPOptions.SystemIdentityModelIdentityConfiguration.ClaimsAuthenticationManager = new WebApplication5.CustomClaimsAuthManager();
            app.UseKentorAuthServicesAuthentication( kentorOptions );
        }
Run Code Online (Sandbox Code Playgroud)

Annndd 希望可以做到!对于其他 Auth 提供程序(例如 OwinOAuthProviders 中的提供程序),您还可以通过重写 options.Provider 方法来操作不同的事件,如下所示:

var cookieOptions = new CookieAuthenticationOptions {
                AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
                LoginPath = new PathString( "/Auth/Login" ),
                CookieName = "cooooookiees",
                ExpireTimeSpan = new TimeSpan( 10000, 0, 0, 0, 0 ),
                Provider = new CookieAuthenticationProvider {
                    OnException = context => {
                        var x = context;
                    },
                    OnValidateIdentity = async context => {
                        var invalidateBySecurityStamp = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
                        validateInterval: TimeSpan.FromMinutes( 15 ),
                        regenerateIdentity: ( manager, user ) => user.GenerateUserIdentityAsync( manager ) );
                        await invalidateBySecurityStamp.Invoke( context );

                        if ( context.Identity == null || !context.Identity.IsAuthenticated ) {
                            return;
                        }
                        var newResponseGrant = context.OwinContext.Authentication.AuthenticationResponseGrant;
                        if ( newResponseGrant != null ) {
                            newResponseGrant.Properties.IsPersistent = true;
                        }

                    }
                }
            };
            app.UseCookieAuthentication( cookieOptions );
Run Code Online (Sandbox Code Playgroud)