2017-02-27 31 views
5

Cố gắng xác thực mã thông báo bằng Điểm cuối Introspection trên IdentityServer4. Tôi tiếp tục nhận được 401: Không được phép. đăng nhập của tôi trông như thế này:API Endpoint IdentityServer4 Introspection Endpoint sử dụng thuật toán băm không hợp lệ

dbug: IdentityServer4.EntityFramework.Stores.ResourceStore[0] 
     Found MyAPI API resource in database 
info: IdentityServer4.Validation.HashedSharedSecretValidator[0] 
     Secret: MyAPI API uses invalid hashing algorithm. 
dbug: IdentityServer4.Validation.SecretValidator[0] 
     Secret validators could not validate secret 
fail: IdentityServer4.Validation.ApiSecretValidator[0] 
     API validation failed. 
fail: IdentityServer4.Endpoints.IntrospectionEndpoint[0] 
     API unauthorized to call introspection endpoint. aborting. 

API của tôi được cấu hình như vậy:

new ApiResource 
       { 
        Name = "MyAPI", 
        DisplayName = "My API", 
        ApiSecrets = 
        { 
         new Secret("TopSecret".Sha256()) 
        }, 
       } 

Tôi đang đi qua tiêu đề cho kiểu nội dung như application/x-www-form-urlencoded và ủy quyền như xxxxxxxxxxxxxxxxx cơ bản trong đó x là chuỗi auth được mã hóa base64 của tôi (myapi: TopSecret). Mã thông báo của tôi nằm trong phần nội dung của bài đăng

Tôi đang thiếu gì? Tại sao tôi nhận được "API MyAPI sử dụng thuật toán băm không hợp lệ"? Nếu nó không hợp lệ, thuật toán băm hợp lệ là gì?

Thông tin bổ sung: Tài nguyên của tôi được chứa trong một db SQL được truy cập thông qua khung thực thể. Cụ thể, thiết lập chỉ giống như trong tài liệu hướng dẫn nhanh được tìm thấy here. Để có được đến điểm tôi ở tôi đã phải tự thêm API của tôi vào bảng ApiSecrets và cung cấp cho nó một Type (SharedSecret) và một giá trị, đó là một mật khẩu Sha256.

Trong Startup.cs COnfigureServices tôi bao gồm

services.AddIdentityServer() 
      .AddTemporarySigningCredential() 
      .AddInMemoryApiResources(Configurations.Scopes.GetApiResources()) 
      .AddInMemoryClients(Configurations.Clients.GetClients()) 

      .AddConfigurationStore(builder => 
       builder.UseSqlServer(connectionString, options => 
        options.MigrationsAssembly(migrationsAssembly))) 
      .AddOperationalStore(builder => 
       builder.UseSqlServer(connectionString, options => 
        options.MigrationsAssembly(migrationsAssembly))); 

     // include the password validation routine 
     services.AddTransient<IResourceOwnerPasswordValidator, Configurations.ResourceOwnerPasswordValidator>(); 
     services.AddTransient<IProfileService, Configurations.ProfileService>(); 

     services.AddMvc(); 

Dưới Cấu hình:

app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions 
     { 
      Authority = "http://localhost:5000", 
      RequireHttpsMetadata = false, 
      ApiSecret = "TopSecret", 
      AutomaticAuthenticate = true, 
      AutomaticChallenge = false, 

      ApiName = "MyAPI" 
     }); 

     InitializeDatabase(app); 

     app.UseIdentityServer(); 

     app.UseMvc(); 

Lưu ý rằng tôi đã thêm các ApiSecret, AutomaticAuthenticate và AutomaticChallenge để phần này chỉ sau khi tôi bắt đầu gặp vấn đề trong một nỗ lực để làm cho nó hoạt động.

Trong Scopes.cs của tôi, tôi đã API sau vạch ra:

public static IEnumerable<ApiResource> GetApiResources() 
    { 
     return new[] 
     { 
      new ApiResource 
      { 
       Name = "MyAPI", 
       DisplayName = "My API", 
       ApiSecrets = 
       { 
        new Secret("TopSecret".Sha256()), 
       }, 

      } 
     };    
    } 

Đối Clients.cs:

