如何将声明从WS-Federation答复转移到Identity

时间:2018-07-06 05:07:21

标签: asp.net-identity ws-federation asp.net-core-2.1

我对.net core 2.1还是很陌生,我想如果我要构建/重建一个项目,我不妨使用新事物。因此,我一直在与ASP.NET Core身份作斗争一段时间-该文档肯定还有一些不足之处。

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

然后我开始查看授权。首先,我尝试了基于角色的方法,但是我已经知道角色使用不多,而且我无法弄清楚为什么分配给用户的角色未通过授权检查(ClaimsPrincipal.IsInRole和剃刀页面的策略)。

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

在登录过程中中断流程,我可以看到对

的调用
_signInManager.GetExternalLoginInfoAsync()

肯定已经从ADFS获得了预期的要求,但是显然没有考虑到之后发生的一切。

就像我说过的那样,我对它的内部工作方式和TBH都非常模糊,我真的不想深入了解具体问题,我只需要知道我可以根据ADFS的团体声明进行授权。 / p>

我的项目或多或少是标准的默认asp.net core 2.1网站,并选择了个人帐户授权,然后我添加了WS-Federation的修改,并评审了Login操作以直接重定向到ADFS比提示它。

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

如何将来自ADFS的组声明放入ASP.NET Core身份,因此我可以通过以下方式引用它们:

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

此外,请随时指导我错过的任何答案。整天都在阅读文档并在网络上搜索,而今天却没有任何进展!

2 个答案:

答案 0 :(得分:1)

身份正常运行。您刚刚以错误的方式访问了声明。 在Razor页面中尝试以下操作。

@inject UserManager<ApplicationUser> UserManager
@{

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

对于策略,可以在Startup.cs中使用类ClaimTypes来获取众所周知的Claims 例如:

policy.RequireClaim(ClaimTypes.WindowsAccountName));

答案 1 :(得分:0)

要添加更多信息,以下是我最终规避此问题的方法。 ASP.NET Core Identity功能比我想要的/需要的要重得多,并且缺少文档。它还或多或少地从联邦来源劫持了索赔,然后用其自己的值替换了它们。因为我只需要获取ADFS发送的团体声明并将其用于策略中,所以我做了类似的事情:

删除对ASP.NET Core Identity的所有引用。我不记得他们在我头顶上掉了什么,但是找到它们应该很明显。

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联邦中间件和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>
}

很显然,如果您要隐藏页面中的链接/等,则还需要制定一些策略,以防止该用户访问实际链接,因为没有什么可以阻止用户简单地尝试访问任何旧路径。

这就是我实现它的方式。如果有人有任何反馈要告诉我我做错了非常严重的事,我可以接受:)