Политика авторизации всегда возвращает 403 (запрещено) - MVC / API - PullRequest
0 голосов
/ 14 мая 2018

Я создал API (.Net Core 2 с EF Core) с конечной точкой для получения определенных ролей.Я интегрировал ASPNetIdentity в свой проект и использую AspNetRoles и AspNetRoleClaims.

При вызове API в моем случае пользователь играет определенную роль (Admin).Эта роль имеет несколько ролевых претензий.В файле startup.cs я добавил политики для этой роли:

   options.AddPolicy(
      "Create Roles", policy => policy.RequireClaim("Can create roles", "role.create"));
   options.AddPolicy(
      "View Roles", policy => policy.RequireClaim("Can read roles", "role.read"));
   options.AddPolicy(
      "Edit Roles", policy => policy.RequireClaim("Can update roles", "role.update"));
   options.AddPolicy(
      "Delete Roles", policy => policy.RequireClaim("Can delete roles", "role.delete"));

В моем веб-интерфейсе пользователи могут войти в систему со своей учетной записью Microsoft (azure), а их утверждение oidc (ID) совпадает с идентификатором в таблице AspNetUser,если их oidc не найден в пользовательской таблице, они автоматически добавляются (с их идентификатором oidc в качестве идентификатора aspnetuser) и получают роль по умолчанию.

Однако при вызове конечной точки роли всегда возвращается 403ошибка (запрещено).Когда я проверяю таблицы, пользователь имеет право на роль и утверждения роли для доступа к конечной точке.Как это возможно, что он продолжает возвращать 403?

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

[HttpGet]
[Authorize(Policy = "View Roles")]
public IEnumerable<IdentityRole> GetRole()
{
     return _context.Roles;
}

После некоторого исследования я нашел пост, в котором говорится, что вам нужно включить роль (утверждение) пользователя в отправляемый токендля API, хотя это будет означать, что мне понадобится конечная точка GET, которая сначала возвращает роль (и) пользователя, внешнему интерфейсу нужно подобрать ее и добавить в токен, а затем вызвать все остальные конечные точки с рольювключен в токен?Или я не на том пути?

---- ОБНОВЛЕНИЕ ----

Я на 90% уверен, что проверка политики / авторизации требует включения заявки о роли в токен пользователя,Однако сейчас процесс выглядит следующим образом:

  1. Пользователь переходит в проект внешнего интерфейса (реагирует на внешний интерфейс).
  2. Внешний интерфейс использует adal.js для проверки подлинности пользователя,если он не аутентифицирован, то пользователь перенаправляется на страницу входа Microsoft.
  3. После успешного входа в систему вызывается API.
  4. В DI (AddJwtBearer) API утверждение oid сравнивается с идентификатором таблицы ASpNetUsers, если оноотсутствует, пользователь добавляется в таблицу AspNetUser, используя значение oid для идентификатора AspNetUser.

Теперь, когда пользователь также добавлен в таблицу AspNetUser, я могу использовать удостоверение Asp.Net для выполнения авторизации с использованием ролей и RoleClaims.

Проблема, однако, заключается в том, что исходный полученный токен API является токеном Azure, который ничего не знает о моих таблицах идентификаторов (исправьте меня, если я ошибаюсь).Я считаю, что это также является причиной того, что моя политика не работает (опять же, поправьте меня, если я ошибаюсь).

Я нашел сообщение, где проблема более или менее та же (https://joonasw.net/view/adding-custom-claims-aspnet-core-2),хитрость заключается в том, чтобы расширить текущий токен с помощью моих необходимых утверждений Identity, таких как ClaimTypes.Role.

Мой код для достижения этой цели выглядит следующим образом:

// Add authentication (Azure AD)
            services
                .AddAuthentication(sharedOptions =>
                {
                    sharedOptions.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
                    sharedOptions.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; 
                    sharedOptions.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; // Use JWT as ChallendgeSchema, if not, ASPNet Identity will be used by default and this will return a default non-existing endpoint (because it is not created): Account/Login; https://stackoverflow.com/questions/45878166/asp-net-core-2-0-disable-automatic-challenge
                })
                .AddJwtBearer(options =>
                {
                    options.Audience = this.Configuration["AzureAd:ClientId"];
                    options.Authority = $"{this.Configuration["AzureAd:Instance"]}{this.Configuration["AzureAd:TenantId"]}";

                    // Added events which checks if the user (token user) exists in our own database, if not then the user is being added with a 'User' role
                    options.Events = new JwtBearerEvents()
                    {
                        OnTokenValidated = context =>
                        {
                            // Check if roles are present
                            CheckRoles cr = new CheckRoles();
                            cr.CreateRoles(services.BuildServiceProvider());

                            // Check if the user has an OID claim(oid = object id = user id)
                            if (!context.Principal.HasClaim(c => c.Type == "http://schemas.microsoft.com/identity/claims/objectidentifier")) 
                            {
                                context.Fail($"The claim 'oid' is not present in the token.");
                            }

                            ClaimsPrincipal userPrincipal = context.Principal;

                            CheckUser cu = new CheckUser();

                            cu.CreateUser(userPrincipal, services.BuildServiceProvider());

                            // Extend the current token with my (test) Role claim
                            var claims = new List<Claim>
                            {
                                new Claim(ClaimTypes.Role, "Admin")
                            };
                            var appIdentity = new ClaimsIdentity(claims);
                            context.Principal.AddIdentity(appIdentity);


                            return Task.CompletedTask;
                        }
                    };
                });

К сожалению, вышеприведенное не работает, когдапри вызове API из внешнего интерфейса токен остается неизменным, а RoleClaim не добавляется. У кого-нибудь есть подсказка, как добавить мой RoleClaim в токен, чтобы я мог использовать свои политики?

1 Ответ

0 голосов
/ 14 мая 2018

При вызове API в моем случае пользователь играет определенную роль (Admin).Эта роль имеет несколько заявок на роль.

Если у пользователя есть role.read как ClaimTypes.Role в основном объекте, их можно создать, как показано ниже в Startup.cs -

* 1009.*

Обновление

Вам необходимо добавить JwtBearerDefaults.AuthenticationScheme тип аутентификации для идентификации утверждений, чтобы он соответствовал схеме по умолчанию.

services
   .AddAuthentication(sharedOptions =>
   {
      ...
   })
   .AddJwtBearer(options =>
   {
      ...
      options.Events = new JwtBearerEvents()
      {         
         OnTokenValidated = context =>
         {
            ...
            var appIdentity = new ClaimsIdentity(claims, 
                   JwtBearerDefaults.AuthenticationScheme);
                               ^^^^^

            context.Principal.AddIdentity(appIdentity);

            return Task.CompletedTask;
         }
      };
   });
...