public static IEnumerable<Client> GetClients() 
    { 
     return new List<Client> 
    { 

     new Client 
     { 
      ClientName = "My Client", 
      AlwaysSendClientClaims=true,     
      ClientId = "MyClient", 
      ClientSecrets = { new Secret("TopSecret".Sha256()) }, 
      RequireClientSecret=false, 
      AllowAccessTokensViaBrowser =true, 
      AllowedGrantTypes = GrantTypes.HybridAndClientCredentials, 
      AllowedScopes = { "MyAPI" }, 
      RequireConsent = false, 
      AllowOfflineAccess = true, 

     }, 

Đó là nhiều hơn hoặc ít hơn tất cả để có phần mã. Cơ sở dữ liệu chứa cấu hình có vẻ như sẽ ghi đè bất kỳ thay đổi mã nào mà tôi thực hiện mặc dù vậy tôi không chắc chắn về việc tất cả những thứ này hữu ích như thế nào. Trong DB, tôi đã tạo một bản ghi trong bảng ApiSecrets với ApiResourceId của 1, thêm mô tả và ngày hết hạn, đặt Type thành "SharedSecret" và thêm Secret bằng các định dạng khác nhau bao gồm văn bản thuần túy, sha256 và base64.

Đây là nhật ký đầy đủ trong suốt cuộc gọi. Có lẽ nó sẽ giúp. Tôi thấy rằng có một số điều về Bearer không được tìm thấy hoặc một cái gì đó như thế nhưng tôi không chắc chắn lý do tại sao đó sẽ là và nếu nó ảnh hưởng đến kết quả của thủ tục.

info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] 
     Request finished in 29.4277ms 401 
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] 
     Request starting HTTP/1.1 POST http://localhost:5000/connect/introspect application/x-www-form-urlencoded 762 
info: IdentityServer4.AccessTokenValidation.Infrastructure.NopAuthenticationMiddleware[7] 
     Bearer was not authenticated. Failure message: No token found. 
dbug: IdentityServer4.CorsPolicyProvider[0] 
     CORS request made for path: /connect/introspect from origin: chrome-extension://aicmkgpgakddgnaphhhpliifpcfhicfo but rejected because invalid CORS path 
info: Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationMiddleware[7] 
     idsrv was not authenticated. Failure message: Unprotect ticket failed 
dbug: IdentityServer4.Hosting.EndpointRouter[0] 
     Request path /connect/introspect matched to endpoint type Introspection 
dbug: IdentityServer4.Hosting.EndpointRouter[0] 
     Mapping found for endpoint: Introspection, creating handler: IdentityServer4.Endpoints.IntrospectionEndpoint 
info: IdentityServer4.Hosting.IdentityServerMiddleware[0] 
     Invoking IdentityServer endpoint: IdentityServer4.Endpoints.IntrospectionEndpoint for /connect/introspect 
dbug: IdentityServer4.Endpoints.IntrospectionEndpoint[0] 
     Starting introspection request. 
dbug: IdentityServer4.Validation.BasicAuthenticationSecretParser[0] 
     Start parsing Basic Authentication secret 
dbug: IdentityServer4.Validation.SecretParser[0] 
     Parser found secret: BasicAuthenticationSecretParser 
dbug: IdentityServer4.Validation.SecretParser[0] 
     Secret id found: MyAPI 
info: Microsoft.EntityFrameworkCore.Storage.IRelationalCommandBuilderFactory[1] 
     Executed DbCommand (0ms) [Parameters=[@__name_0='?' (Size = 200)], CommandType='Text', CommandTimeout='30'] 
     SELECT TOP(1) [apiResource].[Id], [apiResource].[Description], [apiResource].[DisplayName], [apiResource].[Enabled], [apiResource].[Name] 
     FROM [ApiResources] AS [apiResource] 
     WHERE [apiResource].[Name] = @__name_0 
     ORDER BY [apiResource].[Id] 
info: Microsoft.EntityFrameworkCore.Storage.IRelationalCommandBuilderFactory[1] 
     Executed DbCommand (0ms) [Parameters=[@__name_0='?' (Size = 200)], CommandType='Text', CommandTimeout='30'] 
     SELECT [a3].[Id], [a3].[ApiResourceId], [a3].[Type] 
     FROM [ApiClaims] AS [a3] 
     INNER JOIN (
      SELECT DISTINCT TOP(1) [apiResource].[Id] 
      FROM [ApiResources] AS [apiResource] 
      WHERE [apiResource].[Name] = @__name_0 
      ORDER BY [apiResource].[Id] 
    ) AS [apiResource2] ON [a3].[ApiResourceId] = [apiResource2].[Id] 
     ORDER BY [apiResource2].[Id] 
