2017-08-26 92 views
1

我遇到了一個問題,包括在與AspNet Core Identity集成成功登錄到Identity Server 4(IS4)後的角色聲明。這使我無法使用「授權(角色= xxx)」屬性來保護對api的訪問。在Identity Server 4中包含Core Identity角色聲明id_token

我正在關注Identity Server 4/AspNet Identity集成文檔中提供的示例。令人驚訝的是,文檔沒有一個例子來包含角色聲明,我認爲這是一種非常常見的情況。

我按照IS4文檔設置了3個項目,並在主機中指定了HybridClientCredential授權類型,創建了AspNet Identity DB,並將角色(「Admin」)手動添加到由EF Core生成的數據庫中。假如我已經正確設置了一些東西,我預計在成功登錄後,角色會自動包含在用戶聲明中。

  • ASPNET核心(個人認證)/標識服務器(主機)
  • MVC應用程序(客戶端)
  • MVC的Web API(API)

這是我使用的代碼:

主持人:

public class Config 
{ 
    public static IEnumerable<ApiResource> GetApiResources() 
    { 
     return new[] 
     { 
      // expanded version if more control is needed 
      new ApiResource 
      { 
       Name = "api1", 

       Description = "My API", 

       // secret for using introspection endpoint 
       ApiSecrets = 
       { 
        new Secret("secret".Sha256()) 
       }, 

       // include the following using claims in access token (in addition to subject id) 
       UserClaims = { "role" }, 

       // this API defines two scopes 
       Scopes = 
       { 
        new Scope() 
        { 
         Name = "api1", 
         DisplayName = "Full access to API 1", 
         UserClaims = new [] { "role" } 
        } 
       } 
      } 
     }; 
    } 

    public static IEnumerable<IdentityResource> GetIdentityResources() 
    { 
     return new List<IdentityResource> 
     { 
      new IdentityResources.OpenId(), 
      new IdentityResources.Profile() 
     }; 
    } 

    public static IEnumerable<Client> GetClients() 
    { 
     return new List<Client>() 
     { 
      new Client 
      { 
       ClientId = "mvc", 
       ClientName = "MVC Client", 
       AllowedGrantTypes = GrantTypes.HybridAndClientCredentials, 

       RequireConsent = false, 

       ClientSecrets = 
       { 
        new Secret("secret".Sha256()) 
       }, 

       RedirectUris   = { "http://localhost:5002/signin-oidc" }, 
       PostLogoutRedirectUris = { "http://localhost:5002/signout-callback-oidc" }, 
       AlwaysIncludeUserClaimsInIdToken = true, 
       AllowedScopes = 
       { 
        IdentityServerConstants.StandardScopes.OpenId, 
        IdentityServerConstants.StandardScopes.Profile, 
        "api1" 
       }, 
       AllowOfflineAccess = true 
      } 
     }; 
    } 

} 

客戶:

public class Startup 
{ 
    public Startup(IHostingEnvironment env) 
    { 
     var builder = new ConfigurationBuilder() 
      .SetBasePath(env.ContentRootPath) 
      .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) 
      .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true) 
      .AddEnvironmentVariables(); 
     Configuration = builder.Build(); 
    } 

    public IConfigurationRoot Configuration { get; } 

    // This method gets called by the runtime. Use this method to add services to the container. 
    public void ConfigureServices(IServiceCollection services) 
    { 
     // Add framework services. 
     services.AddMvc(); 
    } 

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 
    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) 
    { 
     loggerFactory.AddConsole(Configuration.GetSection("Logging")); 
     loggerFactory.AddDebug(); 

     if (env.IsDevelopment()) 
     { 
      app.UseDeveloperExceptionPage(); 
      app.UseBrowserLink(); 
     } 
     else 
     { 
      app.UseExceptionHandler("/Home/Error"); 
     } 

     app.UseStaticFiles(); 

     app.UseCookieAuthentication(new CookieAuthenticationOptions 
     { 
      AuthenticationScheme = "Cookies" 
     }); 

     JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); 

     app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions 
     { 
      AuthenticationScheme = "oidc", 
      SignInScheme = "Cookies", 

      Authority = "http://localhost:5000", 
      RequireHttpsMetadata = false, 

      ClientId = "mvc", 
      ClientSecret = "secret", 

      ResponseType = "code id_token", 
      Scope = { "api1", "offline_access" }, 

      GetClaimsFromUserInfoEndpoint = true, 
      SaveTokens = true, 

      TokenValidationParameters = new TokenValidationParameters 
      { 
       NameClaimType = JwtClaimTypes.Name, 
       RoleClaimType = JwtClaimTypes.Role, 
      } 
     }); 

     app.UseMvc(routes => 
     { 
      routes.MapRoute(
       name: "default", 
       template: "{controller=Home}/{action=Index}/{id?}"); 
     }); 
    } 
} 

