Как сохранить несколько значений ClaimTypes.Role в списке претензий пользователя? - PullRequest
1 голос
/ 20 апреля 2020

Я создаю модуль ASP. NET Core (v3.1), и мне только что удалось настроить аутентификацию OpenIdConnect. Теперь мне нужно получить все роли пользователя из API, чтобы предоставить или запретить доступ к ним, затем я добавил несколько значений утверждений к одной и той же роли утверждений "ClaimTypes.Role" в списке утверждений пользователя через OnAuthorizationCodeReceived Событие, например, так :

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");
    }
}

Читая некоторые другие форумы и темы сообщений, я обнаружил, что это, вероятно, проблема с сохранением контекста, которую я пытался решить с помощью этого кода в контроллере своей учетной записи:

public async Task Login(string returnUrl = "/")
{
    await HttpContext.ChallengeAsync(
        "OIDC",
        new AuthenticationProperties
        {
            AllowRefresh = false,
            IsPersistent = true,
            RedirectUri = returnUrl
        });
}

В некоторых примерах говорилось, что я могу использовать context.Principal.AddIdentity(identity);, чтобы сохранить новый список утверждений, но затем я получил следующую ошибку:

InvalidOperationException: only a single identity supported
IdentityServer4.Hosting.IdentityServerAuthenticationService.AssertRequiredClaims(ClaimsPrincipal principal)

Подводя итог, я должен найти способ выполнить sist утверждения о роли, которые я добавил в список утверждений пользователя, но до сих пор не добились успеха.

1 Ответ

0 голосов
/ 22 апреля 2020

Обновите информацию об этом, если это кому-нибудь пригодится.

Я пришел к выводу, что проблема связана с context.HttpContext.User = new ClaimsPrincipal(identity);, который, как я понял ранее, является частью кода, который обрабатывает постоянство новых утверждений.

На самом деле, я заметил, что есть атрибут context.Principal типа ClaimsPrincipal, и выглядел так, как будто это был текущий контекст Current, поэтому я покопался в нем и попытался найти способ добавить элементы к его атрибуту "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)));

Я пытался

var identity = context.Principal.Identity as ClaimsIdentity;
if(identity != null)
{
    var listRoles = GenericProxies.RestGet<List<string>>(urlGetRoles, response.AccessToken); // GET request to API 
    foreach (var role in listRoles)
    {
        identity.AddClaim(new Claim(ClaimTypes.Role, role));
    }
}
...