. NET Аутентификация Core Api с использованием сервера идентификации 4 - PullRequest
0 голосов
/ 18 июня 2020

Я пытаюсь создать небольшое демонстрационное приложение для электронной коммерции, используя. net основной API 3.1 с сервером идентификации 4.

Project Structure


Config.cs (проект Demo.Auth)

    public static class Config
    {
        public static IEnumerable<IdentityResource> Ids =>
            new IdentityResource[]
            {                
                new IdentityResources.Profile(),
            };
        public static IEnumerable<ApiResource> ApiResources => new[]
        {
            new ApiResource("Demo.Api", "Demo Api")
        };

        public static IEnumerable<Client> Clients => new[]
        {
            new Client()
            {
                ClientId = "mvc",
                ClientName = "Demo.MvcClient",
                AllowedGrantTypes = GrantTypes.ClientCredentials,
                RequirePkce = true,
                ClientSecrets =
                {
                    new Secret("49C1A7E1-0C79-4A89-A3D6-A37998FB86B0".Sha256())
                },
                RedirectUris = {"http://localhost:5003/signin-oidc"},
                FrontChannelLogoutUri = "http://localhost:5003/signout-oidc",
                PostLogoutRedirectUris = {"http://localhost:5003/signout-callback-oidc"},

                AllowOfflineAccess = true,
                AllowedScopes = {"profile"}
            }
        };
    }


Startup.cs (проект Demo.Auth)

    public class Startup
    {
        // 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)
        {
            services.AddControllersWithViews();
            IConfigurationRoot config = new ConfigurationBuilder()
                .SetBasePath(Directory.GetCurrentDirectory())
                .AddJsonFile("appsettings.json")
                .Build();

            string identityConnectionString = config.GetSection("ConnectionStrings")
                .Value;
            var migratingAssembly = typeof(Startup).GetTypeInfo()
                .Assembly.GetName()
                .Name;

            if (config.GetValue<bool>("UseInMemoryDatabase"))
            {
                services.AddIdentityServer(options =>
                    {
                        options.Events.RaiseErrorEvents = true;
                        options.Events.RaiseInformationEvents = true;
                        options.Events.RaiseFailureEvents = true;
                        options.Events.RaiseSuccessEvents = true;
                    })
                    .AddTestUsers(TestUsers.Users)
                    .AddInMemoryIdentityResources(Config.Ids)
                    .AddInMemoryApiResources(Config.ApiResources)
                    .AddInMemoryClients(Config.Clients)
                    .AddDeveloperSigningCredential();
            }
            else
            {
                services.AddIdentityServer(options =>
                    {
                        options.Events.RaiseErrorEvents = true;
                        options.Events.RaiseInformationEvents = true;
                        options.Events.RaiseFailureEvents = true;
                        options.Events.RaiseSuccessEvents = true;
                    })
                    .AddTestUsers(TestUsers.Users)
                    .AddDeveloperSigningCredential()
                    //This will store client and ApiResource
                    .AddConfigurationStore(options =>
                    {
                        options.ConfigureDbContext = b => b.UseSqlServer(identityConnectionString,
                            sql => sql.MigrationsAssembly(migratingAssembly));
                    })
                    //This will store token, consent or code
                    .AddOperationalStore(options =>
                    {
                        options.ConfigureDbContext = b => b.UseSqlServer(identityConnectionString,
                            sql => sql.MigrationsAssembly(migratingAssembly));
                    });
            }
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app,
            IWebHostEnvironment env)
        {
            // this will do the initial DB population
           // InitializeDatabase(app);

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

            app.UseRouting();
            app.UseIdentityServer();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapGet("/",
                    async context => { await context.Response.WriteAsync("Hello World!"); });
            });
        }       
    }


Startup.cs (проект API)

    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.AddAuthentication("Bearer").AddIdentityServerAuthentication(options =>
            {
                options.Authority = "http://localhost:5000";
                options.RequireHttpsMetadata = false;
                options.ApiName = "Demo.Api";
            });

            services.AddControllers();
        }

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

            app.UseRouting();
            app.UseAuthentication();
            app.UseAuthorization();

            app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
        }
    }


WeatherForecastController (проекта Demo.Api)

    [Authorize]
    [ApiController]
    [Route("[controller]")]
    public class WeatherForecastController : ControllerBase
    {
        private static readonly string[] Summaries = new[]
        {
            "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
        };

        private readonly ILogger<WeatherForecastController> _logger;
        public WeatherForecastController(ILogger<WeatherForecastController> logger)
        {
            _logger = logger;
        }

        [HttpGet]
        public IEnumerable<WeatherForecast> Get()
        {
            var rng = new Random();
            return Enumerable.Range(1, 5).Select(index => new WeatherForecast
            {
                Date = DateTime.Now.AddDays(index),
                TemperatureC = rng.Next(-20, 55),
                Summary = Summaries[rng.Next(Summaries.Length)]
            })
            .ToArray();
        }
    }


