如何将声明从 WS-Federation 回复转移到身份中

How to transfer claims from WS-Federation reply into Identity

我是 .net core 2.1 的新手,我想如果我要 build/rebuild 一个项目,我不妨使用这个新东西。所以我一直在与 ASP.NET Core Identity 斗争一段时间 - 文档肯定还有一些不足之处。

我已成功实施身份验证 - 我重定向到我的 ADFS 并再次返回,用户已登录。

然后我开始看Authorization。首先我尝试了 Role-Based 但我读到角色没有太多用处,此外我无法弄清楚为什么分配给用户的角色没有通过授权检查(ClaimsPrincipal.IsInRole 和 razor 页面的策略)。

我决定使用基于声明的授权,认为我可以使用通过 WS-Federation 提供的声明 - 我正在发送一些(名称、名称 ID、电子邮件地址、组),其中组是不合格的作为字符串的组成员列表 - 但是,登录后我没有在 ClaimsPrincipal (HttpContext.User) 上看到任何这些声明。

登录时中断流程我可以看到对

的调用
_signInManager.GetExternalLoginInfoAsync()

肯定从 ADFS 获得了预期的索赔,但显然没有进入之后发生的任何事情。

就像我说的,我对它的内部工作方式很模糊,TBH 我真的不想太深入了解细节我只需要知道我可以根据来自 ADFS 的组声明进行授权.

我的项目或多或少是标准默认 asp.net 核心 2.1 网站,选择了个人帐户授权,然后我添加了对 WS-Federation 的修改,陪审团操纵登录操作直接重定向输出到 ADFS 而不是提示它。

如果您需要澄清,请告诉我,但要点是:

如何将组声明从 ADFS 获取到 ASP.NET Core Identity,以便我可以以这种方式引用它们:

services.AddAuthorization(options =>
            {
                options.AddPolicy("RequireAdminGroup", policy =>
                    policy.RequireClaim("Group", "AD Admin Group Name")
                );
            });

此外,如果我遗漏了任何答案,请随时指导我。一整天都在阅读文档和搜索网络,但今天一点进展都没有!

要添加额外的信息,这是我最终规避问题的方法。 ASP.NET Core Identity 功能比我 wanted/needed 重量级多了很多,而且文档有点欠缺。它还或多或少地劫持了来自联邦源的声明,然后用自己的值替换它们。因为我只需要获取 ADFS 发送的组声明并在策略中使用它们,所以我做了类似的事情:

删除所有对 ASP.NET 核心标识的引用。我不记得它们是什么,但它们应该很容易找到。

services.AddAuthentication(sharedOptions =>
        {
            sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            sharedOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            sharedOptions.DefaultChallengeScheme = WsFederationDefaults.AuthenticationScheme;
        })
        .AddWsFederation(options =>
        {
            options.MetadataAddress = "https://federationservicesurl/";
            options.Wtrealm = "realmname";
            options.SignOutWreply = "https://signoutaddress if you want it";

        })
        .AddCookie(options =>
        {
            options.AccessDeniedPath = "/AccessDenied"; // If you need one
            options.ExpireTimeSpan = TimeSpan.FromMinutes(20); // Or from config
        });

这添加了身份验证选项、ws-federation 中间件和 cookie 以使其正常工作。然后你添加授权:

            services.AddAuthorization(options =>
        {
            // Any Admins
            options.AddPolicy("RequireGroup", policy =>
                policy.RequireClaim("http://schemas.xmlsoap.org/claims/Group", "Group 1", "Group 2")
            );

            //... more policies
        }

最后,您可以使用这些政策。在我的例子中,我使用的是 Razor Pages,所以我只有 AuthorizeFolder/AuthorizePage.

的范围
services.AddRazorPagesOptions(options =>
        {
            options.Conventions.AllowAnonymousToPage("/AccessDenied");
            options.Conventions.AllowAnonymousToPage("/SignedOut");
            options.Conventions.AllowAnonymousToPage("/SignOut");

            options.Conventions.AuthorizeFolder("/Network", "RequireGroup");
            options.Conventions.AuthorizePage("/About", "RequireGroup");

            // ... more directives
        })

这很管用。如果您还想隐藏界面片段,您可以这样做。我再次使用 Razor 而不是纯 MVC,所以我不确定如何以 MVC 方式实现它,但我在顶部的 cshtml 文件中执行此操作:

@inject IAuthorizationService AuthorizationService
@{
    var requiregroup= (await AuthorizationService.AuthorizeAsync(User, "RequireGroup"));
}

然后:

@if (requiregroup.Succeeded)
{
    <div>some content that requires the policy RequireGroup</div>
}

显然,如果您要从页面中隐藏 links/etc,您还需要有策略来阻止该用户访问实际链接,因为没有什么可以阻止用户只是尝试访问任何旧路径。

这就是我实现它的方式。如果有人有任何反馈告诉我我做错了什么,我很乐意接受:)

Identitiy 工作正常。您只是以错误的方式访问了声明。 在 Razor 页面中尝试以下操作。

@inject UserManager<ApplicationUser> UserManager
@{

  var claims = await UserManager.GetClaimsAsync(await UserManager.GetUserAsync(User));
}

对于保单,您可以使用 Startup.cs 中的 class ClaimTypes 来获得众所周知的索赔 例如:

policy.RequireClaim(ClaimTypes.WindowsAccountName));