IdentityServer4 Ролевая авторизация для веб-API с основной идентификацией ASP.NET - PullRequest
0 голосов
/ 30 декабря 2018

Я использую IdentityServer4 с .Net Core 2.1 и Asp.Net Core Identity.У меня есть два проекта в моем решении.

  • IdentityServer
  • Web API

Я хочу защитить свои веб-API, я использую почтальон для запроса новых токеновРаботает и токены генерируются успешно.Когда я использую [Authorize] на моих контроллерах без ролей, он работает отлично, но когда я использую [Authorize(Roles="Student")] (даже с [Authorize(Policy="Student")]), он всегда возвращает 403 forbidden

Github-ссылку для полного кода: https://github.com/Mohammad7070/ShagerdanehIdentityServer

Что не так с моим кодом

Web API startup.cs

  public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {



            services.AddMvcCore()
            .AddAuthorization(options => options.AddPolicy("Student", policy => policy.RequireClaim("Role", "Student")))
            .AddAuthorization(options => options.AddPolicy("Teacher", policy => policy.RequireClaim("Role", "Teacher")))
            .AddAuthorization(options => options.AddPolicy("Admin", policy => policy.RequireClaim("Role", "Admin")))
            .AddJsonFormatters();

            services.AddAuthentication("Bearer")
                .AddIdentityServerAuthentication(options =>
                {
                    options.Authority = "http://localhost:5000";
                    options.RequireHttpsMetadata = false;
                    options.ApiName = "api1";

                });





        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            app.UseAuthentication();
            app.UseMvc();
        }
    }

Тест API:

  [Route("api/[controller]")]
    [ApiController]
    [Authorize(Roles="Student")]
    public class ValuesController : ControllerBase
    {
        // GET api/values
        [HttpGet]
        public ActionResult<IEnumerable<string>> Get()
        {
            return new string[] { "value1", "value2" };
        }

        // GET api/values/5
        [HttpGet("{id}")]
        public ActionResult<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)
        {
        }
    }

IdentityServer startup.cs

  public class Startup
    {

        public IConfiguration Configuration { get; }
        public IHostingEnvironment Environment { get; }

        public Startup(IConfiguration configuration, IHostingEnvironment environment)
        {
            Configuration = configuration;
            Environment = environment;
        }

        // This method gets called by the runtime. Use this method to add services to the container.
        // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
        public void ConfigureServices(IServiceCollection services)
        {
            string connectionString = Configuration.GetConnectionString("DefaultConnection");

            string migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;


            services.AddDbContext<ApplicationDbContext>(options =>
                             options.UseSqlServer(connectionString));

            services.AddIdentity<ApplicationUser, ApplicationRole>()
                .AddEntityFrameworkStores<ApplicationDbContext>()
                .AddDefaultTokenProviders();

            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);


            services.Configure<IISOptions>(iis =>
            {
                iis.AuthenticationDisplayName = "Windows";
                iis.AutomaticAuthentication = false;
            });

            IIdentityServerBuilder builder = services.AddIdentityServer(options =>
            {
                options.Events.RaiseErrorEvents = true;
                options.Events.RaiseInformationEvents = true;
                options.Events.RaiseFailureEvents = true;
                options.Events.RaiseSuccessEvents = true;
            })
                .AddAspNetIdentity<ApplicationUser>()

                // this adds the config data from DB (clients, resources)
                .AddConfigurationStore(options =>
                {
                    options.ConfigureDbContext = b =>
                        b.UseSqlServer(connectionString,
                            sql => sql.MigrationsAssembly(migrationsAssembly));
                })
                // this adds the operational data from DB (codes, tokens, consents)
                .AddOperationalStore(options =>
                {
                    options.ConfigureDbContext = b =>
                        b.UseSqlServer(connectionString,
                            sql => sql.MigrationsAssembly(migrationsAssembly));

                    // this enables automatic token cleanup. this is optional.
                    options.EnableTokenCleanup = true;
                    // options.TokenCleanupInterval = 15; // frequency in seconds to cleanup stale grants. 15 is useful during debugging
                })
                .AddProfileService<ProfileService>();

            if (Environment.IsDevelopment())
            {
                builder.AddDeveloperSigningCredential();
            }
            else
            {
                throw new Exception("need to configure key material");
            }

            services.AddAuthentication();

        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {


          //  InitializeDatabase(app);



            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseIdentityServer();

            //app.Run(async (context) =>
            //{
            //    await context.Response.WriteAsync("Hello World!");
            //});
        }



        }
    }
