Рекомендации по хранению утверждений ASP.NET Core Authorization при аутентификации пользователей в Active Directory?

Я создаю корпоративное интранет-приложение ASP.NET Core MVC. Я хочу, чтобы мои пользователи проходили аутентификацию с использованием Active Directory, и я хочу, чтобы пользовательские авторизации (утверждения) сохранялись вApplicationDbContext.

Я предполагаю, что мне нужно использоватьMicrosoft.AspNetCore.Identity а такжеMicrosoft.AspNetCore.Identity.EntityFrameworkCore для достижения моих целей. Какова наилучшая практика для хранения утверждений ASP.NET Core Authorization при аутентификации в Active Directory?

Следующий код даст мне доступ к текущему контексту безопасности пользователя Windows (текущий зарегистрированный пользователь) из конвейера. Как-то мне нужно сопоставить пользователя со связаннымMicrosoft.AspNetCore.Identity претензии?

 app.Use(async (context, next) =>
 {
      var identity = (ClaimsIdentity) context.User.Identity;
      await next.Invoke();
 });

Заранее спасибо за помощь!

 Ssss19 авг. 2016 г., 12:19
Привет @Will, это было решено?
 lazy21 авг. 2016 г., 06:15
@ У пользователя HttpContext.User должны быть идентификационные данные и данные пользователя, чтобы вы могли идентифицировать и сопоставить пользователя с идентификационной информацией.

Ответы на вопрос(2)

что есть лучшая практика, но у вас есть много вариантов. Возможно, вы могли бы немного рассказать о том, что вы пытаетесь достичь? Вот несколько советов, которые могут помочь вам разобраться с этим. Просто вопрос ... что вы используете для аутентификации против AD под капотом? Если вы используетеIdentityServer или что-то подобное, то я бы порекомендовал склониться к варианту 4.

Вариант 1 - Хранить претензии какApplicationUser имущество

Прежде всего, заявки - это просто пары ключ-значение. Это означает, что вы можете создать такую ​​структуру, как:

public class UserClaim 
{
    public string UserName {get; set;}
    public string Key {get; set;}
    public string Value {get; set;}
}

Это позволит вам хранить претензии в вашемApplicationUser учебный класс.

Вариант 2 - Хранение претензий с использованиемUserManager

А еще лучше, вы можете использовать встроенные компоненты идентификации, вводяUserManager<ApplicationUser> userManager в класс, в который вы хотите добавить пользовательские утверждения, а затем вызватьAddClaim() с соответствующими значениями. Из-за системы DI в Core вы можете делать это в любом классе, который будет активирован во время выполнения.

Вариант 3 - Хранение претензий на собственном столе

Другим подходом будет увеличениеUserClaim класс сUserName свойство, затем используйте уникальный идентификатор принципа (User.Identity.Name). Тогда вы можете хранить это вDbSet<UserClaim> в вашемApplicationDbContext и получить претензии по имени пользователя.

Вариант 4 - Не хранить претензии

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

User оформлен утверждениями, принадлежащими пользователю, выполнившему вход в ваше приложение, и доступен на каждом контроллере.

В противном случае вы можете получитьClaimsPrinciple и таким образом получить доступ к утверждениям пользователя. В этом случае (за пределами контроллера) вы должны добавитьIHttpContextAccessor accessor к конструктору вашего класса и перейдите кHttpContextAccessor.HttpContext.User собственность, которая сноваClaimsPrinciple.

Реализуйте класс MyUser

public class MyUser: IdentityUser
{
}

Используйте ASP.Net Core DbContext в отдельном «безопасном» DBContext (я предпочитаю ограниченные контексты, отвечающие за их собственную функциональность)

public class SecurityDbContext : IdentityDbContext<MyUser>
{
    public SecurityDbContext(DbContextOptions<SecurityDbContext> options)
        : base(options)
    { }
}

Создать претензию трансформера. Это используется для добавления претензий из магазина в ClaimsIdentity (объект User в вашем HttpContext)