info: Microsoft.EntityFrameworkCore.Storage.IRelationalCommandBuilderFactory[1] 
     Executed DbCommand (0ms) [Parameters=[@__name_0='?' (Size = 200)], CommandType='Text', CommandTimeout='30'] 
     SELECT [a2].[Id], [a2].[ApiResourceId], [a2].[Description], [a2].[Expiration], [a2].[Type], [a2].[Value] 
     FROM [ApiSecrets] AS [a2] 
     INNER JOIN (
      SELECT DISTINCT TOP(1) [apiResource].[Id] 
      FROM [ApiResources] AS [apiResource] 
      WHERE [apiResource].[Name] = @__name_0 
      ORDER BY [apiResource].[Id] 
    ) AS [apiResource1] ON [a2].[ApiResourceId] = [apiResource1].[Id] 
     ORDER BY [apiResource1].[Id] 
info: Microsoft.EntityFrameworkCore.Storage.IRelationalCommandBuilderFactory[1] 
     Executed DbCommand (0ms) [Parameters=[@__name_0='?' (Size = 200)], CommandType='Text', CommandTimeout='30'] 
     SELECT [a].[Id], [a].[ApiResourceId], [a].[Description], [a].[DisplayName], [a].[Emphasize], [a].[Name], [a].[Required], [a].[ShowInDiscoveryDocument] 
     FROM [ApiScopes] AS [a] 
     INNER JOIN (
      SELECT DISTINCT TOP(1) [apiResource].[Id] 
      FROM [ApiResources] AS [apiResource] 
      WHERE [apiResource].[Name] = @__name_0 
      ORDER BY [apiResource].[Id] 
    ) AS [apiResource0] ON [a].[ApiResourceId] = [apiResource0].[Id] 
     ORDER BY [apiResource0].[Id], [a].[Id] 
info: Microsoft.EntityFrameworkCore.Storage.IRelationalCommandBuilderFactory[1] 
     Executed DbCommand (0ms) [Parameters=[@__name_0='?' (Size = 200)], CommandType='Text', CommandTimeout='30'] 
     SELECT [a0].[Id], [a0].[ApiScopeId], [a0].[Type] 
     FROM [ApiScopeClaims] AS [a0] 
     INNER JOIN (
      SELECT DISTINCT [apiResource0].[Id], [a].[Id] AS [Id0] 
      FROM [ApiScopes] AS [a] 
      INNER JOIN (
       SELECT DISTINCT TOP(1) [apiResource].[Id] 
       FROM [ApiResources] AS [apiResource] 
       WHERE [apiResource].[Name] = @__name_0 
       ORDER BY [apiResource].[Id] 
     ) AS [apiResource0] ON [a].[ApiResourceId] = [apiResource0].[Id] 
    ) AS [a1] ON [a0].[ApiScopeId] = [a1].[Id0] 
     ORDER BY [a1].[Id], [a1].[Id0] 
dbug: IdentityServer4.EntityFramework.Stores.ResourceStore[0] 
     Found MyAPI API resource in database 
info: IdentityServer4.Validation.HashedSharedSecretValidator[0] 
     Secret: MyAPI Secret uses invalid hashing algorithm. 
info: IdentityServer4.Validation.HashedSharedSecretValidator[0] 
     Secret: MyAPI Secret uses invalid hashing algorithm. 
dbug: IdentityServer4.Validation.SecretValidator[0] 
     Secret validators could not validate secret 
fail: IdentityServer4.Validation.ApiSecretValidator[0] 
     API validation failed. 
fail: IdentityServer4.Endpoints.IntrospectionEndpoint[0] 
     API unauthorized to call introspection endpoint. aborting. 
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] 
     Request finished in 30.673ms 401 
+0

Có thể bạn có thể xuất bản toàn bộ giải pháp VS của mình để mọi người dễ dàng gỡ lỗi hơn. – Evk

+0

