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.UseApiAuth(GetApiAuthOptions());
    });
    // else
    app.UseWhen(ctx => !IsApiRequest(ctx), subBranch =>
    {
        subBranch.UseOpenIdConnectAuthentication(GetOpenIdOptions());
    });
}

现在,我们希望将其迁移到ASP.NET Core MVC 2.0。在新版本中,身份验证已完全进行了重新设计,而在文档中,我没有找到执行此操作的任何线索。任何想法如何迁移上面的代码?

克里斯托弗

经过2天的测试和尝试,我提出了可行的解决方案。

主要问题是,在ASP.NET Core MVC 2.0中,身份验证方法被注册为服务而不是中间件。这意味着它们必须在ConfigureServicesmethod中而不是in中注册Configure,因此无法在注册时进行分支以创建分支。此外,身份验证系统用于AuthenticationOptions确定将使用哪种身份验证方法。从我的测试中发现,该AuthenticationOptions实例在请求之间共享,因此无法对其进行修改以进行调整DefaultScheme经过一番挖掘,我发现了IAuthenticationSchemeProvider,可以将其重写以克服这些问题。

这是代码:

// 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();
    });

    [...]
}

中间件:

// 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);
    }
}

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();
    }
}

如果有人知道更好的解决方案,我很乐意看到它。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

ASP.NET Core 2.0中基于MVC的身份验证模板

Asp.Net Core 2 中基于令牌的身份验证

ASP.NET Core中基于令牌的身份验证

Auth0 与 .Net Core ASP MVC 到 WebAPI 身份验证

基于令牌的身份验证 - Angular 2 + ASP.NET MVC/WebAPI + C#

ASP.NET Core MVC 中的 cookie 身份验证有问题

mvc 到 net core 2 迁移身份验证

ASP.NET Core 2身份验证方案

关闭ASP.NET MVC Core 2 OpenIdConnect中的AutomaticChallenge

在.Net Core 2.x MVC应用程序中配置Windows AD身份验证

ASP.NET Core 2中不同区域的身份验证和LoginPath

如何在ASP.NET Core 2中对Facebook Web API进行身份验证

如何在ASP.NET Core 2中添加身份验证Cookie超时

使用 ASP.Net Core 2 中的 cookie(无 DB)进行 Google 身份验证

在 Asp.Net Core 中实现自定义的 2 因素身份验证机制

在ASP.NET MVC中显示基于身份验证状态的视图

ASP.NET Core中基于令牌的身份验证(刷新)

如何在ASP.NET Core 2.0中基于路由配置服务身份验证

基于多租户Asp.net Core网站中参数的JWT身份验证

ASP.NET Core MVC MySQL身份

动态验证基于非MVC Asp.Net Core 2.x中的Authorization标头方案

如何使用 Windows 身份验证向 ASP.NET Core (MVC) 中的特定用户发送 SignalR 通知?

如何在ASP .NET MVC Core中注销Facebook之类的外部身份验证方案?

ASP.NET Core 1.1-使用“登录”屏幕的Windows身份验证(MVC视图)

Identity Server 4 与 ASP.NET Core MVC 进行身份验证然后调用 Angular SPA

是否可以在空的ASP.NET Core Mvc项目中打开身份验证?

JWT身份验证ASP.NET Core MVC应用程序

ASP.NET Core中的多种身份验证方案

ASP.NET Core中的承载令牌身份验证