【问题标题】:Can I Combine Identities from two Authentication Schemes in ASP.NET Core 3?我可以在 ASP.NET Core 3 中组合来自两个身份验证方案的身份吗?
【发布时间】:2021-03-02 08:39:24
【问题描述】:

我有一个使用我们组织的 CAS 服务器进行身份验证的 Web 应用程序。我目前正在为此应用程序开发与 DocuSign 的集成。用户将首先访问我们的站点并使用 CAS 登录。然后,他们可以进入应用程序的 DocuSign 区域,登录 DocuSign,然后执行一些与 DocuSign API 相关的功能。这些部分中的每一个都可以在我的应用程序中正常工作。

我当前的问题是我无法同时访问 HttpContext 中的两个身份。我需要 CAS 身份来确定用户行为和对某些功能的访问。我需要 DocuSign 身份来获取启用 API 调用所需的值。在 Startup.cs 中

    services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
       .AddCookie(options =>
       {
          options.LoginPath = new PathString("/Account/Login");
       })
       .AddCAS(options =>
       {
           options.CasServerUrlBase = Configuration["CasBaseUrl"];
           options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
       })
       .AddOAuth("DocuSign", options ->
       {
          //necessary DocuSign options
       });

我有一个 HomeController,它使用 Authorize 属性并且正确地需要 CAS 才能访问。我可以从 CAS 身份正确访问声明。我有一个 DocusignController,我在其中使用 Authorize(AuthenticationSchemes = "DocuSign")。应用于此控制器的 ActionFilter 表明 DocuSign 身份正在正确通过。不幸的是,没有附加 CAS 身份,所以我无法检查管理员权限等内容。我检查了 cookie,发现当我在不同的身份验证方案之间切换时,.AspNetCore.Cookies 值发生了变化。

解决方案的一个尝试是更改 DocusignController 以将 Authorize(AuthenticationSchemes = "DocuSign, CAS" 作为其属性。这似乎是两个方案的“或”而不是“与”。如果 CAS 是最新的方案,那么 CAS 标识就是在我的 ActionFilter 中看到的标识。DocuSign 也是如此。

另一个尝试是创建我自己的 AuthenticationHandler 来组合这两个身份。附加到上面的 AddAuthentication:

    .AddScheme<CombinedSchemeOptions, CombinedHandler>
        ("Combined", op => { });

然后,在这个 CombinedHandler 中:

    protected async override Task<AuthenticateResult> HandleAuthenticateAsync()
    {
        var CasResult = await Context.AuthenticateAsync("CAS");
        if(CasResult?.Principal != null)
        {
            principal.AddIdentities(CasResult.Principal.Identities);
        }
        var DSResult = await Context.AuthenticateAsync("DocuSign");
        if(DSResult?.Principal != null)
        {
            principal.AddIdentities(DSResult.Principal.Identities);
        }
        var ticket = new AuthenticationTicket(principal, "Combined");
        return AuthenticateResult.Success(ticket);
    }

这似乎与以前的行为方式相同。我最近使用的方案,在进入组合方案后,将给出一个带有标识的成功结果,而另一个结果将返回一个失败的结果。

我可以在 HttpContext.User 中同时拥有这两个身份吗?否则我是否可以将来自两个身份的声明合并为一个并将其传递?

【问题讨论】:

    标签: authentication docusignapi claims-based-identity


    【解决方案1】:

    进一步的研究和修补使我找到了解决方案。首先,我发现我需要两个身份验证方案来写入单独的 cookie。然后我确保 DocuSign 方案使用新的 cookie 作为其 SignInScheme。

    .AddCookie("DSCookie")
    .AddOAuth("DocuSign", options =>
    {
       options.SignInScheme = "DSCookie";
       //further DocuSign options
    }
    

    我还了解到 Authorize 标签作为 OR 语句工作(如果您有 CAS OR DocuSign,则您有权执行此操作),但它会传递该方案允许的所有有效身份(您有 CAS 并且您有DocuSign?带上两个身份)。因此,我的解决方案的第二部分有一个需要 DocuSign 身份验证的单一操作,提示必要的挑战。然后,我转向具有两种身份验证方案的操作,并且两种身份都正确携带。

    编辑:根据 Dmitriy 的要求详细说明

    [Authorize(AuthenticationSchemes = "DocuSign")]
    public ActionResult Index()
    {
       return RedirectToAction("Control");
    }
    
    [Authorize(AuthenticationSchemes = "DocuSign,CAS")]
    public ActionResult Control()
    {
       //relevant code
    }
    

    我单击一个链接转到索引操作。由于我目前没有有效的 DocuSign 身份,它会执行必要的提示并将我带到登录屏幕。如果我直接链接到 Control,身份验证会看到我当前拥有一个有效的 CAS 身份,因此会批准我的访问,即使我还没有 DocuSign 身份。

    登录后,当我到达索引功能时,当前只有 DocuSign 身份可用。然后我重定向到控制。该功能验证我至少拥有一个指定的身份,授予我访问权限,并传递我当前拥有的任何列出的身份。因此,在 Control 中,我可以从 CAS 和 DocuSign 中获取信息。

    【讨论】:

    • 请用代码示例描述解决方案的“第二部分”。
    • 你不知道你只写了你需要两个单独的 cookie 对我有多大帮助。我正在努力实现来自不同提供商的两个身份。感谢您回来回答您自己的问题!
    • 我很高兴它有帮助!我很幸运在那一周 StackOverflow 是我的“橡皮鸭”!
    猜你喜欢
    • 2018-02-23
    • 2020-07-27
    • 2021-04-20
    • 2019-08-31
    • 2017-10-03
    • 2020-10-01
    • 2018-02-24
    • 2017-10-29
    • 2020-04-25
    相关资源
    最近更新 更多