API:

[Route("api/[controller]")] 
[Authorize(Roles="Admin")] 
public class ValuesController : Controller 
{ 
    // GET api/values 
    [HttpGet] 
    public IEnumerable<string> Get() 
    { 
     return new string[] { "value1", "value2" }; 
    } 

    // GET api/values/5 
    [HttpGet("{id}")] 
    public string Get(int id) 
    { 
     return "value"; 
    } 

    // POST api/values 
    [HttpPost] 
    public void Post([FromBody]string value) 
    { 
    } 

    // PUT api/values/5 
    [HttpPut("{id}")] 
    public void Put(int id, [FromBody]string value) 
    { 
    } 

    // DELETE api/values/5 
    [HttpDelete("{id}")] 
    public void Delete(int id) 
    { 
    } 
} 

我的設置除了主機不包括成功登錄後,角色要求的工作。

我想知道是否有人可以幫助讓我知道如何解決這個問題?謝謝。

回答

0

你好,這是我創建定製的策略基於角色的方式,

1)

在配置

- >客戶端部分添加:

Claims = new Claim[] 
{ 
    new Claim("Role", "admin") 
} 

2)

然後在Api - >啓動。CS - > ConfigureServices補充:

services.AddAuthorization(options => 
    { 
     options.AddPolicy("admin", policyAdmin => 
     { 
      policyAdmin.RequireClaim("client_Role", "Admin"); 
     }); 

     //otherwise you already have "api1" as scope 

     options.AddPolicy("admin", builder => 
     { 
      builder.RequireScope("api1"); 
     }); 
    }); 

3)

然後使用這種方式:

[Route("api/[controller]")] 
    [Authorize("admin")] 
    public class ValuesController : Controller 

如果analize令牌你就會有這樣的事情:

{ 
    "alg": "RS256", 
    "kid": "2f2fcd9bc8c2e54a1f29acf77b2f1d32", 
    "typ": "JWT" 
} 

{ 
    "nbf": 1513935820, 
    "exp": 1513937620, 
    "iss": "http://localhost/identityserver", 
    "aud": [ 
    "http://localhost/identityserver/resources", 
    "MySecuredApi" 
    ], 
    "client_id": "adminClient", 
    "client_Role": "admin",  <--------------- 
    "scope": [ 
    "api.full_access", 
    "api.read_only" 
    ] 
} 

PS:

你不能使用 「RequireRole」 因爲Identity Server的4 當您使用:

Claims = new Claim[] 
{ 
    new Claim("Role", "admin") 
}, 

將創建:

client_Role: admin 

但 「RequireRole」 用途:

Role: admin 

所以它不會匹配。

,你可以測試:

using System.Security.Claims; 
MessageBox.Show("" + new Claim("Role", "admin")); 

WITH RequireRole UPDATE:清除 「ClientClaimsPrefix」

在配置

- >客戶端部分添加:

ClientClaimsPrefix = "", 
Claims = new Claim[] 
{ 
new Claim(ClaimTypes.Role, "Admin") 
} 

然後在API - > startup.cs - > ConfigureServices add:

services.AddAuthorization(options => 
{ 
    options.AddPolicy("admin", builder => 
    { 
     builder.RequireRole(new[] { "Admin" }); 
    }); 
}); 

然後使用這種方式:

[Route("api/[controller]")] 
    [Authorize("admin")] 
    public class ValuesController : Controller 

否則不 「政策」 使用這樣的:

[Authorize(Roles = "Admin")]