ASP.NET核心MVC 2.0中基于路径的身份验证

ASP.NET核心MVC 2.0中基于路径的身份验证,.net,authentication,asp.net-core-mvc,asp.net-core-mvc-2.0,.net,Authentication,Asp.net Core Mvc,Asp.net Core Mvc 2.0,在ASP.NET Core MVC 1.1中,我们有如下基于路径的身份验证: public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { // /api/* path app.UseWhen(ctx => IsApiRequest(ctx), subBranch => { subBranch.Use

在ASP.NET Core MVC 1.1中,我们有如下基于路径的身份验证:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    // /api/* path
    app.UseWhen(ctx => IsApiRequest(ctx), subBranch =>
    {
        subBranch.UseApiAuth(GetApiAuthOptions());
    });
    // else
    app.UseWhen(ctx => !IsApiRequest(ctx), subBranch =>
    {
        subBranch.UseOpenIdConnectAuthentication(GetOpenIdOptions());
    });
}
现在我们想将其迁移到ASP.NET核心MVC2.0。在新版本中,身份验证被完全重新设计,而在文档中,我找不到任何关于如何做到这一点的线索。
有没有办法迁移上面的代码?

经过两天的测试和尝试,我找到了一个可行的解决方案

主要问题是,在ASP.NET核心MVC2.0中,身份验证方法注册为服务,而不是中间件。 这意味着它们必须在
ConfigureServices
方法中注册,而不是在
Configure
中注册,因此无法在注册时进行分支以创建分支。 此外,身份验证系统使用
AuthenticationOptions
确定将使用哪种身份验证方法。 从测试中我发现,
AuthenticationOptions
实例是跨请求共享的,因此不能修改它来调整
DefaultScheme
。 经过一些挖掘,我发现了
iaauthenticationschemeProvider
,可以覆盖它来克服这些问题

代码如下:

// Startup.cs
public IServiceProvider ConfigureServices(IServiceCollection services)
{
    [...]

    // Override default IAuthenticationSchemeProvider implementation
    services.AddSingleton<IAuthenticationSchemeProvider, CustomAuthenticationSchemeProvider>();

    // Register OpenId Authentication services
    services.AddAuthentication().AddCookie(this.GetCookieOptions);
    services.AddAuthentication().AddOpenIdConnect(this.GetOpenIdOptions);

    // Register HMac Authentication services (for API)
    services.AddAuthentication().AddHMac(this.GetHMacOptions);

    [...]
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    [...]

    // /api/* path
    app.UseWhen(ctx => IsApiRequest(ctx), subBranch =>
    {
        // Register middleware which will override DefaultScheme; must be called before UseAuthentication()
        subBranch.UseAuthenticationOverride(HMacAuthenticationDefaults.AuthenticationScheme);
        subBranch.UseAuthentication();
    });
    // else
    app.UseWhen(ctx => !IsApiRequest(ctx), subBranch =>
    {
        // Register middleware which will override DefaultScheme and DefaultChallengeScheme; must be called before UseAuthentication()
        subBranch.UseAuthenticationOverride(new AuthenticationOptions
        {
            DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme,
            DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme
        });
        subBranch.UseAuthentication();
    });

    [...]
}
//Startup.cs
公共IServiceProvider配置服务(IServiceCollection服务)
{
[...]
//覆盖默认IAAuthenticationSchemeProvider实现
services.AddSingleton();
//注册OpenId身份验证服务
services.AddAuthentication().AddCookie(this.GetCookieOptions);
services.AddAuthentication().AddOpenIdConnect(this.GetOpenIdOptions);
//注册HMac身份验证服务(适用于API)
services.AddAuthentication().AddHMac(this.GetHMacOptions);
[...]
}
公共void配置(IApplicationBuilder应用程序、IHostingEnvironment环境、iLogger工厂)
{
[...]
///api/*路径
app.UseWhen(ctx=>IsApiRequest(ctx),子分支=>
{
//注册将覆盖DefaultScheme的中间件;必须在UseAuthentication()之前调用
subBranch.UseAuthenticationOverride(HMacAuthenticationDefaults.AuthenticationScheme);
subBranch.UseAuthentication();
});
//否则
app.UseWhen(ctx=>!IsApiRequest(ctx),子分支=>
{
//注册将覆盖DefaultScheme和DefaultChallengeScheme的中间件;必须在UseAuthentication()之前调用
subBranch.UseAuthenticationOverride(新的AuthenticationOptions
{
DefaultScheme=CookieAuthenticationDefaults.AuthenticationScheme,
DefaultChallengeScheme=OpenIdConnectDefaults.AuthenticationScheme
});
subBranch.UseAuthentication();
});
[...]
}
中间件:

// AuthenticationOverrideMiddleware.cs
// Adds overriden AuthenticationOptions to HttpContext to be used by CustomAuthenticationSchemeProvider
public class AuthenticationOverrideMiddleware
{
    private readonly RequestDelegate _next;
    private readonly AuthenticationOptions _authenticationOptionsOverride;

    public AuthenticationOverrideMiddleware(RequestDelegate next, AuthenticationOptions authenticationOptionsOverride)
    {
        this._next = next;
        this._authenticationOptionsOverride = authenticationOptionsOverride;
    }
    public async Task Invoke(HttpContext context)
    {
        // Add overriden options to HttpContext
        context.Features.Set(this._authenticationOptionsOverride);
        await this._next(context);
    }
}
public static class AuthenticationOverrideMiddlewareExtensions
{
    public static IApplicationBuilder UseAuthenticationOverride(this IApplicationBuilder app, string defaultScheme)
    {
        return app.UseMiddleware<AuthenticationOverrideMiddleware>(new AuthenticationOptions { DefaultScheme = defaultScheme });
    }
    public static IApplicationBuilder UseAuthenticationOverride(this IApplicationBuilder app, AuthenticationOptions authenticationOptionsOverride)
    {
        return app.UseMiddleware<AuthenticationOverrideMiddleware>(authenticationOptionsOverride);
    }
}
//authenticationOverrideMidleware.cs
//将覆盖的AuthenticationOptions添加到要由CustomAuthenticationSchemeProvider使用的HttpContext
公共类身份验证重写EMIDware
{
private readonly RequestDelegate\u next;
私有只读身份验证选项\u身份验证选项覆盖;
公共身份验证OverrideMidware(RequestDelegate next,AuthenticationOptions AuthenticationOptions Override)
{
这个。_next=next;
这是。_authenticationOptionsOverride=authenticationoptions override;
}
公共异步任务调用(HttpContext上下文)
{
//将覆盖选项添加到HttpContext
context.Features.Set(this.\u authenticationoptions覆盖);
等待此消息。_下一步(上下文);
}
}
公共静态类身份验证OverrideMidleWareExtensions
{
公共静态IAApplicationBuilder UseAuthenticationOverride(此IAApplicationBuilder应用程序,字符串defaultScheme)
{
返回app.useMidleware(新的AuthenticationOptions{DefaultScheme=DefaultScheme});
}
公共静态IApplicationBuilder UseAuthenticationOverride(此IApplicationBuilder应用,AuthenticationOptions AuthenticationOptions Override)
{
返回app.use中间件(authenticationOptionsOverride);
}
}
CustomAuthenticationSchemeProvider:

// CustomAuthenticationSchemeProvider.cs
// When asked for Default*Scheme, will check in HttpContext for overriden options, and return appropriate schema name
public class CustomAuthenticationSchemeProvider : AuthenticationSchemeProvider
{
    private readonly IHttpContextAccessor _contextAccessor;

    public CustomAuthenticationSchemeProvider(IOptions<AuthenticationOptions> options, IHttpContextAccessor contextAccessor) : base(options)
    {
        this._contextAccessor = contextAccessor;
    }

