2017-04-14 64 views
0

我正在编写IdentityServer4实现并使用快速入门项目here为什么我在IdentityServer4的同意屏幕上看到重复的范围?

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

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

将创建一个名为“API”的范围(这是在ApiResource构造函数中完成的)。如果我在客户端对象上使用“api”作为允许的范围(使用InMemoryClients作为概念证明),并在我的JavaScript客户端的身份验证请求中的作用域查询字符串参数中请求此作用域,我会收到invalid_scope错误消息。

我发现以下this documentation您可以通过作用域属性,像这样

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

添加作用域到ApiResource所以现在,如果我不是定义我ApiResource这样并请求作用域api.read和api.write (并将它们添加到客户端对象上的AllowedScopes属性),那么一切正常,除了显示重复范围的同意页面。它显示了2次api.read和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

+0

你有多少API资源?他们的范围将被复制。请考虑从'/ .well-known/openid-configuration'端点发布'scopes_supported'内容。 –

+0

@IlyaChumakov我发布了它。我绝对只有一个API资源,所以我迷失在为什么会发生这种情况 –

回答

1

它看起来像问题是与快速入门用户界面..或者与Scope.cs类取决于你如何看待它。具体而言,在该方法和线在类ConsentService.cs

以下代码

vm.ResourceScopes = resources.ApiResources.SelectMany(x => x.Scopes).Select(x => CreateScopeViewModel(x, vm.ScopesConsented.Contains(x.Name) || model == null)).ToArray(); 

所示未过滤掉的重复。也就是说,即使两个范围具有相同的名称,但它们并不相同。因此,如果在Scope.cs(它位于IdentityServer4中 - 不是快速入门)中覆盖GetHashCodeEquals,那么它将解决此问题。在这种情况下,SelectMany会返回一个唯一的集合。这是因为ApiResources属性是作为HashSet实现的。或者,您可以编写自己的逻辑,使其返回一组唯一的范围。这就是我解决问题的方法。我写了一些与Jon Skeet在this post中的回答非常相似的东西,它们滤除了重复的范围。

1

问题在于IdentityService4代码在执行InMemoryResourcesStore.FindApiResourcesByScopeAsync中,并且使用此commit修复了此问题。您可以在2017年6月22日以后使用dev分支,但它从未在任何针对.NET Standard 1.4的NuGET软件包中发布,这非常烦人。

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

对于固定的看法,我说标有藤行至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个不需要的范围副本。但至少它是可用的,直到它被修复。