AspNet 用户声明丢失
AspNet User Claims Missing
正在研究身份提供者的概念证明,需要帮助理解 aspnet 身份的一些细微差别,特别是与用户声明相关。
我想要完成的事情:
1) 公开一个 MVC 应用程序,该应用程序提供对将公开体育和运动员数据的 2 个微服务之一的安全访问。
2) 允许本地用户帐户和外部帐户(如 google 或 facebook 身份验证)。
当前设置:
1) Asp.Net 利用 Identity Server 4 进行身份验证的 MVC 应用程序。
2) 两个 Web Api 2 个 Web 服务(1 个用于运动,1 个用于运动员)。运动 API 不安全...即...开放 API。运动员 API 虽然应该通过基于策略的授权来保护。
3) Identity Server 4 Web 应用程序,通过 IdentityServer4 nuget 包利用 Entity Framework 和 ASP.NET Identity。
4) SQL 服务器数据库 "fully" 配置为 api 资源、身份资源、客户端、几个具有不同角色和声明的测试用户。
当前有效:
1) 所有用户都可以登录(本地和 google)
2) 声明似乎正在按我的预期加载(仍在努力理解 Identity Server 数据模型中声明 table 的所有关系)。
3) MVC 应用显示 id_token、access_token、refresh_token,然后遍历用户声明并显示这些声明。
什么不起作用:
1) 我认为应该在 mvc 应用程序中显示的所有声明实际上并未显示。
我的意思举例:
1) 在下面的第一个屏幕截图中,您可以看到 given_name 和 family_name 作为用户 "bob" 的声明。这是在 MVC razor 中使用以下代码片段显示的:
@if (User.Identities.First().IsAuthenticated)
{
<h1>Tokens:</h1>
<dt>id token</dt>
<dd>@await ViewContext.HttpContext.GetTokenAsync("id_token")</dd>
<dt>access token</dt>
<dd>@await ViewContext.HttpContext.GetTokenAsync("access_token")</dd>
<dt>refresh token</dt>
<dd>@await ViewContext.HttpContext.GetTokenAsync("refresh_token")</dd>
<br />
<h1>Claims:</h1>
<dl>
@foreach (var claim in User.Claims)
{
<dt>@claim.Type : @claim.Value</dt>
}
</dl>
}
2) 在第二个屏幕截图中,您可以看到身份服务器生成的访问令牌中包含的其他 "claims"。例如,"permission"、"testing"、"role"、"testingroleclaim" 和 "oddball"。
除了几处零散的代码外,大部分代码直接来自 Identity Server 4 文档中的快速入门教程。根据我阅读的所有内容,为了包含自定义声明,您需要实现自己的 IProfileService 接口实例。我已经这样做了,它似乎按预期工作。下面是显示 "other" 声明被加载到调试器中的代码和屏幕截图:
这是数据库 table 及其条目:
1) 身份 Resources/Identity 声明:
2) ApiResources/ApiScopes/ApiScopeClaims
3) AspNetUsers/AspNetRoles/AspNetUserClaims/AspNetRoleClaims/etc
这是我的问题:
1) 为什么在 ProfileService::GetProfileDataAsync 方法中加载的声明不包含在 MVC 显示的 User.Claims 列表中?
更新 1:
1) 我在客户端 table 上为 mvc 应用程序更新了 AlwaysIncludeUserClaimsInIdToken = True。发生了以下事情:a) "oddball" 声明现在显示在 MVC 声明列表的输出中。 b) MVC 应用程序中显示的声明现在包含在 id_token 中,而之前它们没有,但它们仍然不包含 "other" 声明。
更新 2:
1) 我找到了我原来问题的答案。筛选列表的原因是因为以下代码行将根据 RequestedClaimsType 属性 中存在的声明类型进行内部筛选。现在我需要了解为什么该列表中只有 "name"、"given_name" 和 "family_name"。此信息的来源:https://github.com/IdentityServer/IdentityServer4/blob/master/src/IdentityServer4/src/Extensions/ProfileDataRequestContextExtensions.cs
context.AddRequestedClaims(claims);
终于明白我错过了什么。客户端应用程序负责在连接 openid 中间件时设置 OpenIdConnect 选项。选项对象的属性之一称为 "ClaimActions"。这些声明操作允许客户端连接自定义映射属性。这是 ClaimsActions.MapJsonKey property/method 组合的文档:
这是我添加到我的客户端启动程序中的代码 class 以使其适用于一组自动序列化的声明。
services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies")
.AddOpenIdConnect("oidc", options =>
{
options.SignInScheme = "Cookies";
options.Authority = "http://localhost:5000";
options.RequireHttpsMetadata = false;
options.ClientId = "mvc";
options.ClientSecret = "secret";
options.ResponseType = "code id_token";
options.SaveTokens = true;
options.GetClaimsFromUserInfoEndpoint = true;
options.Scope.Add("athlete.full");
options.Scope.Add("rights");
options.Scope.Add("email");
options.Scope.Add("address");
options.Scope.Add("phone");
options.Scope.Add("offline_access");
// These are what allowed the claims to be serialized for front-end consumption.
options.ClaimActions.MapJsonKey(JwtClaimTypes.WebSite, "website");
options.ClaimActions.MapJsonKey(JwtClaimTypes.Gender, "gender");
options.ClaimActions.MapJsonKey(JwtClaimTypes.BirthDate, "birthdate");
});
正在研究身份提供者的概念证明,需要帮助理解 aspnet 身份的一些细微差别,特别是与用户声明相关。
我想要完成的事情:
1) 公开一个 MVC 应用程序,该应用程序提供对将公开体育和运动员数据的 2 个微服务之一的安全访问。
2) 允许本地用户帐户和外部帐户(如 google 或 facebook 身份验证)。
当前设置:
1) Asp.Net 利用 Identity Server 4 进行身份验证的 MVC 应用程序。
2) 两个 Web Api 2 个 Web 服务(1 个用于运动,1 个用于运动员)。运动 API 不安全...即...开放 API。运动员 API 虽然应该通过基于策略的授权来保护。
3) Identity Server 4 Web 应用程序,通过 IdentityServer4 nuget 包利用 Entity Framework 和 ASP.NET Identity。
4) SQL 服务器数据库 "fully" 配置为 api 资源、身份资源、客户端、几个具有不同角色和声明的测试用户。
当前有效:
1) 所有用户都可以登录(本地和 google)
2) 声明似乎正在按我的预期加载(仍在努力理解 Identity Server 数据模型中声明 table 的所有关系)。
3) MVC 应用显示 id_token、access_token、refresh_token,然后遍历用户声明并显示这些声明。
什么不起作用:
1) 我认为应该在 mvc 应用程序中显示的所有声明实际上并未显示。
我的意思举例:
1) 在下面的第一个屏幕截图中,您可以看到 given_name 和 family_name 作为用户 "bob" 的声明。这是在 MVC razor 中使用以下代码片段显示的:
@if (User.Identities.First().IsAuthenticated)
{
<h1>Tokens:</h1>
<dt>id token</dt>
<dd>@await ViewContext.HttpContext.GetTokenAsync("id_token")</dd>
<dt>access token</dt>
<dd>@await ViewContext.HttpContext.GetTokenAsync("access_token")</dd>
<dt>refresh token</dt>
<dd>@await ViewContext.HttpContext.GetTokenAsync("refresh_token")</dd>
<br />
<h1>Claims:</h1>
<dl>
@foreach (var claim in User.Claims)
{
<dt>@claim.Type : @claim.Value</dt>
}
</dl>
}
2) 在第二个屏幕截图中,您可以看到身份服务器生成的访问令牌中包含的其他 "claims"。例如,"permission"、"testing"、"role"、"testingroleclaim" 和 "oddball"。
除了几处零散的代码外,大部分代码直接来自 Identity Server 4 文档中的快速入门教程。根据我阅读的所有内容,为了包含自定义声明,您需要实现自己的 IProfileService 接口实例。我已经这样做了,它似乎按预期工作。下面是显示 "other" 声明被加载到调试器中的代码和屏幕截图:
这是数据库 table 及其条目:
1) 身份 Resources/Identity 声明:
2) ApiResources/ApiScopes/ApiScopeClaims
3) AspNetUsers/AspNetRoles/AspNetUserClaims/AspNetRoleClaims/etc
这是我的问题:
1) 为什么在 ProfileService::GetProfileDataAsync 方法中加载的声明不包含在 MVC 显示的 User.Claims 列表中?
更新 1:
1) 我在客户端 table 上为 mvc 应用程序更新了 AlwaysIncludeUserClaimsInIdToken = True。发生了以下事情:a) "oddball" 声明现在显示在 MVC 声明列表的输出中。 b) MVC 应用程序中显示的声明现在包含在 id_token 中,而之前它们没有,但它们仍然不包含 "other" 声明。
更新 2:
1) 我找到了我原来问题的答案。筛选列表的原因是因为以下代码行将根据 RequestedClaimsType 属性 中存在的声明类型进行内部筛选。现在我需要了解为什么该列表中只有 "name"、"given_name" 和 "family_name"。此信息的来源:https://github.com/IdentityServer/IdentityServer4/blob/master/src/IdentityServer4/src/Extensions/ProfileDataRequestContextExtensions.cs
context.AddRequestedClaims(claims);
终于明白我错过了什么。客户端应用程序负责在连接 openid 中间件时设置 OpenIdConnect 选项。选项对象的属性之一称为 "ClaimActions"。这些声明操作允许客户端连接自定义映射属性。这是 ClaimsActions.MapJsonKey property/method 组合的文档:
这是我添加到我的客户端启动程序中的代码 class 以使其适用于一组自动序列化的声明。
services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies")
.AddOpenIdConnect("oidc", options =>
{
options.SignInScheme = "Cookies";
options.Authority = "http://localhost:5000";
options.RequireHttpsMetadata = false;
options.ClientId = "mvc";
options.ClientSecret = "secret";
options.ResponseType = "code id_token";
options.SaveTokens = true;
options.GetClaimsFromUserInfoEndpoint = true;
options.Scope.Add("athlete.full");
options.Scope.Add("rights");
options.Scope.Add("email");
options.Scope.Add("address");
options.Scope.Add("phone");
options.Scope.Add("offline_access");
// These are what allowed the claims to be serialized for front-end consumption.
options.ClaimActions.MapJsonKey(JwtClaimTypes.WebSite, "website");
options.ClaimActions.MapJsonKey(JwtClaimTypes.Gender, "gender");
options.ClaimActions.MapJsonKey(JwtClaimTypes.BirthDate, "birthdate");
});