    // Retrieves overridden options from HttpContext
    private AuthenticationOptions GetOverrideOptions()
    {
        HttpContext context = this._contextAccessor.HttpContext;
        return context?.Features.Get<AuthenticationOptions>();
    }
    public override Task<AuthenticationScheme> GetDefaultAuthenticateSchemeAsync()
    {
        AuthenticationOptions overrideOptions = this.GetOverrideOptions();
        string overridenScheme = overrideOptions?.DefaultAuthenticateScheme ?? overrideOptions?.DefaultScheme;
        if (overridenScheme != null)
            return this.GetSchemeAsync(overridenScheme);
        return base.GetDefaultAuthenticateSchemeAsync();
    }
    public override Task<AuthenticationScheme> GetDefaultChallengeSchemeAsync()
    {
        AuthenticationOptions overrideOptions = this.GetOverrideOptions();
        string overridenScheme = overrideOptions?.DefaultChallengeScheme ?? overrideOptions?.DefaultScheme;
        if (overridenScheme != null)
            return this.GetSchemeAsync(overridenScheme);
        return base.GetDefaultChallengeSchemeAsync();
    }
    public override Task<AuthenticationScheme> GetDefaultForbidSchemeAsync()
    {
        AuthenticationOptions overrideOptions = this.GetOverrideOptions();
        string overridenScheme = overrideOptions?.DefaultForbidScheme ?? overrideOptions?.DefaultScheme;
        if (overridenScheme != null)
            return this.GetSchemeAsync(overridenScheme);
        return base.GetDefaultForbidSchemeAsync();
    }
    public override Task<AuthenticationScheme> GetDefaultSignInSchemeAsync()
    {
        AuthenticationOptions overrideOptions = this.GetOverrideOptions();
        string overridenScheme = overrideOptions?.DefaultSignInScheme ?? overrideOptions?.DefaultScheme;
        if (overridenScheme != null)
            return this.GetSchemeAsync(overridenScheme);
        return base.GetDefaultSignInSchemeAsync();
    }
    public override Task<AuthenticationScheme> GetDefaultSignOutSchemeAsync()
    {
        AuthenticationOptions overrideOptions = this.GetOverrideOptions();
        string overridenScheme = overrideOptions?.DefaultSignOutScheme ?? overrideOptions?.DefaultScheme;
        if (overridenScheme != null)
            return this.GetSchemeAsync(overridenScheme);
        return base.GetDefaultSignOutSchemeAsync();
    }
}
//CustomAuthenticationSchemeProvider.cs
//当询问Default*Scheme时,将在HttpContext中检查覆盖的选项,并返回适当的架构名称
公共类CustomAuthenticationSchemeProvider:AuthenticationSchemeProvider
{
专用只读IHttpContextAccessor\u contextAccessor;
公共CustomAuthenticationSchemeProvider(IOptions选项,IHttpContextAccessor contextAccessor):基本(选项)
{
这._contextAccessor=contextAccessor;
}
//从HttpContext检索重写的选项
私有身份验证选项GetOverrideOptions()
{
HttpContext context=this.\u contextAccessor.HttpContext;
返回上下文?.Features.Get();
}
公共覆盖任务GetDefaultAuthenticateSchemeAsync()
{
AuthenticationOptions overrideOptions=this.GetOverrideOptions();
字符串OverrideScheme=overrideOptions?.DefaultAuthenticateScheme??overrideOptions?.DefaultScheme;
if(overridenScheme!=null)
返回这个.GetSchemeAsync(overridenScheme);
返回base.GetDefaultAuthenticateSchemeAsync();
}
公共覆盖任务GetDefaultChallengeSchemeAsync()
{
AuthenticationOptions overrideOptions=this.GetOverrideOptions();
字符串OverrideScheme=overrideOptions?.DefaultChallengeScheme??overrideOptions?.DefaultScheme;
if(overridenScheme!=null)
返回这个.GetSchemeAsync(overridenScheme);
return base.GetDefaultChallengeSchemeAsync();
}
公共覆盖任务GetDefaultBankeSchemeAsync()
{
AuthenticationOptions overrideOptions=this.GetOverrideOptions();
字符串OverrideScheme=overrideOptions?.DefaultBankeScheme??overrideOptions?.DefaultScheme;
if(overridenScheme!=null)
返回这个.GetSchemeAsync(overridenScheme);
return base.getDefaultBankeSchemeAsync();
}
公共覆盖任务GetDefaultSignInSchemeAsync()
{
鉴定