Я тестирую API в почтальоне, и он работает нормально. Проект «Demo.Auth» генерирует токен, и я могу успешно получить доступ к своему контроллеру авторизации.

Идея здесь:

MVC Клиент ----> Проект сервера идентификации - -> API

MVC клиент хочет получить доступ к API. Итак, я аутентифицирую клиента Mvc в проекте сервера идентификации, сгенерирую токен, если он действительный пользователь, и затем вызову свой api.

Примечание: в настоящее время я использую клиент MVC, но позже я добавлю еще одного клиента, может быть Angular.

Но у меня есть вопросы.
Как можно Я добавляю пользователей в свою базу данных и аутентифицирую пользователя базы данных, а не тестируемого.
Еще я не понимаю, где мне разместить функции входа и регистрации и как будет выглядеть этот код.

Я новичок в сервере идентификации, пожалуйста, извините.

Может ли кто-нибудь помочь мне ответить на мой вопрос с помощью кода? Заранее спасибо

Ответы [ 3 ]

0 голосов
/ 20 июня 2020

В потоке ResourceOwnerPasswrod вы можете сохранить функциональность регистрации и входа в систему на стороне клиента, а также вы можете проверить пользователя по отношению к пользователю базы данных.

Вы должны реализовать собственное хранилище пользователей для проверки пользователя и добавления утверждений из базы данных. Измените код запуска, как показано ниже, класс Userrepository представляет связь с базой данных для аутентификации пользователя и получения утверждений из базы данных:

Обновить метод конфигурации запуска для конфигурации идентификации:

var idServerServiceFactory = new IdentityServerServiceFactory()
.UseInMemoryClients(Clients.Get())
.UseInMemoryScopes(Scopes.Get())
.AddCustomUserStore();

Добавьте следующие классы и измените в соответствии с в соответствии с вашим требованием:

public static class CustomIdentityServerBuilderExtensions
{
    public static IIdentityServerBuilder AddCustomUserStore(this IIdentityServerBuilder builder)
    {                   
        builder.AddProfileService<UserProfileService>();           
        builder.AddResourceOwnerValidator<UserResourceOwnerPasswordValidator>();
        return builder;
    }
}

public class UserProfileService : IProfileService
{
    public async Task GetProfileDataAsync(ProfileDataRequestContext context)
    {
            UserRepository userRepository=new UserRepository();
            var user = userRepository.GetUserById(int.Parse(context.Subject.GetSubjectId()));
            if (user != null)
            {
                var userTokenModel = _mapper.Map<UserTokenModel>(user);
                var claims = new List<Claim>();
                claims.Add(new Claim("UserId", user.UserId));
                // Add another claims here 
                context.IssuedClaims.AddRange(claims);                    
    }
    public async Task IsActiveAsync(IsActiveContext context)
    {          
    }
}

public class UserResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator
{        
    public async Task ValidateAsync(ResourceOwnerPasswordValidationContext context)
    {           
            UserRepository userRepository=new UserRepository();
            var userLoginStatus = userRepository.GetUserById(context.UserName, context.Password);

            if (userLoginStatus != null)
            {

                    context.Result = new GrantValidationResult(userLoginStatus.UserId.ToString(),
                         OidcConstants.AuthenticationMethods.Password);                   
            }
            else
            {                    
                context.Result = new GrantValidationResult(TokenRequestErrors.InvalidClient, 
                        "Wrong Credentials");
            }            
    }
}

Обратитесь ASP. NET ПОТОК ПАРОЛЯ ВЛАДЕЛЬЦА РЕСУРСА IDENTITYSERVER4 С ПОМОЩЬЮ ПОЛЬЗОВАТЕЛЯ для потока ResourceOwnerPasswrod. Этот поток рекомендуется использовать для поддержки старых приложений.

Есть другие потоки:

