为什么我在IdentityServer4的同意屏幕上看到重复的范围?

时间:2017-04-14 20:55:41

标签: identityserver4

我正在编写IdentityServer4实现并使用描述为here的快速入门项目。

定义ApiResource(现在使用InMemory类)时,IdentityServer看起来像创建一个与资源同名的Scope。例如

public static IEnumerable<ApiResource> GetApiResources()
{
    return new List<ApiResource>
    {
        new ApiResource("api", "My API")
    };
}

将创建一个名为&#34; api&#34; (这是在ApiResource构造函数中完成的)。如果我添加&#34; api&#34;作为我的Client对象上的允许范围(使用InMemoryClients进行概念验证)并在我的JavaScript客户端的auth请求中的范围查询字符串参数中请求此api Scope我收到invalid_scope错误消息。

我通过跟随this documentation发现你可以通过Scopes属性将范围添加到ApiResource,如此

new ApiResource
{
     Name = "api",
     DisplayName = "Custom API",
     Scopes = new List<Scope>
     {
          new Scope("api.read"),
          new Scope("api.write")
      }
 }

所以现在如果我改为像这样定义我的ApiResource并请求Scopes api.read和api.write(并将它们添加到客户端对象上的AllowedScopes属性),那么一切正常,除了显示重复范围的同意页面。它显示api.read 2次,api.write 2次。请参见此处的同意屏幕

enter image description here

客户端配置如下:

new Client
{
     ClientId = "client.implicit",
     ClientName = "JavaScript Client",
     AllowedGrantTypes = GrantTypes.Implicit,
     AllowAccessTokensViaBrowser = true,
     RedirectUris = { "http://localhost:3000/health-check" },
     PostLogoutRedirectUris = { "http://localhost:3000" },
     AllowedCorsOrigins =     { "http://localhost:3000" },
     AllowedScopes = {
                        IdentityServerConstants.StandardScopes.OpenId,
                        IdentityServerConstants.StandardScopes.Profile,
                        "customApi.read", "customApi.write"
                     }
}

为什么会这样?我做了一件明显不对的事吗?

更新 这里显示范围的发现文档的一部分仅列出一次......

enter image description here

3 个答案:

答案 0 :(得分:2)

看起来问题出在Quickstart UI上,或者storage\app\public类,这取决于你如何看待它。具体而言,在类ConsentService.cs

中显示的方法和行中

以下代码

Scope.cs

没有过滤掉重复项。也就是说,即使两个Scope具有相同的名称,它们也不被认为是相同的。因此,如果vm.ResourceScopes = resources.ApiResources.SelectMany(x => x.Scopes).Select(x => CreateScopeViewModel(x, vm.ScopesConsented.Contains(x.Name) || model == null)).ToArray(); GetHashCodeEquals(在IdentityServer4中,而不是快速入门)中被覆盖,那么它将解决此问题。在这种情况下,SelectMany将返回一个唯一的集合。这是因为ApiResources属性是作为HashSet实现的。或者,您可以编写自己的逻辑,以使其返回一组唯一的范围。这就是我解决问题的方法。我写了一些与Jon Skeet在this post中的答案非常类似的东西,它过滤掉了重复的范围。

答案 1 :(得分:1)

问题在于InMemoryResourcesStore.FindApiResourcesByScopeAsync实现中的IdentityService4代码,并且已使用此commit修复。您可以使用自2017年6月22日起包含的dev分支,但它从未在任何针对.NET Standard 1.4的NuGET包中发布,这非常令人讨厌。

我创建了一个问题,并要求修补它: https://github.com/IdentityServer/IdentityServer4/issues/1470

为了修复视图,我将标有Todo的行添加到ConsentService.cs

var resources = await _resourceStore.FindEnabledResourcesByScopeAsync(request.ScopesRequested);
if (resources != null && (resources.IdentityResources.Any() || resources.ApiResources.Any()))
{
    // TODO: Hotfix to cleanup scope duplication:
    resources.ApiResources = resources.ApiResources.DistinctBy(p => p.Name).ToList();
    return CreateConsentViewModel(model, returnUrl, request, client, resources);
}

这解决了显示问题,但范围仍将在访问令牌中多次包含,这使得它更大,因为它平方化该API的范围计数。我有3个范围,因此每个范围包含3次,添加了6个不需要的范围副本。但至少在它得到解决之前它是可用的。

答案 2 :(得分:0)

在1.5中修复了一个错误,解决了这个问题:https://github.com/IdentityServer/IdentityServer4/pull/1030。请升级,看看是否能解决问题。感谢。