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

2023-12-28

在 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。在新版本中,身份验证被完全重新设计,并且在文档中我没有找到任何如何做到这一点的线索。 有什么想法如何迁移上面的代码吗?


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

主要问题是,在 ASP.NET Core MVC 2.0 中,身份验证方法被注册为服务而不是中间件。 这意味着它们必须在ConfigureServices方法而不是在Configure,因此无法在注册时进行分支来创建分支。 此外,auth系统使用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.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();
    }
}

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ASP.NET Core MVC 2.0 中基于路径的身份验证 的相关文章

  • 在字段更改时显示 asp-validation-summary

    使用 ASP NET Core 不显眼的客户端验证 我想在字段更改时显示验证摘要 不仅仅是在表单提交上 The div div 元素在表单提交时显示每个字段的相关错误消息 但在字段修改时 且修改状态无效 则不显示 这是我的示例代码 我的型号
  • 使用 Windbg 调试 .NET 转储

    我对 NET 进程进行了转储 使用 ma 选项和 procdump exe 中的高 CPU 触发器 并且希望在正在运行的线程中查看有关我的代码正在执行的操作的线索 我明白了 procdump ma c 65 s 2 n 3 service
  • 连接到 SQL Server 数据库 C#-WinForms

    我正在制作一个桌面应用程序 我希望用户必须登录才能充分使用该程序 我已经在 www winhost com 我的网站的托管位置 上创建了一个数据库 但现在我不知道该怎么办 我一直在使用 google 和 msdn 我想知道如何以编程方式将新
  • 在 C# 中实例化 python 类

    我已经用 python 编写了一个类 我想通过 IronPython 将其包装到 net 程序集中 并在 C 应用程序中实例化 我已将该类迁移到 IronPython 创建了一个库程序集并引用了它 现在 我如何真正获得该类的实例 该类看起来
  • .NET 表适配器:获取与填充?

    在处理数据库中的数据 强类型或其他方式 时 我似乎总是使用 Get 并且我从未真正需要使用 Fill 尽管在提取和更新数据时我可以轻松地使用 Fill 而不是 get 任何人都可以提供有关每种方法的含义和陷阱的指导吗 在什么情况下最好使用其
  • WCF 版本控制枚举

    我开始编写一些需要向前兼容和版本控制的 WCF 数据协定 我一直在阅读 MSDN 文章here http msdn microsoft com en us library ms733832 aspx 并且想知道是否有人对有关枚举的第 14
  • 是否可以在 html 中将单选按钮标签助手值属性设置为“已选中”?

    我正在寻找一种方法来使用单选按钮标签帮助器上的值属性来通知按钮是否被选中 而不是使用单独的字段进行选择 我找到了 Shyju 的答案相关问题 https stackoverflow com questions 34570908 radio
  • C# 暴露给 COM - 接口继承

    假设我有一个实现 IBaseClass 的类 BaseClass 然后我有一个继承IBaseClass的接口IClass 然后我有一个名为 class 的类 它实现了 IClass 例如 ComVisible true InterfaceT
  • 如何避免由于 DI 容器绑定要求而导致 BAL 依赖于 DAL?

    我的应用程序由三个项目组成 核心 DAL 和 BAL 核心包含域对象 客户 订单 产品 它还包含基本的 IRepository 接口 IRepository
  • 将 ASP.NET Intranet 应用程序与 Outlook 日历集成的技术

    我不能再忽视用户的叫喊声了 他们想要一个任务调度系统 而在某些时候我必须交付 我正在考虑制作自己的系统 并不难 但是用户将拥有两个并行的任务管理系统 因为他们已经使用 Outlook 来完成相同的事情 在 Outlook 日历 任务集成方面
  • 身份验证后以编程方式添加角色

    我有以下 JSF 2 1 登录表单 在 Glassfish 3 1 中运行
  • 向父进程发出信号,表明子进程已完全初始化

    我正在启动一个公开 WCF 端点的子进程 如何从子进程向父进程发出信号 表明子进程已完全初始化并且现在可以访问端点 我曾考虑过使用信号量来实现此目的 但不太清楚如何实现所需的信号 string pipeUri net pipe localh
  • 身份验证后如何退出 Google

    所以我的应用程序可以选择使用 Google 登录 单击 Google 提供的按钮后 将打开一个 Web 视图并让用户输入其凭据 允许应用程序访问其信息后 应用程序将用户登录并将 SignInViewController 更改为 TabBar
  • 我应该更喜欢 C# 中的静态方法吗

    在花了一些时间学习函数式编程之后 我越来越自然地想要使用不执行任何突变的静态方法 我有什么理由应该抑制这种本能吗 我觉得这个问题有点奇怪 因为静态方法和不执行突变的方法是方法的两个正交分类 您可以拥有可变静态方法和非可变实例方法 对我来说
  • System.Threading._IOCompletionCallback.PerformIOCompletionCallback(...) 处的 System.AccessViolationException

    使用 Net Framework 4 我在多线程 C 代码中遇到 System AccessViolationException 即使我的所有代码都是托管代码 这可能是 Net 中的一个错误吗 因为我一直认为使用 Net 意味着无论我犯什么
  • 从 SQL XML 列中的元素获取属性名称

    对于此 xml 在 SQL 2005 XML 列中
  • 在wince上用c#静默运行命令行程序

    我再次需要一些帮助 我使用 net Compact Framework 和编程语言 C 来为运行 WinCE 5 0 的移动设备进行开发 我想要完成的是以编程方式安装网络驱动器 为此 应用程序在后台线程中运行以下代码 ProcessStar
  • 禁止显示“资源名称不是有效标识符”

    我有一个包含 5000 多个资源字符串的项目 几乎所有的标识符中都有句点 我们正在切换到自动生成强类型类 当然 由于周期的原因 我们看到了几千条警告 资源名称 blah 不是有效的标识符 我知道不是 生成器将句点更改为下划线 一切都很好 我
  • 批准后使用 jenkinsfile 构建促销

    仅当更改管理使用 servicenow 更改票证或通过手动批准批准它时 我才需要使用 jenkins 文件将我的构建升级到生产 我想要类似的东西 产品构建只有在经理批准后才能手动触发 他 她应该收到带有批准 拒绝链接的批准邮件 或者 如果与
  • Django:登录用户并在同一页面上刷新而不定义模板?

    我正在尝试使用引导下拉登录表单来让用户登录 我可以对我的用户名和密码进行硬编码并进行身份验证 但我试图在不进入登录屏幕的情况下让用户登录 这是我的代码 模板 我使用操作来调用 logUserIn url 以便表单可以发布到该视图 ul cl

