Adr*_*ian 10 asp.net-identity identityserver4
在成功登录到与 AspNet Core Identity 集成的 Identity Server 4 (IS4) 后,我遇到了一个问题,包括角色声明。这会阻止我使用“Authorize(Roles=xxx)”属性来保护对 api 的访问。
我正在遵循 Identity Server 4/AspNet Identity 集成文档中提供的示例。令人惊讶的是,文档没有包含角色声明的示例,我认为这是一个非常常见的场景。
我根据 IS4 文档使用主机中指定的 HybridClientCredential 授权类型设置了 3 个项目,创建了 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
}
};
}
}
Run Code Online (Sandbox Code Playgroud)
客户:
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?}");
});
}
}
Run Code Online (Sandbox Code Playgroud)
接口:
[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)
{
}
}
Run Code Online (Sandbox Code Playgroud)
除了主机在成功登录后不包括角色声明之外,我的设置工作正常。
我想知道是否有人可以帮助我知道如何解决这个问题?谢谢。
Ang*_*Sky 10
Hi this is the way I create custom Policy role-based,
1)
in Config -> Client section add:
Claims = new Claim[]
{
new Claim("Role", "admin")
}
Run Code Online (Sandbox Code Playgroud)
2)
Then in the Api -> startup.cs -> 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");
});
});
Run Code Online (Sandbox Code Playgroud)
3)
Then use it this way:
[Route("api/[controller]")]
[Authorize("admin")]
public class ValuesController : Controller
Run Code Online (Sandbox Code Playgroud)
If you analize the token you'll have something like this:
{
"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"
]
}
Run Code Online (Sandbox Code Playgroud)
PS:
you cannot use "RequireRole" because Identity Server 4 when you use:
Claims = new Claim[]
{
new Claim("Role", "admin")
},
Run Code Online (Sandbox Code Playgroud)
will create:
client_Role: admin
Run Code Online (Sandbox Code Playgroud)
but "RequireRole" uses:
Role: admin
Run Code Online (Sandbox Code Playgroud)
so it won't match.
As you can test:
using System.Security.Claims;
MessageBox.Show("" + new Claim("Role", "admin"));
Run Code Online (Sandbox Code Playgroud)
UPDATE WITH RequireRole : Clear "ClientClaimsPrefix"
in Config -> Client section add:
ClientClaimsPrefix = "",
Claims = new Claim[]
{
new Claim(ClaimTypes.Role, "Admin")
}
Run Code Online (Sandbox Code Playgroud)
Then in the Api -> startup.cs -> ConfigureServices add:
services.AddAuthorization(options =>
{
options.AddPolicy("admin", builder =>
{
builder.RequireRole(new[] { "Admin" });
});
});
Run Code Online (Sandbox Code Playgroud)
Then use it this way:
[Route("api/[controller]")]
[Authorize("admin")]
public class ValuesController : Controller
Run Code Online (Sandbox Code Playgroud)
Otherwise without the "Policy" use like this:
[Authorize(Roles = "Admin")]
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
10047 次 |
| 最近记录: |