NetCore 3.1 Используйте IdentityServer4 с существующей базой данных и таблицей пользователей - PullRequest
0 голосов
/ 06 августа 2020

У меня есть существующая база данных с таблицей под названием Users (на самом деле это старая структура таблицы базы данных DotNetNuke 8.1 (например, примерно в 2016 году) с Users, UserRoles и т. Д. c таблицами). Он не соответствует структуре текущего удостоверения Microsoft, например (AspNetUsers, AspNetUserRoles ... et c).

Я хочу добавить уровень проверки подлинности в проект NetCore 3.1, который использует эту базу данных. Мне удалось скомпилировать таблицы базы данных в модели и добавить классы контекста db, чтобы получить доступ к таблице Users.

Как мне добавить IdentityServer4 для аутентификации с именами пользователей и их паролями из таблицы Users. что у меня есть:

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.AddDbContext<ApplicationDbContext>(option => option.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

            // added for identity server
            services.AddIdentityServer()
                .AddInMemoryApiResources(Configurations.Configuration.GetApis())
                .AddInMemoryClients(Configurations.Configuration.GetClients())
                .AddDeveloperSigningCredential();

            services.AddTransient<IResourceOwnerPasswordValidator, Configurations.ResourceOwnerPasswordValidator>();
            services.AddTransient<IProfileService, Configurations.ProfileService>();

            services.AddControllersWithViews();

          
        }

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

            app.UseHttpsRedirection();

            app.UseRouting();

            // added for identity server
            app.UseIdentityServer();

            //added
            app.UseAuthentication();

            app.UseAuthorization();

            //added
            dbContext.Database.EnsureCreated();

            app.UseEndpoints(endpoints =>
            {

                endpoints.MapControllerRoute(
                   name: "default",
                   pattern: "{controller=Test}/{action=Index}/{id?}");
            });
        }
    }

Класс конфигурации для IdentityServer4:

public static class Configuration
    {
        public static IEnumerable<ApiResource> GetApis() =>
            new List<ApiResource> 
            { 
                new ApiResource("ApiOne")  // registering one api with this name
            };

        public static IEnumerable<Client> GetClients() =>    // define a client that will consume above api
            new List<Client>
            {
                new Client
                {
                    ClientId = "resClient",
                    ClientSecrets = { new Secret("topsecret".ToSha256()) },   // make client secret more complex for production, can be made to expire


                    AllowedGrantTypes = GrantTypes.ClientCredentials,    // how client will request the access token

                    //define what the access token will be allowed to be used for, the scopes
                    AllowedScopes = { "ApiOne" }     // this client will be allowed to access Api One
                }
            };


    }

Класс ProfileService:

public class ProfileService : IProfileService
    {
        public Task GetProfileDataAsync(ProfileDataRequestContext context)
        {
            context.IssuedClaims = context.Subject.Claims.ToList();
            return Task.FromResult(0);
        }

        public Task IsActiveAsync(IsActiveContext context)
        {
            return Task.FromResult(0);
        }
    }

Я пытаюсь указать имя пользователя и передаю из базы данных (не хешируется, это просто для тестирования), но всегда возвращается:

"unauthorized_client"

введите описание изображения здесь

Ответы [ 2 ]

1 голос
/ 07 августа 2020

Это пример файла конфигурации, необходимого для работы IdentityServer4 в ASP. NET Core 2.2 и выше. Создайте класс stati c и подключите его к классу запуска UR, как вы это сделали

public static class InMemoryConfiguration
     {
          public static IEnumerable<ApiResource> ApiResources()
          {
               return new[] {
                    new ApiResource("yourapp", "Your App", new List<string>() {"role"})
                    {
                         ApiSecrets = { new Secret("topsecret".Sha256()) },
                         UserClaims = { JwtClaimTypes.Email, JwtClaimTypes.Role, JwtClaimTypes.Name, JwtClaimTypes.FamilyName, JwtClaimTypes.GivenName }
                    }
               };
          }

      public static IEnumerable<IdentityResource> GetIdentityResources()
      {
           return new List<IdentityResource>
           {
               new IdentityResources.OpenId(),
               new IdentityResources.Profile(),
               new IdentityResources.Email(),
               new IdentityResource("roles", "Your App Roles", new List<string>() {"role"})
           };
      }

      public static IEnumerable<Client> Clients()
      {
           return new[] {
                new Client
                {
                     ClientId = "resClient",
                     ClientSecrets = new [] { new Secret("topsecret".Sha256()) },
                     AllowedGrantTypes = GrantTypes.ResourceOwnerPasswordAndClientCredentials,
                     AllowedScopes = new [] { "yourapp" },
                     AllowedCorsOrigins = new [] {"http://localhost:8841", "http://localhost:8842"}
                },
                new Client
                {
                     ClientId = "mykabapp_native",
                     ClientSecrets = new [] { new Secret("mykabsecret".Sha256()) },
                     AllowedGrantTypes = GrantTypes.ResourceOwnerPasswordAndClientCredentials,
                     AllowedScopes = {
                          StandardScopes.OpenId,
                          StandardScopes.Profile,
                          StandardScopes.Email,
                          "mykabapp",
                          "roles"
                      },
                     AllowedCorsOrigins = new [] {"http://localhost:8841", "http://localhost:8842"}
                }
        };
      }

      public static IEnumerable<TestUser> Users()
      {
           return new[] {
                new TestUser
                {
                    SubjectId = "012345",
                    Username = "mail@userdomain.com",
                    Password = "password"
                },
                new TestUser
                {
                    SubjectId = "123456",
                    Username = "admin@userdomain.com",
                    Password = "password"
                }
           };
      }
 }
 

// AllowedGrantTypes = GrantTypes.ResourceOwnerPasswordAndClientCredentials,

Обратите внимание на строку выше. это действительно важно, даже если ваш идентификатор клиента правильный на стороне клиента. Вы можете получить ошибку «unauthorized_client»

1 голос
/ 06 августа 2020

Вы получаете unauthorized_client клиента, потому что resClient настроен только для принятия гранта ClientCredentials, вам необходимо изменить клиента, чтобы он также принял грант Password (или просто пароль, если ClientCredentials не требуются этим client):

                new Client
            {
                ClientId = "resClient",
                ClientSecrets = { new Secret("topsecret".ToSha256()) },   // make client secret more complex for production, can be made to expire


                AllowedGrantTypes = GrantTypes.ResourceOwnerPasswordAndClientCredentials,    // how client will request the access token

                //define what the access token will be allowed to be used for, the scopes
                AllowedScopes = { "ApiOne" }     // this client will be allowed to access Api One
            }

Чтобы решить вашу ошибку invalid_scope:

Замените вызов .AddInMemoryApiResources(Configurations.Configuration.GetApis()) на .AddInMemoryApiScopes(Configurations.Configuration.GetApis()) и измените GetApis() на:

        public static IEnumerable<ApiScope> GetApis() =>
        new List<ApiScope> 
        { 
            new ApiScope("ApiOne")  // registering one api with this name
        };
...