在 MVC 应用程序中的何处使用 WIF 创建自定义标识?
Where to create custom Identity with WIF in a MVC application?
在 WIF 之前,Application_PostAcquireRequestState
是创建自定义身份的好地方,但需要大量框架来确保正确映射您正在执行的每种类型的身份验证。通过自定义身份,我的意思是 class 从身份继承,例如下面的 SomeIdentity,这样我们就可以拥有特定的 属性 我们可能要求所有经过身份验证的用户都拥有。
PostAcquirerequestState 仍然可用,但有许多新方法可以挂接到身份验证。此外,旧方法在支持多种身份验证方法时会变得复杂。
我想知道现在在 WIF 中是否有比下面更好的方法来完成此操作。主要是我想分离出处理映射声明到身份的代码。这个想法是代码对于其他身份验证 types/providers 会有所不同,因为它检索 属性 值的方式可能不是来自 SAML 等声明,而是来自其他地方的其他类型的身份验证方法.我目前正在使用 Kentor.AuthServices
来支持 SAML。虽然根据提供者可能有不同的代码来映射这些值,但最终结果将是创建了一个 SomeIdentity 实例并且它是 SomeProperty 并且将设置其他属性。这样应用程序的其余部分总是可以 depend/assume 那些已经被处理。
我的 MVC 项目带有一个 AccountController
,它有一个 ExternalLoginCallback
,顾名思义,当外部身份验证完成时,它可能是一个很好的挂钩(对我来说 SAML 是一个 "external" 验证)。但是,它似乎在任何时候都没有命中 during/after 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;
}
现在我正在使用 WIF,我应该将特定于创建自定义 SomeIdentity 的特定身份验证类型(即 Kentor.AuthServices SAML)的代码放在哪里?
我的想法是 SomeIdentity 将成为我应用程序中随处使用的身份 class,但是填充它的属性的代码将需要为每种身份验证类型专门编写,例如使用 SAML 来提取声明并使用它们的值来设置属性。 IE。这是映射发生的地方。
好的,我要试一试,希望我能理解你的问题,而不是对你的代码做出太多假设。我要做的假设是这是一个全新的 MVC 应用程序,使用 Visual Studio ASP.NET 4.6 模板和 "No Authentication" 选项创建(根据我对你的情况的了解,你不是'不想存储这些数据,就像从声明中读取它一样多)。
将名为 Started 的 class 添加到项目的根目录中
using Microsoft.Owin;
using Owin;
[assembly: OwinStartup(typeof(WebApplication1.Startup))]
namespace WebApplication1
{
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
}
}
}
现在这将是 运行,正如您可能猜到的那样,在 "startup" 上就像 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)
{
}
}
}
这是我们进行身份验证逻辑/设置的地方。 OWIN 带有很多开箱即用的身份验证策略,有些库甚至更多。如果您打算自己编写,我建议您看看 OwinOAuthProviders。
继续安装 NuGet 包 Kentor.AuthServices.Owin 包和依赖项。这也应该修复您目前遇到的任何编译错误。您还需要在您的项目中添加对 System.IdentityModel 的引用以备后用。
现在,在 Startup.Auth.cs 中的 ConfigureAuth 方法中,您可以通过执行以下操作将 Kentor 添加到您的应用中。
Public void ConfigureAuth(IAppBuilder app)
{
var kentorOptions = new KentorAuthServicesAuthenticationOptions(true);
}
现在你的变量 kentorOptions 因为我把它传递给 true,将从你的 WebConfig 读取你的设置。不过,您也可以在此处手动配置它们。
我们感兴趣的部分是 kentorOptions.SPOptions.SystemIdentityModelIdentityConfiguration.ClaimsAuthenticationManager 属性。我们想创建一个自定义的 ClaimsAuthenticationManager 以根据传入的声明提供身份。
创建一个继承自 ClaimsAuthenticationManager
的新 class
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;
}
}
}
那是您拥有身份代码的地方。现在最后我们需要将其设置为实际使用的 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 );
}
Annnndd,希望能做到!对于其他 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 );
在 WIF 之前,Application_PostAcquireRequestState
是创建自定义身份的好地方,但需要大量框架来确保正确映射您正在执行的每种类型的身份验证。通过自定义身份,我的意思是 class 从身份继承,例如下面的 SomeIdentity,这样我们就可以拥有特定的 属性 我们可能要求所有经过身份验证的用户都拥有。
PostAcquirerequestState 仍然可用,但有许多新方法可以挂接到身份验证。此外,旧方法在支持多种身份验证方法时会变得复杂。
我想知道现在在 WIF 中是否有比下面更好的方法来完成此操作。主要是我想分离出处理映射声明到身份的代码。这个想法是代码对于其他身份验证 types/providers 会有所不同,因为它检索 属性 值的方式可能不是来自 SAML 等声明,而是来自其他地方的其他类型的身份验证方法.我目前正在使用 Kentor.AuthServices
来支持 SAML。虽然根据提供者可能有不同的代码来映射这些值,但最终结果将是创建了一个 SomeIdentity 实例并且它是 SomeProperty 并且将设置其他属性。这样应用程序的其余部分总是可以 depend/assume 那些已经被处理。
我的 MVC 项目带有一个 AccountController
,它有一个 ExternalLoginCallback
,顾名思义,当外部身份验证完成时,它可能是一个很好的挂钩(对我来说 SAML 是一个 "external" 验证)。但是,它似乎在任何时候都没有命中 during/after 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;
}
现在我正在使用 WIF,我应该将特定于创建自定义 SomeIdentity 的特定身份验证类型(即 Kentor.AuthServices SAML)的代码放在哪里?
我的想法是 SomeIdentity 将成为我应用程序中随处使用的身份 class,但是填充它的属性的代码将需要为每种身份验证类型专门编写,例如使用 SAML 来提取声明并使用它们的值来设置属性。 IE。这是映射发生的地方。
好的,我要试一试,希望我能理解你的问题,而不是对你的代码做出太多假设。我要做的假设是这是一个全新的 MVC 应用程序,使用 Visual Studio ASP.NET 4.6 模板和 "No Authentication" 选项创建(根据我对你的情况的了解,你不是'不想存储这些数据,就像从声明中读取它一样多)。
将名为 Started 的 class 添加到项目的根目录中
using Microsoft.Owin;
using Owin;
[assembly: OwinStartup(typeof(WebApplication1.Startup))]
namespace WebApplication1
{
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
}
}
}
现在这将是 运行,正如您可能猜到的那样,在 "startup" 上就像 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)
{
}
}
}
这是我们进行身份验证逻辑/设置的地方。 OWIN 带有很多开箱即用的身份验证策略,有些库甚至更多。如果您打算自己编写,我建议您看看 OwinOAuthProviders。
继续安装 NuGet 包 Kentor.AuthServices.Owin 包和依赖项。这也应该修复您目前遇到的任何编译错误。您还需要在您的项目中添加对 System.IdentityModel 的引用以备后用。
现在,在 Startup.Auth.cs 中的 ConfigureAuth 方法中,您可以通过执行以下操作将 Kentor 添加到您的应用中。
Public void ConfigureAuth(IAppBuilder app)
{
var kentorOptions = new KentorAuthServicesAuthenticationOptions(true);
}
现在你的变量 kentorOptions 因为我把它传递给 true,将从你的 WebConfig 读取你的设置。不过,您也可以在此处手动配置它们。
我们感兴趣的部分是 kentorOptions.SPOptions.SystemIdentityModelIdentityConfiguration.ClaimsAuthenticationManager 属性。我们想创建一个自定义的 ClaimsAuthenticationManager 以根据传入的声明提供身份。
创建一个继承自 ClaimsAuthenticationManager
的新 classusing 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;
}
}
}
那是您拥有身份代码的地方。现在最后我们需要将其设置为实际使用的 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 );
}
Annnndd,希望能做到!对于其他 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 );