public class ClaimsTransformer : IClaimsTransformer
{
    private readonly SecurityDbContext _context;
    private readonly UserManager<MyUser> _userManager;

    public ClaimsTransformer(SecurityDbContext context, UserManager<MyUser> userManager)
    {
        _context = context;
        _userManager = userManager;
    }

    public Task<ClaimsPrincipal> TransformAsync(ClaimsTransformationContext context)
    {
        var identity = context.Principal.Identity as ClaimsIdentity;
        if (identity == null) return Task.FromResult(context.Principal);

        try
        {
            if (context.Context.Response.HasStarted)
                return Task.FromResult(context.Principal);

            var claims = AddClaims(identity);
            identity.AddClaims(claims);
        }
        catch (InvalidOperationException)
        {
        }
        catch (SqlException ex)
        {
            if (!ex.Message.Contains("Login failed for user") && !ex.Message.StartsWith("A network-related or instance-specific error"))
                throw;
        }

        return Task.FromResult(context.Principal);
    }

    private IEnumerable<Claim> AddClaims(IIdentity identity)
    {
        var claims = new List<Claim>();
        var existing = _userManager.Users.Include(u => u.Claims).SingleOrDefault(u => u.UserName == identity.Name);
        if (existing == null) return claims;

        claims.Add(new Claim(SupportedClaimTypes.ModuleName, Constants.ADGroupName));
        claims.AddRange(existing.Claims.Select(c => c.ToClaim()));

        return claims;
    }
}

Вам нужно будет добавить несколько вещей в ваш класс startup.cs, я добавил только подходящие:

public void ConfigureServices(IServiceCollection services)
{
    services.AddIdentity<FreightRateUser, IdentityRole>(config =>
            {
                config.User.AllowedUserNameCharacters =
                    "ab[email protected]\\";
            config.User.RequireUniqueEmail = false;
            config.Cookies.ApplicationCookie.LoginPath = "/Auth/Login";
        })
        .AddEntityFrameworkStores<SecurityDbContext>();
}

Не забудьте метод Configure

public async void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    app.UseIdentity();
}

Наконец, вам понадобится некоторое представление для добавления соответствующих пользователей / утверждений в таблицы Identity, у меня есть контроллер с парой действий (только показывает Create здесь):

    [AllowAnonymous]
    public IActionResult CreateAccess()
    {
        var vm = new AccessRequestViewModel
        {
            Username = User.Identity.Name
        };
        return View(vm);
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    [AllowAnonymous]
    public async Task<IActionResult> CreateAccess(AccessRequestViewModel viewModel)
    {
        if (User == null || !User.Identity.IsAuthenticated) return View("Index");

            var newUser = new MyUser
            {
                UserName = viewModel.Username
            };
            var x = await _userManager.CreateAsync(newUser);
            if (!x.Succeeded)
                return View(ModelState);

            var myClaims = new List<Claim>();
            if (viewModel.CanManageSecurity)
                myClaims.Add(new Claim(SupportedClaimTypes.Security, "SITE,LOCAL"));
            if (viewModel.CanChangeExchangeRates)
                myClaims.Add(new Claim(SupportedClaimTypes.ExchangeRates, "AUD,USD"));
            if (viewModel.CanChangeRates)
                myClaims.Add(new Claim(SupportedClaimTypes.Updates, "LOCAL"));
            if (viewModel.CanManageMasterData)
                myClaims.Add(new Claim(SupportedClaimTypes.Admin, "SITE,LOCAL"));

            await _userManager.AddClaimsAsync(newUser, myClaims);
        }
        return View("Index");
    }

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

Пожалуйста, обратите внимание, это для текущего пользователя HttpContext, с помощью которого вы захотите сделать создание для других пользователей в Create, поскольку вы, очевидно, не хотите, чтобы текущий пользователь предоставлял себе доступ.

Ваш ответ на вопрос