我正在构建ASP.NET Core(v3.1)模块,而我刚刚设法配置了OpenIdConnect身份验证。现在,我需要从API获取所有用户角色以授予或拒绝访问它们的权限,然后通过OnAuthorizationCodeReceived
事件将多个Claim值添加到用户Claims列表中的同一Claim角色“ ClaimTypes.Role” :
OnAuthorizationCodeReceived = async (context) =>
{
// Uses the authentication code and gets the access and refresh token
var client = new HttpClient();
var response = await client.RequestAuthorizationCodeTokenAsync(new AuthorizationCodeTokenRequest()
{
Address = urlServer + "/connect/token",
ClientId = "hybrid",
Code = context.TokenEndpointRequest.Code,
RedirectUri = context.TokenEndpointRequest.RedirectUri,
}
if (response.IsError) throw new Exception(response.Error);
var identity = new ClaimsIdentity(context.Principal.Identity);
var listRoles = GenericProxies.RestGet<List<string>>(urlGetRoles, response.AccessToken); // GET request to API
listRoles.ForEach(role => identity.AddClaim(new Claim(ClaimTypes.Role, role)));
context.HttpContext.User = new ClaimsPrincipal(identity);
context.HandleCodeRedemption(response.AccessToken, response.IdentityToken);
}
调试时,我注意到所有角色都在此行之后添加到“用户的声明”列表中:
context.HttpContext.User = new ClaimsPrincipal(identity);
但是,显然,在我的Home控制器(经过身份验证的用户将被重定向到的位置)中,当我访问HttpContext.User时,除了“ Admin”之外,我似乎找不到我添加的任何角色。 “(我猜这是默认的ClaimTypes.Role值)。
[Authorize]
public IActionResult Index()
{
if (User.IsInRole("SomeRole"))
{
return RedirectToAction("SomeAction", "SomeController");
}
else
{
return RedirectToAction("Forbidden", "Error");
}
}
[通过阅读其他论坛和主题文章,我发现这可能是一个上下文持久性问题,我试图使用我的Account控制器中的代码来解决:
public async Task Login(string returnUrl = "/")
{
await HttpContext.ChallengeAsync(
"OIDC",
new AuthenticationProperties
{
AllowRefresh = false,
IsPersistent = true,
RedirectUri = returnUrl
});
}
一些示例说我可以使用context.Principal.AddIdentity(identity);
来保留新的Claims列表,但是随后出现以下错误:
InvalidOperationException: only a single identity supported
IdentityServer4.Hosting.IdentityServerAuthenticationService.AssertRequiredClaims(ClaimsPrincipal principal)
总结起来,我必须找到一种方法来保留我添加到“用户的索赔”列表中的角色声明,但是到目前为止我没有成功。
对此进行更新,如果这对任何人都有用。
[我推断问题出在context.HttpContext.User = new ClaimsPrincipal(identity);
上,我以前理解这是处理新声明的持久性的代码的一部分。
实际上,我确实注意到有一个context.Principal
类型的ClaimsPrincipal
属性,并且看起来它是实际的Current上下文,因此我对其进行了研究,并试图找出一种向其“ [ C0]“属性,它是只读的。
一段时间后,我发现以下对我来说很好的解决方案:
代替
IEnumerable<Claim> Claims
我尝试过
var identity = new ClaimsIdentity(context.Principal.Identity);
var listRoles = GenericProxies.RestGet<List<string>>(urlGetRoles, response.AccessToken); // GET request to API
listRoles.ForEach(role => identity.AddClaim(new Claim(ClaimTypes.Role, role)));