Thật khó để nói nhưng dựa trên mã bạn đăng nó có vẻ như rằng bạn đang sử dụng API của bạn và IdentityServer trong một ứng dụng. Có thể có một sự pha trộn ở đây? Ngoài ra tại sao bạn phải tự thêm một ApiSecret băm? Đã làm sai ở đó sao? Nếu bạn theo tài liệu QS 'InitializeDatabase (ứng dụng);' sẽ chỉ điền vào cơ sở dữ liệu của bạn nếu nó không chứa dữ liệu, đó có thể là lý do thay đổi mã của bạn dường như không có hiệu lực. – user1336

Trả lời

5

Nếu không nhìn thấy từng chi tiết nhỏ của mã và cấu hình cơ sở dữ liệu thì sẽ hơi khó. Ngoài ra, tôi không thấy mã nơi bạn thực sự thực hiện cuộc gọi đến điểm cuối Introspection. Bạn đang làm điều đó trong C# hoặc trong Javascript hoặc với Postman?

Anyways, đây là xem xét của tôi ...

Startup.cs

Phương pháp ConfigureServices có vẻ tốt. Việc thêm dịch vụ trình xác thực mật khẩu ResourceOwner là không cần thiết cho vấn đề đã nêu; để truy cập điểm cuối Introspection, cần ApiSecret, không phải mật khẩu ResourceOwner. Tôi giả sử bạn có nó ở đó vì một số lý do không liên quan, nếu không, sau đó lấy nó ra.

Theo phương pháp cấu hình bạn có app.UseIdentityServerAuthentication có nghĩa là bạn đang sử dụng ứng dụng web không chỉ hoạt động như máy chủ xác thực (sử dụng IdentityServer4), mà còn là ứng dụng Web Api gọi lại máy chủ xác thực (chính nó trong trường hợp này) để xác thực mã thông báo đến.

app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions 
{ 
    Authority = "https://localhost:44388", 
    RequireHttpsMetadata = false, 
    ApiName = "MyAPI" 
    //ApiSecret = "TopSecret" not necessary to know the api secret for normal validation 
    //AutomaticAuthenticate = true, not necessary 
    //AutomaticChallenge = false not necessary 
}); 

Bạn cũng có thể muốn app.UseMvcWithDefaultRoute().

Api InMemory Configurations

Sử dụng new ApiResource("name", "display") constructor sẽ thiết lập cơ sở dữ liệu một cách chính xác; nhưng sử dụng cú pháp khởi tạo đối tượng như bạn đã làm ở trên sẽ không. Đây là vấn đề báo cáo với GitHub: https://github.com/IdentityServer/IdentityServer4/issues/836

public static IEnumerable<ApiResource> GetApiResources() 
{ 
    return new List<ApiResource> 
    { 
     // this will incorrectly leave out the ApiScope record in the database, but will create the ApiResoure and ApiSecret records 
     new ApiResource 
     { 
      Name = "MyAPI", 
      DisplayName = "My API", 
      ApiSecrets = 
      { 
       new Secret("TopSecret".Sha256()), 
      } 
     }, 
     // this will correctly create the ApiResource, ApiScope, and ApiSecret records in the database. 
     new ApiResource("MyAPI2", "My API2") 
     { 
      ApiSecrets = 
      { 
       new Secret("TopSecret2".Sha256()) 
      } 
     } 
    }; 
} 

FYI, vì không có Phạm vi quy định tại các new ApiResources trực tiếp trên, các dụng cụ IdentityServer sẽ autogenerate một ApiScope cho mỗi ApiResource. ApiScore có cùng tên với ApiResource trong trường hợp đó. Một ApiResource phải có ít nhất một ApiScope; nhưng có thể có nhiều. Đó là ApiScopes sau đó có liên quan đến Client trong bảng ClientScopes.

Khách hàng InMemory Cấu hình

Xem bình luận ...

public static IEnumerable<Client> GetClients() 
{ 
    return new List<Client> 
    { 
     new Client 
     { 
      ClientName = "My Client", 
      AlwaysSendClientClaims = true, 
      ClientId = "MyClient", 
      // changed the secret to make clear this is unrelated to the Api secret 
      ClientSecrets = { new Secret("TopSecretClientSecret".Sha256()) }, 
      // RequireClientSecret might as well be true if you are giving this client a secret 
      RequireClientSecret = true, 
      AllowAccessTokensViaBrowser = true, 
      AllowedGrantTypes = GrantTypes.HybridAndClientCredentials, 
      // Added MyAPI2 from my example above 
      AllowedScopes = { "MyAPI", "MyAPI2" }, 
      RequireConsent = false, 
      AllowOfflineAccess = true 
     } 
    }; 
} 

