Пользовательская аутентификация в ASP.Net-Core

Я работаю над веб-приложением, которое необходимо интегрировать с существующей пользовательской базой данных. Я все равно хотел бы использовать атрибуты [Authorize], но я не хочу использовать структуру Identity. Если бы я хотел использовать структуру Identity, я бы добавил что-то вроде этого в файле startup.cs:

services.AddIdentity<ApplicationUser, IdentityRole>(options =>
{
    options.Password.RequireNonLetterOrDigit = false;
}).AddEntityFrameworkStores<ApplicationDbContext>()
  .AddDefaultTokenProviders();

Я предполагаю, что мне нужно добавить что-то еще, а затем создать какой-то класс, который реализует определенный интерфейс? Может кто-нибудь указать мне в правильном направлении? Я использую RC1 из asp.net 5 прямо сейчас.

Ответ 1

Создание пользовательской аутентификации в ASP.NET Core может быть выполнено различными способами. Если вы хотите скомпоновать существующие компоненты (но не хотите использовать личность), проверьте категорию документов "Безопасность" на docs.asp.net. https://docs.asp.net/en/latest/security/index.html

Некоторые статьи, которые могут вам пригодиться:

Использование промежуточного ПО Cookie без идентификатора ASP.NET

Пользовательская авторизация на основе политик

И, конечно, если это не удается или документы недостаточно ясны, исходный код находится в https://github.com/aspnet/Security, который содержит некоторые примеры.

Ответ 2

Из того, что я узнал после нескольких дней исследований, Вот Руководство по пользовательской аутентификации пользователя ASP.Net Core MVC 2.x

В Startup.cs:

Добавьте следующие строки в метод ConfigureServices:

public void ConfigureServices(IServiceCollection services)
{

services.AddAuthentication(
    CookieAuthenticationDefaults.AuthenticationScheme
).AddCookie(CookieAuthenticationDefaults.AuthenticationScheme,
    options =>
    {
        options.LoginPath = "/Account/Login";
        options.LogoutPath = "/Account/Logout";
    });

    services.AddMvc();

    // authentication 
    services.AddAuthentication(options =>
    {
       options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    });

    services.AddTransient(
        m => new UserManager(
            Configuration
                .GetValue<string>(
                    DEFAULT_CONNECTIONSTRING //this is a string constant
                )
            )
        );
     services.AddDistributedMemoryCache();
}

имейте в виду, что в приведенном выше коде мы сказали, что если любой неаутентифицированный пользователь запрашивает действие, которое аннотировано [Authorize], он вполне принудительно перенаправляет на URL /Account/Login.

Добавьте следующие строки в метод Configure:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseBrowserLink();
        app.UseDatabaseErrorPage();
    }
    else
    {
        app.UseExceptionHandler(ERROR_URL);
    }
     app.UseStaticFiles();
     app.UseAuthentication();
     app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: DEFAULT_ROUTING);
    });
}

Создайте свой класс UserManager, который также будет управлять входом и выходом из системы. он должен выглядеть так, как показано ниже (обратите внимание, что я использую dapper):

public class UserManager
{
    string _connectionString;

    public UserManager(string connectionString)
    {
        _connectionString = connectionString;
    }

    public async void SignIn(HttpContext httpContext, UserDbModel user, bool isPersistent = false)
    {
        using (var con = new SqlConnection(_connectionString))
        {
            var queryString = "sp_user_login";
            var dbUserData = con.Query<UserDbModel>(
                queryString,
                new
                {
                    UserEmail = user.UserEmail,
                    UserPassword = user.UserPassword,
                    UserCellphone = user.UserCellphone
                },
                commandType: CommandType.StoredProcedure
            ).FirstOrDefault();

            ClaimsIdentity identity = new ClaimsIdentity(this.GetUserClaims(dbUserData), CookieAuthenticationDefaults.AuthenticationScheme);
            ClaimsPrincipal principal = new ClaimsPrincipal(identity);

            await httpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal);
        }
    }

    public async void SignOut(HttpContext httpContext)
    {
        await httpContext.SignOutAsync();
    }

    private IEnumerable<Claim> GetUserClaims(UserDbModel user)
    {
        List<Claim> claims = new List<Claim>();

        claims.Add(new Claim(ClaimTypes.NameIdentifier, user.Id().ToString()));
        claims.Add(new Claim(ClaimTypes.Name, user.UserFirstName));
        claims.Add(new Claim(ClaimTypes.Email, user.UserEmail));
        claims.AddRange(this.GetUserRoleClaims(user));
        return claims;
    }

    private IEnumerable<Claim> GetUserRoleClaims(UserDbModel user)
    {
        List<Claim> claims = new List<Claim>();

        claims.Add(new Claim(ClaimTypes.NameIdentifier, user.Id().ToString()));
        claims.Add(new Claim(ClaimTypes.Role, user.UserPermissionType.ToString()));
        return claims;
    }
}

Тогда, может быть, у вас есть AccountController с действием Login, которое должно выглядеть следующим образом:

public class AccountController : Controller
{
    UserManager _userManager;

    public AccountController(UserManager userManager)
    {
        _userManager = userManager;
    }

    [HttpPost]
    public IActionResult LogIn(LogInViewModel form)
    {
        if (!ModelState.IsValid)
            return View(form);
         try
        {
            //authenticate
            var user = new UserDbModel()
            {
                UserEmail = form.Email,
                UserCellphone = form.Cellphone,
                UserPassword = form.Password
            };
            _userManager.SignIn(this.HttpContext, user);
             return RedirectToAction("Search", "Home", null);
         }
         catch (Exception ex)
         {
            ModelState.AddModelError("summary", ex.Message);
            return View(form);
         }
    }
}

Теперь вы можете использовать аннотацию [Authorize] на любом Action или Controller.

Не стесняйтесь комментировать любые вопросы или ошибки.