  1. Неявный
  2. Гибридный
  3. Код авторизации

Подробнее см. официальную документацию .

0 голосов
/ 21 июня 2020

Как я могу добавить пользователей в свою базу данных и аутентифицировать пользователя базы данных, а не тестового.

Еще одна вещь, которую я не понимаю, это то, где я должен разместить Функции входа и регистрации и как этот код будет выглядеть.

Существует способ создать рабочий пример, соответствующий вашим требованиям, используя в основном реализации из IdentityServer4 Quickstarts.

Шаги: с использованием базы данных SQL):

  1. Создайте основной проект mvc, используя шаблон do tnet is4aspid. Он настроит IdentityServer в качестве промежуточного программного обеспечения для проекта, вы можете обновить базу данных с готовой миграцией, чтобы создать все таблицы для ASP. NET Core Identity и функции входа, выхода, согласия, грантов (UI) для IdentityServer. (В файле CreaeteIdentitySchema.cs перед обновлением базы данных замените Annotation for Identity column, чтобы соответствовать базе данных SQL как: Annotation ("SqlServer: ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), схема в шаблоне предназначена для базы данных SQLite 1016

  2. Активируйте Razore Pages в Startup.cs из mvc основного проекта, добавив services.AddRazorPages () и endpoints.MapRazorPages (), тогда можно будет добавить строительные леса, и вы сможете добавить все страницы, которые вам нужны регистрировать и поддерживать учетные записи пользователей (локальных и от внешних поставщиков) с помощью библиотеки классов Razor. Страницы входа и выхода из системы должны оставаться под контролем IdentityServer для целей аутентификации.

  3. Затем вы можете использовать контексты ConfigurationDbContext, PersistedGrantDbContext и их сущности из пакета IdentityServer4.EntityFramework.Storage nuget для создания миграции и обновления существующая ASP. NET База данных идентификаторов, добавляющая таблицы для клиентов, ресурсов и областей, а также для временных рабочих данных, таких как коды авторизации и refre sh токены. Чтобы добавить, удалить или обновить данные в эти таблицы, вы можете вручную создать интерфейс, используя эти два контекста.

  4. Последний шаг - создать клиентские проекты и проекты Api в соответствии с Quickstarts и настроить их с помощью IdentityServer для используйте.

Файл Startup.cs в конце будет:

    public class Startup
{
    public IWebHostEnvironment Environment { get; }
    public IConfiguration Configuration { get; }

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

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddScoped<IEmailSender, EmailSender>();

        services.AddControllersWithViews();

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

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

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

        services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

        services.AddIdentity<ApplicationUser, IdentityRole>()
            .AddEntityFrameworkStores<ApplicationDbContext>()
            .AddDefaultTokenProviders();
        
        var builder = services.AddIdentityServer(options =>
            {
                options.Events.RaiseErrorEvents = true;
                options.Events.RaiseInformationEvents = true;
                options.Events.RaiseFailureEvents = true;
                options.Events.RaiseSuccessEvents = true;
            })
            .AddConfigurationStore(options =>
            {
                options.ConfigureDbContext = b =>   b.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"),
                    sql => sql.MigrationsAssembly(migrationsAssembly));
            })
            .AddOperationalStore(options =>
            {
                options.ConfigureDbContext = b =>           b.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"),
                    sql => sql.MigrationsAssembly(migrationsAssembly));
            })
            .AddAspNetIdentity<ApplicationUser>();

        builder.AddDeveloperSigningCredential();

        services.AddRazorPages();

        services.AddAuthentication()
            .AddGoogle(options =>
            {
                options.ClientId = "copy client ID from Google here";
                options.ClientSecret = "copy client secret from Google here";
            });
    }

    public void Configure(IApplicationBuilder app)
    {
        if (Environment.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseDatabaseErrorPage();
        }

        app.UseStaticFiles();

        app.UseRouting();
        app.UseIdentityServer();
        app.UseAuthorization();
        app.UseEndpoints(endpoints =>
        {
            endpoints.MapDefaultControllerRoute();
            endpoints.MapRazorPages();
        });
    }

}  
0 голосов
/ 20 июня 2020

Ответственность за создание и поддержку пользователей лежит на сервере аутентификации.

Где я должен разместить функции входа и регистрации

Итак, проект Identity Server будет содержат конечные точки, такие как Регистрация, Вход, Забыли пароль и т. д. c.

Как я могу добавить пользователей в свою базу данных и аутентифицировать пользователя базы данных, а не тестового.

Microsoft Identity Core

Вы можете реализовать Microsoft Identity Core , который предоставляет все функции, связанные с управлением учетной записью. И в IdentityServer4 есть встроенная поддержка для этого.

Таким образом, вам не придется беспокоиться о коде или базе данных.

Примечание. Microsoft Identity Core выполняет много вещей под капотом, поэтому вы не сможете понять, как на самом деле это работает с IdentityServer4.

Вы можете найти пример кода из здесь (Open Startup.cs) и документацию из здесь .

Вы также можете взглянуть на эту серию YouTube с помощью кодирования строк.

Пользовательский репозиторий

Если вы хотите проверять пользователей без используя Microsoft Identity Core, вы можете реализовать интерфейс IResourceOwnerPasswordValidator, пример кода можно найти здесь здесь и блог из здесь .

...