我遇到了一个问题,包括成功登录Identity Server 4(IS4)并与AspNet Core Identity集成后的角色声明。这使我无法使用"授权(角色= xxx)"属性以保护对api的访问。
我正在关注Identity Server 4 / AspNet Identity集成文档中提供的示例。令人惊讶的是,文档没有一个示例来包含角色声明,我认为这是一种非常常见的情况。
我根据IS4文档设置了3个项目,主机中指定了HybridClientCredential授权类型,创建了AspNet Identity DB,并将角色(" Admin")手动添加到EF Core生成的数据库中。如果我已正确设置,我希望在成功登录后该角色会自动包含在用户声明中。
这是我正在使用的代码:
主机:
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 :(得分:3)
嗨,这是我创建基于角色的自定义策略的方式,
1)
在Config中 - &gt;客户部分添加:
Claims = new Claim[]
{
new Claim("Role", "admin")
}
2)
然后在Api - &gt; startup.cs - &gt; ConfigureServices add:
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
如果您对该令牌进行分析,您将会遇到以下情况:
{
"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:
你不能使用&#34; RequireRole&#34;因为Identity Server 4 当你使用:
Claims = new Claim[]
{
new Claim("Role", "admin")
},
将创建:
client_Role: admin
但是&#34; RequireRole&#34;用途:
Role: admin
所以它不会匹配。
您可以测试:
using System.Security.Claims;
MessageBox.Show("" + new Claim("Role", "admin"));
使用RequireRole进行更新:清除&#34; ClientClaimsPrefix&#34;
在Config中 - &gt;客户部分添加:
ClientClaimsPrefix = "",
Claims = new Claim[]
{
new Claim(ClaimTypes.Role, "Admin")
}
然后在Api - &gt; startup.cs - &gt; ConfigureServices add:
services.AddAuthorization(options =>
{
options.AddPolicy("admin", builder =>
{
builder.RequireRole(new[] { "Admin" });
});
});
然后以这种方式使用它:
[Route("api/[controller]")]
[Authorize("admin")]
public class ValuesController : Controller
否则没有&#34;政策&#34; 像这样使用:
[Authorize(Roles = "Admin")]