Gọi Mẫn Endpoint

Đoạn mã dưới đây là từ một bộ điều khiển WebAPI. (Hãy nhớ rằng, thẩm quyền IdentityServer và ApiResource được lưu trữ trong cùng một ứng dụng web trong cuộc thảo luận này). Một yêu cầu cho phương pháp này sẽ được thực hiện bởi một khách hàng.

Bên trong phương thức này, bạn có thể thấy nó gọi đến điểm cuối nội suy của thẩm quyền để xác thực/giải mã access_token. Điều này là không cần thiết trong ví dụ này bởi vì chúng tôi thiết lập ứng dụng web thành app.UseIdentityServerAuthentication đã thực hiện điều này. Điểm cuối nội tâm sẽ được sử dụng cho Reference tokens hoặc khi ứng dụng web không có khả năng xác thực access_token.

[Route("api/[controller]/[action]")] 
[Produces("application/json")] 
public class DataController : Controller 
{ 
    [HttpGet] 
    [Authorize] 
    public async Task<IEnumerable<String>> Secure() 
    { 
     var accessToken = await HttpContext.Authentication.GetTokenAsync("access_token"); 

     var introspectionClient = new IntrospectionClient("https://localhost:44388/connect/introspect", "MyAPI", "TopSecret"); 

     var response = await introspectionClient.SendAsync(new IntrospectionRequest { Token = accessToken }); 

     var isActive = response.IsActive; 
     var claims = response.Claims; 

     return new[] { "secure1", "secure2", $"isActive: {isActive}", JsonConvert.SerializeObject(claims) }; 
    } 
} 

Ở đây, việc sử dụng một IntrospectionClient cho ApiScope "MyAPI" sẽ cung cấp cho một 401 vì cơ sở dữ liệu thiếu ApiScope do vấn đề đối tượng initializer đề cập trước đây.

Một điều cuối cùng

Một vấn đề có thể là bằng tay thêm một ApiSecret băm trong trình soạn thảo cơ sở dữ liệu có thể dẫn đến các vấn đề lạ sao chép/dán làm cho văn bản không thể được giải mã đúng.

Xem giải pháp đầy đủ:

https://github.com/travisjs/AspNetCore-IdentityServer-Instrospection

Tôi hy vọng điều này có thể giúp tìm hiểu tường tận về vấn đề này hoặc ít nhất là kích thích một tư tưởng mới.

+0

Đây là câu trả lời ngắn gọn nhất cho đến nay. Rất tiếc, tôi không thể tải giải pháp của bạn vì tôi đã xuống hạng để sử dụng VS2015 cho thời điểm này và dường như giải pháp của bạn sử dụng phiên bản beta 2017 mới. Điều đó sang một bên, tôi đã quản lý để có được một số mã của bạn để làm việc. Dường như tôi đã có cách tiếp cận sai, và để thích nghi với cụm từ của riêng bạn, bạn đã kích thích một số suy nghĩ mới về phía tôi. Rất cảm kích, thưa ngài! – Rafe

+0

@Rất vâng, tôi vừa xây dựng lại máy của mình và quyết định không cài đặt VS 2015; nếu bạn bỏ tất cả mã vào một dự án VS 2015, nó sẽ hoạt động- project.json là sự khác biệt thực sự duy nhất. –

+0

Cảm ơn @ travis.js. Tôi đang trao cho bạn tiền thưởng về điều này. Tôi đã tự hỏi mặc dù nếu nó sẽ được alright nếu tôi gửi email cho bạn trực tiếp về một vấn đề liên quan tôi đang có trên dự án này? – Rafe

0

(myapi: TopSecret). Mã thông báo của tôi nằm trong phần nội dung của bài đăng

Điểm cuối nội soi cần xác thực cơ bản sử dụng scope:apisecret, không phải name:apisecret.

+0

Tôi đã nhập sai, đó thực sự là MyAPI: TopSecret trong đó MyAPI là phạm vi. – Rafe

Các vấn đề liên quan