随机推荐

  • getMapAsync 错误 - Google 地图 api android

    因此 我尝试从 Json 文件在地图上显示标记 但它们没有出现 我已将其范围缩小到该行 map mapFragment getMapAsync this 它给了我错误 不兼容的类型 必需 com google android gms map
  • 在 Mac OS X 上使用 PCL(点云库)生成项目

    我按照其建议安装了所有依赖项和预编译的 PCL 库site http pointclouds org downloads macosx html 安装完所有内容后 我想生成一个项目如下this http pointclouds org do
  • GAE开发服务器重启后保留全文搜索索引吗?

    是否有办法强制 GAE 开发服务器在重新启动后保留全文搜索索引 我发现每当开发服务器重新启动时索引都会丢失 当我启动开发服务器时 我已经在使用静态数据存储路径 datastore path选项 此功能是在几个版本之前添加的 我认为是在 1
  • 我的项目在 IntelliJ IDEA 中的文件夹层次结构有什么问题吗?

    今天 当我打开我的项目时 我的文件夹层次结构出现了一些问题 您可以看到下面的内容 这里没有包 一般来说 公共文件夹层次结构应该是这样的 EDIT 我尝试重新打开该项目并重新打开我的 IntelliJ IDEA 两者都不起作用 Delete
  • 将坐标转换为城市名称?

    如何使用 MapKit 从坐标获取地址 我有这个代码 当长按地图时它会获取坐标 func didLongPressMap sender UILongPressGestureRecognizer if sender state UIGestu
  • 尝试同时编译多个 CUDA 文件时出现链接错误 LNK2005

    我有一个 CUDA 程序 可以正常工作 但目前全部写在一个文件中 我想将这个大文件分成几个较小的文件 以便更容易维护和导航 新的结构是 foo cuh foo cu bar cuh bar cu main cu The cuh头文件包含结构
  • 我想在 Yup 中转换值,但 Formik 没有返回正确的值

    我在表单 电子邮件 中有一个值 我想将其转换为小写 我在 Yup 中有一个转换正在工作 但 Formik 没有显示小写值 如何才能使当我以大写形式输入电子邮件时 它会自动转换为小写形式 这是我的代码 import React from re
  • 无法终止 SPID“事务回滚正在进行中”

    我的数据库中有一条处于永久回滚模式的未提交语句 当我尝试终止与此语句关联的 SPID 时 出现以下错误 事务回滚正在进行中 预计回滚完成 0 预计剩余时间 0 秒 此未提交的语句导致用户无法查看数据库的表 视图和过程树 如何停止这个 SPI
  • 在运行时加载 MP3 文件

    我正在尝试使用在运行时加载 mp3 文件WWW http docs unity3d com ScriptReference WWW htmlUnity中提供的类 我没有收到任何错误 但在处理歌曲后我无法播放音乐 我到处都找过了 但找不到任何
  • 在构造函数中设置变量数组的最小大小

    因此 我的编程教授希望我编写一个 Kingdom 类 其变量名至少有 12 个字符长 通常情况下 如果最小 12 个字符的不变量被破坏 人们只需使用 String 名称变量和错误消息来实现此类 就像 Java 中的这样 import jav
  • 马尔可夫链聊天机器人如何工作?

    我正在考虑使用马尔可夫链之类的东西创建一个聊天机器人 但我不完全确定如何让它工作 据我了解 您可以根据给定单词和后面的单词的数据创建一个表格 在训练机器人时是否可以附加任何类型的概率或计数器 这是个好主意吗 问题的第二部分是关键字 假设我已
  • lldb:异常断点(相当于gdb的catch throw)

    我正在尝试使用 lldb 进行 C 调试 如果抛出异常 我想停止 就像 gdb 的那样catch throw 并且我在 lldb 文档中找不到等效项 Use breakpoint set E c 打破所有异常并且breakpoint set
  • 将 JScrollPane 添加到 JLabel

    我似乎不知道如何添加JScrollPane to a JLabel The JLabel我正在使用的是一个长格式的 HTML 字符串 请帮忙 area new JLabel JScrollPane scroller new JScrollP
  • 如何运行指向 jar 的 TestNG 测试

    我有一个 Jar文件包含在 TestNG 测试上运行所需的文件 我想在该 Jar 文件中运行特定的 xml 文件 我的要求是是否可以执行指向 Jar文件如果是的话我该怎么做 您可以使用 xmlpathinjar suites GroupBa
  • 如何确定谁更改了文件?

    在 Windows 中 如何以编程方式确定上次更改或删除文件的用户帐户 我知道设置对象访问审核可能是一个选项 但如果我使用它 我就会遇到尝试将审核日志条目与特定文件匹配的问题 听起来复杂而混乱 我想不出任何其他方法 那么有人对这种方法或任何
  • 如何获取 PowerShell 字符串中最后一次出现的字符的索引?

    我想从 PowerShell 中的以下字符串获取最后一个 出现的索引 以便修剪 Activity 单词并保留它 string C cmb Trops TAX Auto Activity 我正在将代码从 VBScript 转换为 PowerS
  • 从 IEnumerable 中的任意点访问一系列元素

    我有这个方法 private IEnumerable
  • Laravel Jobs 不允许序列化“Closure”

    我想将数据发送到 NewsletterStore 作业 但它因以下错误而失败 有什么建议么 我还尝试删除 SerializesModels Models 特征 没有任何成功 Error Exception Serialization of
  • 如何在 Julia 中逐行读取文件?

    如何打开文本文件并逐行读取它 我对两种不同情况的答案感兴趣 一次获取数组中的所有行 一次处理每一行 对于第二种情况 我不想一次将所有行保留在内存中 将文件作为行数组一次性读入内存只需调用readlines功能 julia gt words
  • ASP.NET Core MVC 2.0 中基于路径的身份验证

    在 ASP NET Core MVC 1 1 中 我们有基于路径的身份验证 如下所示 public void Configure IApplicationBuilder app IHostingEnvironment env ILogger