1028 * IdentityServer4 config.cs
   public class Config
    {
        // scopes define the resources in your system
        public static IEnumerable<IdentityResource> GetIdentityResources()
        {
            return new List<IdentityResource>
            {
                new IdentityResources.OpenId(),
                new IdentityResources.Profile(),
            };
        }

        public static IEnumerable<ApiResource> GetApiResources()
        {
            return new List<ApiResource>
            {
                new ApiResource("api1", "My API"),
                 new ApiResource("roles", "My Roles"),
                 new IdentityResource("roles", new[] { "role" })
            };
        }

        // clients want to access resources (aka scopes)
        public static IEnumerable<Client> GetClients()
        {
            // client credentials client
            return new List<Client>
            {
                // resource owner password grant client
                new Client
                {
                    ClientId = "ro.client",
                    AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,

                    ClientSecrets =
                    {
                        new Secret("secret".Sha256())
                    },
                    AllowedScopes = { "api1","roles" }
                }
            };
        }

    }

Токен Sample

eyJhbGciOiJSUzI1NiIsImtpZCI6ImU0ZjczZDU5MjQ2YjVjMmFjOWVkNDI2ZGU4YzlhNGM2IiwidHlwIjoiSldUIn0.eyJuYmYiOjE1NDYyNTk0NTYsImV4cCI6MTU0NjI2MzA1NiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo1MDAwIiwiYXVkIjpbImh0dHA6Ly9sb2NhbGhvc3Q6NTAwMC9yZXNvdXJjZXMiLCJhcGkxIl0sImNsaWVudF9pZCI6InJvLmNsaWVudCIsInN1YiI6IjIiLCJhdXRoX3RpbWUiOjE1NDYyNTk0NTYsImlkcCI6ImxvY2FsIiwic2NvcGUiOlsicm9sZXMiLCJhcGkxIl0sImFtciI6WyJwd2QiXX0.D6OvbrGx2LwrYSySne59VJ _-_ Kz-WriNUbDiETiHO4pknYJzBxKr307DxvBImlvP8w35Cxj3rKxwyWDqVxyhdFhFvFFuHmxqIAv_g2r37lYj3ExcGYAn23Q1i4PuXXBWQe2AHuwFsN2cfPcG39f-N-q7pfLFhoHacXe8vSWyvKxSD0Vj3qVz15cj5VMV1R8qhodXMO-5sZfY1wNfkcJmqmXnbpPnUK_KKUY1Pi6YJkU1nYRXGRoW7YLXc7Y2SFSfa9c1ubU3DDVJV0JqVxSBpfGnvydHEpk-gBx11yQgW5nsJdu6Bi2-DVGA5AdZ_-7pz0AVI-eZPwk2lNtlivmoeA

APS.NET_USERS Таблица

1039 *enter image description here 1044 * APS.NET_USERS_Claims Таблица

enter image description here

Почтальон enter image description here

ApiRequest enter image description here

Претензии при использовании [Authorize]

enter image description here

Ответы [ 3 ]

0 голосов
/ 02 января 2019

Проблема заключается в том, что заявки не добавляются в токен доступа .

Существует два токена: токен доступа и идентификационный токен.

Если вы хотите добавить заявки к идентификационному токену , вам придется настроить IdentityResource .Если вы хотите добавить утверждения к токену доступа , вам необходимо настроить ApiResource (или область действия).

Это должно исправить это для вас:

public static IEnumerable<ApiResource> GetApiResources()
{
    return new List<ApiResource>
    {
        new ApiResource("api1", "My API"),
        new ApiResource("roles", "My Roles", new[] { "role" })
    };
}

Убедитесь, что клиент (почтальон) запрашивает область roles.

Я протестировал его с образцом кода изIdentityServer.В моей настройке я добавил роль «TestUser» для Алисы:

new TestUser
{
    SubjectId = "1",
    Username = "alice",
    Password = "password",
    Claims = new List<Claim> { new Claim("role", "TestUser") } 
},

Вызов почтальона, обратите внимание на запрошенную область действия:

enter image description here

Маркер доступа, включая утверждение о роли:

enter image description here

0 голосов
/ 18 июня 2019

Я решил эту проблему, добавив ' role ' в Тип столбец в ApiClaims , см. Изображение ниже.

ApiResourceId имя столбца найдено в Таблица ApiClaims является первичным ключом ApiResources таблица с Id именем столбца.

enter image description here

0 голосов
/ 30 декабря 2018

В вашем Api, где-то перед services.AddAuthentication("Bearer") добавьте строку для JwtSecurityTokenHandler.InboundClaimTypeMap.Clear();.

Дополнительная информация на этого поста .

РЕДАКТИРОВАТЬ: Кроме того, попробуйте обновить конфигурацию ресурсов идентификации с помощью roles ресурса идентификации.

    // scopes define the resources in your system
    public static IEnumerable<IdentityResource> GetIdentityResources()
    {
        return new List<IdentityResource>
        {
            new IdentityResources.OpenId(),
            new IdentityResources.Profile(),
            new IdentityResource("roles", new[] { "role" })
        };
    }

А вашему клиенту AllowedScopes необходимо добавить rolesа затем:

    AllowedScopes = { "api1", "roles" }

Наконец, ваш запрос почтальона должен затем попросить включить область roles scope: api1 roles.

РЕДАКТИРОВАТЬ 2: Такжеобновите свой профиль, чтобы включить роли в выданные претензии:

    public async Task GetProfileDataAsync(ProfileDataRequestContext context)
    {
        context.IssuedClaims.AddRange(context.Subject.Claims);

        var user = await _userManager.GetUserAsync(context.Subject);

        var roles = await _userManager.GetRolesAsync(user);

        foreach (var role in roles)
        {
            context.IssuedClaims.Add(new Claim(JwtClaimTypes.Role, role));
        }
    }

Вышеприведенное описание, вероятно, следует обновить, чтобы добавить претензию roles только тогда, когда она запрашивается.

1031 * Убедитесь, что недавно выпустил JWT жетоны теперь включают в себя roles утверждают, как в ниже:

eyJhbGciOiJSUzI1NiIsImtpZCI6ImU0ZjczZDU5MjQ2YjVjMmFjOWVkNDI2ZGU4YzlhNGM2IiwidHlwIjoiSldUIn0.eyJuYmYiOjE1NDY0Mzk0MTIsImV4cCI6MTU0NjQ0MzAxMiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo1MDAwIiwiYXVkIjpbImh0dHA6Ly9sb2NhbGhvc3Q6NTAwMC9yZXNvdXJjZXMiLCJhcGkxIiwicm9sZXMiXSwiY2xpZW50X2lkIjoicm8uY2xpZW50Iiwic3ViIjoiMiIsImF1dGhfdGltZSI6MTU0NjQzOTQxMSwiaWRwIjoibG9jYWwiLCJyb2xlIjpbIkFkbWluIiwiU3R1ZGVudCJdLCJzY29wZSI6WyJvcGVuaWQiLCJhcGkxIiwicm9sZXMiXSwiYW1yIjpbInB3ZCJdfQ.irLmhkyCTQB77hm3XczL4krGMUqAH8izllG7FmQhZIQaYRqI7smLIfrqd6UBDFWTDpD9q0Xx0oefUzjBrwq2XnhGSm83vxlZXaKfb0RdLbYKtC4BlypgTEj8OC-G0ktPqoN1C0lh2_Y2PfKyQYieSRlEXkOHeK6VWfpYKURx6bl33EVDcwe_bxPO1K4axdudtORpZ_4OOkx9b_HvreYaCkuUqzUzrNhYUMl028fPFwjRjMmZTmlDJDPu3Wz-jTaSZ9CHxELG5qIzmpbujCVknh3I0QxRU8bSti2bk7Q139zaiPP2vT5RWAqwnhIeuY9xZb_PnUsjBaxyRVQZ0vTPjQ

1037 *
...