Авторизация с использованием ролей и нескольких схем аутентификации для каждой пользовательской политики по умолчанию неC#

Место общения программистов C#
Ответить Пред. темаСлед. тема
Гость
 Авторизация с использованием ролей и нескольких схем аутентификации для каждой пользовательской политики по умолчанию не

Сообщение Гость »

Вопрос
Как сделать так, чтобы токены для обеих схем работали с ролями независимо от того, используется ли токен схемы «По умолчанию» или «Вторичный»?

На данный момент любой токен будет работать (ответ 200) для любого API, имеющего .RequireAuthorization(), но будут работать только токены, принадлежащие схеме, определенной DefaultAuthenticateScheme. работают для API, имеющих .RequireAuthorization(a => a.RequireRole(roleName));.

Изменение схемы, DefaultAuthenticateScheme указывает на то, какие токены работают с API, требующими роли Администратора, даже если оба токена имеют эту роль, несмотря на принадлежность к разным схемам.

Так в чем же здесь решение?
Случай воспроизведения Код
Это должно быть все необходимое для воспроизведения проблемы. Токены JWT были созданы с помощью службы тестирования (не волнуйтесь! Утечек учетных данных здесь нет!).

с использованием Microsoft.AspNetCore.Authentication.JwtBearer; использование Microsoft.AspNetCore.Mvc.ApplicationParts; использование Microsoft.IdentityModel.Tokens; используя System.IdentityModel.Tokens.Jwt; использование System.Security.Claims; использование System.Text; пространство имен AuthorizeProblemSample { Программа общественного класса { public static void Main(string[] args) { const string roleName = "Администратор"; const string defaultScheme = «По умолчанию»; const string SecondaryScheme = "Вторичный"; вар строитель = WebApplication.CreateBuilder(args); builder.Services.AddControllers(); builder.Services.AddAuthentication(o => { o.DefaultAuthenticateScheme = defaultScheme; о.DefaultScheme = defaultScheme; }) // Учетные данные JWT, созданные для этого примера с помощью JWT Builder Джейми Курца. // При создании этого образца ни одна учетная запись не пострадала. // Токен схемы по умолчанию: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE2OTUyODkzMjMsImV4cCI6MTcyNjgyNTMyMywiYXVkIjoiZGVmY XVsdEF1ZGllbmNlIiwic3ViIjoidXNlcjFAZXhhbXBsZS5jb20ifQ.SH3mxkdJCjdQ4HUX7sRPLJ2_7baW2OwNhB39fnGduD8 .AddJwtBearer(defaultScheme, o => o.Audience = "defaultAudience") // Токен вторичной схемы: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE2OTUyODkzMjMsImV4cCI6MTcyNjgyNTMyMywiYXVkIjoic2Vjb2 5kYXJ5QXVkaWVuY2UiLCJzdWIiOiJ1c2VyMUBleGFtcGxlLmNvbSJ9.TNamLBog9qxLiebI7F8hu0dX09MjZlGoydKYeDve0ig .AddJwtBearer(вторичнаяScheme, o => o.Audience = "вторичнаяАудиенс"); builder.Services.ConfigureAll(o => { o.TokenValidationParameters = новые TokenValidationParameters() { ВалидатеАктор = ложь, ValidateIssuer = ложь, ValidateIssuerSigningKey = ложь, Валидателайфтайм = ложь, Валидатаудиенс = правда, Валидатетокенреплей = ложь, SignatureValidator = (t, v) => новый JwtSecurityToken (t) }; o.Events = новый JwtBearerEvents() { OnTokenValidated = контекст => { var претензии = context.Principal!.Claims.Append(new Claim(ClaimTypes.Role, roleName)); varclaimsIdentity = new ClaimsIdentity(claims, context.Principal!.Identity!.AuthenticationType, ClaimTypes.Name, ClaimTypes.Role); context.Principal = новый ClaimsPrincipal(claimsIdentity); вернуть Задача.ЗавершеннаяЗадача; } }; }); builder.Services.AddAuthorization(opts => { const string policyName = "myPolicy"; opts.AddPolicy(policyName, policy => { политика.RequireAuthenticatedUser(); policy.AddAuthenticationSchemes(defaultScheme,вторичнаясхема); }); opts.DefaultPolicy = opts.GetPolicy(policyName)!; }); вар приложение = builder.Build(); приложение.UseAuthentication(); приложение.UseRouting(); приложение.UseAuthorization(); app.MapGet("/one", () => "привет").RequireAuthorization(); app.MapGet("/two", () => "world").RequireAuthorization(a => a.RequireRole(roleName)); app.MapGet("/info", (требование HttpRequest) => { результат вар = новый StringBuilder(); result.AppendFormat("Пользователь находится в роли {0}?: {1}", roleName, req.HttpContext.User.IsInRole(roleName)); результат.AppendLine(); result.AppendFormat("Пользователь аутентифицирован?: {0}", req.HttpContext.User.Identity.IsAuthenticated); результат.AppendLine(); var roleClaims = req.HttpContext.User.Claims.Where(c => c.Type == ClaimTypes.Role); foreach (var roleClaim в roleClaims) { result.AppendFormat("Роль: {0}", roleClaim.Value); } вернуть результат.ToString(); }).RequireAuthorization(); приложение.Выполнить(); } } } Как видите, обе схемы работают одинаково, когда речь идет о добавлении роли Администратор к входящим запросам через событие OnTokenValidated.
Шаги по созданию демонстрационного проекта [*]Создайте новый пустой веб-API ASP.NET 7.0 (с использованием операторов верхнего уровня, без необходимости HTTPS или Docker). [*]Добавьте следующие пакеты:
[*]Вставьте весь приведенный выше код в Program.cs [*]Запустите его и сделайте запросы Конечные точки /информация Если вы сделаете запрос на /info с помощью любого токена JWT, вы увидите, что пользователь, которого представляет токен, действительно имеет роль администратора, что он считается прошедшим проверку подлинности, и это единственная роль.

Вывод выглядит следующим образом:

Пользователь находится в роли администратора?: True Пользователь аутентифицирован?: Правда Роль: Администратор /один Любой токен будет работать (ответ 200), когда дело доходит до запроса к /one, предположительно потому, что он не требует проверки ролей. При вызове вы должны получить результат «привет».
/два
/two требует, чтобы у вызывающего была роль Администратор. Поведение, которое вы заметите, заключается в том, что оно работает для токенов, принадлежащих схеме DefaultScheme (ответ 200), но не для токенов, принадлежащих схеме SecondaryScheme (ответ 403).

Но если вы затем измените DefaultAuthenticateScheme = SecondaryScheme, произойдет обратное: /two будет работать для токенов, принадлежащих SecondaryScheme (200 ответ), но не для токенов, принадлежащих DefaultScheme (ответ 403). Вот в этом и проблема.
Примечания [*]Та же проблема возникает таким же образом на неминимальных API, украшенных атрибутами [Authorize] или [Authorize(Roles = "Administrator")], но Здесь я использовал минимум API, чтобы уменьшить размер кода примера. [*]Мне интересно, возможно, мой код в OnTokenValidated на самом деле не работает так, как я ожидаю, но комментирование всего события приводит к тому, что у пользователя, конечно, нет Администратора или любые роли при вызове /info и запрещает оба токена при вызове /two, поэтому очевидно, что это часть кода, которая создает DefaultAuthenticateScheme Токен > успешен при вызове /two. [*]Я не уверен, откуда взялась идея, что это разрешения Windows или какие-либо разрешения ОС. Пользователи — это пользователи уровня приложения, разрешения — это разрешения уровня приложения, предназначенные для управления доступом к определенным функциям API. Хотя мой проект не использует ASP.NET Core Identity, роли основаны на наличии утверждений ролей против аутентифицированного пользователя, и, опять же, роли являются частью домена приложения (см. этот вопрос) о том, как можно создавать роли для тех, кто использует ASP. .NET Core Identity, чтобы лучше понять, что это такое.
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «C#»