Как реализовать глобальную авторизацию на основе группы AD в веб-приложении asp.net core 2.x?

Мне интересно, может ли кто-нибудь указать мне направление или пример, в котором есть законченный код, чтобы я мог получить общее представление?

Спасибо.

Обновлять: У меня есть только следующий фрагмент кода в Startup.cs и я проверяю, что windowsAutication истинно в launchSettings.json.

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();

    services.AddMvc(config =>
    {
        var policy = new AuthorizationPolicyBuilder()
                         .RequireAuthenticatedUser()
                         //.RequireRole(@"Departmental - Information Technology - Development")   // Works
                         .RequireRole(@"*IT.Center of Excellence.Digital Workplace")              // Error
                         .Build();
        config.Filters.Add(new AuthorizeFilter(policy));
    });

}

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

Если я использую закомментированный RequireRole, он работает, но использую раскомментированный RequireRole, он дает мне эту ошибку: Win32Exception: не удалось установить доверительные отношения между основным доменом и доверенным доменом.

Верхняя строка в стопке показывает: System.Security.Principal.NTAccount.TranslateToSids (IdentityReferenceCollection sourceAccounts, из bool someFailed)

Есть идеи, почему?

Насколько я понимаю из обновления выше

Похоже, что имя группы, указанное в RequireRole, является списком рассылки электронной почты, а не группой безопасности. Если я использую другую группу AD, она работает, но с этой новой ошибкой:

InvalidOperationException: не указана схема проверки подлинности и схема DefaultForbidScheme не найдена.

Если я добавлю IIS default authenticationScheme в ConfigureServices в Startup.cs

services.AddAuthentication(IISDefaults.AuthenticationScheme);

он дает мне страницу HTTP 403: веб-сайт отказался отображать эту веб-страницу

Итак, это последний код:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();

    services.AddAuthentication(IISDefaults.AuthenticationScheme);

    services.AddMvc(config =>
    {
        var policy = new AuthorizationPolicyBuilder()
                         .RequireAuthenticatedUser()
                         .RequireRole(@"Departmental - Information Technology - Development") // AD security group
                         .Build();
        config.Filters.Add(new AuthorizeFilter(policy));
    });

}

Поправьте меня, если я неправильно понял. Спасибо.

Рассматривает авторизацию на основе утверждений

David Brossard 02.05.2018 12:51

Спасибо, Дэвид. Я заглянул на веб-сайт Microsoft: docs.microsoft.com/en-us/aspnet/core/security/authorization/‌…, не уверен, как реализация требует условия авторизации на основе утверждений. Для группы AD будет ли авторизация на основе ролей более подходящей проверкой принадлежности пользователя к группе?

Xiao Han 02.05.2018 15:48

авторизацию какого типа вы ищете?

David Brossard 02.05.2018 16:37

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

Xiao Han 02.05.2018 16:58

Думаю, этот пост тоже отвечает на мой вопрос: https://stackoverflow.com/questions/36413476/mvc-core-how-to‌ -force-set-global-autorization-for-all-‌ действия? rq = 1

Xiao Han 14.05.2018 19:15
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
8
5
19 068
1

Ответы 1

Вариант 1. Проверка подлинности Windows

Вы можете включить проверку подлинности Windows для приложений интрасети. Прочтите документы здесь. Вы можете проверить, входит ли пользователь в роль / группу, выполнив что-то вроде это.

Прежде чем вы это сделаете, вы можете проверить информацию о группах, к которым присоединился ваш компьютер, выполнив gpresult /R в командной строке. См. эта почта для получения дополнительной информации.

User.IsInRole("xxxx")  // this should return True for any group listed up there

Вам не нужно преобразовывать текущий участник в субъект Windows, если вам не нужно получать какую-либо информацию, связанную с Windows.

Если вы хотите получить список всех групп, вам все равно нужно запросить свой AD.

предупреждение:

Иногда я вижу, что некоторые группы не отображаются в результатах при использовании gpresult /R на компьютере, по сравнению с методом варианта 2. Вот почему иногда, когда вы выполняете User.IsInRole(), он возвращает false. Я до сих пор не знаю, почему это происходит.

Вариант 2: проверка подлинности формы с поиском в AD

Аутентификация Windows предлагает лишь небольшую информацию о пользователе и группах AD. Иногда этого достаточно, но в большинстве случаев это не так.

Вы также можете использовать обычную проверку подлинности с помощью формы и поговорить с AD внизу и выпустить файл cookie. Таким образом, хотя пользователю необходимо войти в ваше приложение, используя свои учетные данные и пароль Windows, у вас будет полный контроль над информацией AD.

Вы же не хотите писать все от руки. К счастью, здесь есть библиотека Novell.Directory.Ldap.NETStandard. Вы можете найти его в NuGet.

Интерфейсы для определения того, что вам нужно от AD, а также протокол входа в систему:

namespace DL.SO.Services.Core
{
    public interface IAppUser
    {
        string Username { get; }
        string DisplayName { get; }
        string Email { get; }
        string[] Roles { get; }
    }

    public interface IAuthenticationService
    {
        IAppUser Login(string username, string password);
    }
}

Реализация AppUser:

using DL.SO.Services.Core;

namespace DL.SO.Services.Security.Ldap.Entities
{
    public class AppUser : IAppUser
    {
        public string Username { get; set; }
        public string DisplayName { get; set; }
        public string Email { get; set; }
        public string[] Roles { get; set; }
    }
}

Объект конфигурации Ldap для сопоставления значений из appsettings.json:

namespace DL.SO.Services.Security.Ldap
{
    public class LdapConfig
    {
        public string Url { get; set; }
        public string BindDn { get; set; }
        public string Username { get; set; }
        public string Password { get; set; }
        public string SearchBase { get; set; }
        public string SearchFilter { get; set; }
    }
}

Реализация LdapAuthenticationService:

using Microsoft.Extensions.Options;
using Novell.Directory.Ldap;
using System;
using System.Linq;
using System.Text.RegularExpressions;
using DL.SO.Services.Core;
using DL.SO.Services.Security.Ldap.Entities;

namespace DL.SO.Services.Security.Ldap
{
    public class LdapAuthenticationService : IAuthenticationService
    {
        private const string MemberOfAttribute = "memberOf";
        private const string DisplayNameAttribute = "displayName";
        private const string SAMAccountNameAttribute = "sAMAccountName";
        private const string MailAttribute = "mail";

        private readonly LdapConfig _config;
        private readonly LdapConnection _connection;

        public LdapAuthenticationService(IOptions<LdapConfig> configAccessor)
        {
            _config = configAccessor.Value;
            _connection = new LdapConnection();
        }

        public IAppUser Login(string username, string password)
        {
            _connection.Connect(_config.Url, LdapConnection.DEFAULT_PORT);
            _connection.Bind(_config.Username, _config.Password);

            var searchFilter = String.Format(_config.SearchFilter, username);
            var result = _connection.Search(
                _config.SearchBase,
                LdapConnection.SCOPE_SUB, 
                searchFilter,
                new[] { 
                    MemberOfAttribute, 
                    DisplayNameAttribute, 
                    SAMAccountNameAttribute, 
                    MailAttribute 
                }, 
                false
            );

            try
            {
                var user = result.next();
                if (user != null)
                {
                    _connection.Bind(user.DN, password);
                    if (_connection.Bound)
                    {
                        var accountNameAttr = user.getAttribute(SAMAccountNameAttribute);
                        if (accountNameAttr == null)
                        {
                            throw new Exception("Your account is missing the account name.");
                        }

                        var displayNameAttr = user.getAttribute(DisplayNameAttribute);
                        if (displayNameAttr == null)
                        {
                            throw new Exception("Your account is missing the display name.");
                        }

                        var emailAttr = user.getAttribute(MailAttribute);
                        if (emailAttr == null)
                        {
                            throw new Exception("Your account is missing an email.");
                        }

                        var memberAttr = user.getAttribute(MemberOfAttribute);
                        if (memberAttr == null)
                        {
                            throw new Exception("Your account is missing roles.");
                        }

                        return new AppUser
                        {
                            DisplayName = displayNameAttr.StringValue,
                            Username = accountNameAttr.StringValue,
                            Email = emailAttr.StringValue,
                            Roles = memberAttr.StringValueArray
                                .Select(x => GetGroup(x))
                                .Where(x => x != null)
                                .Distinct()
                                .ToArray()
                        };
                    }
                }
            }
            finally
            {
                _connection.Disconnect();
            }

            return null;
        }

        private string GetGroup(string value)
        {
            Match match = Regex.Match(value, "^CN=([^,]*)");
            if (!match.Success)
            {
                return null;
            }

            return match.Groups[1].Value;
        }
    }
}

Конфигурация в appsettings.json (просто пример):

{
    "ldap": {
       "url": "[YOUR_COMPANY].loc",
       "bindDn": "CN=Users,DC=[YOUR_COMPANY],DC=loc",
       "username": "[YOUR_COMPANY_ADMIN]",
       "password": "xxx",
       "searchBase": "DC=[YOUR_COMPANY],DC=loc",
       "searchFilter": "(&(objectClass=user)(objectClass=person)(sAMAccountName = {0}))"
    },
    "cookies": {
        "cookieName": "cookie-name-you-want-for-your-app",
        "loginPath": "/account/login",
        "logoutPath": "/account/logout",
        "accessDeniedPath": "/account/accessDenied",
        "returnUrlParameter": "returnUrl"
    }
}

Настройте аутентификацию (возможно, авторизацию) для приложения:

namespace DL.SO.Web.UI
{
    public class Startup
    {
        private readonly IHostingEnvironment _currentEnvironment;
        public IConfiguration Configuration { get; private set; }

        public Startup(IConfiguration configuration, IHostingEnvironment env)
        {
            _currentEnvironment = env;
            Configuration = configuration;
        }

        public void ConfigureServices(IServiceCollection services)
        { 
            // Authentication service
            services.Configure<LdapConfig>(this.Configuration.GetSection("ldap"));
            services.AddScoped<IAuthenticationService, LdapAuthenticationService>();

            // MVC
            services.AddMvc(config =>
            {
                // Requiring authenticated users on the site globally
                var policy = new AuthorizationPolicyBuilder()
                    .RequireAuthenticatedUser()

                    // You can chain more requirements here
                    // .RequireRole(...) OR
                    // .RequireClaim(...) OR
                    // .Requirements.Add(...)         

                    .Build();
                config.Filters.Add(new AuthorizeFilter(policy));
            });

            services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

            // Authentication
            var cookiesConfig = this.Configuration.GetSection("cookies")
                .Get<CookiesConfig>();
            services.AddAuthentication(
                CookieAuthenticationDefaults.AuthenticationScheme)
                .AddCookie(options =>
                {
                    options.Cookie.Name = cookiesConfig.CookieName;
                    options.LoginPath = cookiesConfig.LoginPath;
                    options.LogoutPath = cookiesConfig.LogoutPath;
                    options.AccessDeniedPath = cookiesConfig.AccessDeniedPath;
                    options.ReturnUrlParameter = cookiesConfig.ReturnUrlParameter;
                });

            // Setup more authorization policies as an example.
            // You can use them to protected more strict areas. Otherwise
            // you don't need them.
            services.AddAuthorization(options =>
            {
                options.AddPolicy("AdminOnly", 
                    policy => policy.RequireClaim(ClaimTypes.Role, "[ADMIN_ROLE_OF_YOUR_COMPANY]"));

                // More on Microsoft documentation
                // https://docs.microsoft.com/en-us/aspnet/core/security/authorization/policies?view=aspnetcore-2.1
            });
        }

        public void Configure(IApplicationBuilder app)
        {
            app.UseAuthentication();
            app.UseMvc(...);
        }  
    }
}

Как аутентифицировать пользователей с помощью службы аутентификации:

namespace DL.SO.Web.UI.Controllers
{
    public class AccountController : Controller
    {
        private readonly IAuthenticationService _authService;

        public AccountController(IAuthenticationService authService)
        {
            _authService = authService;
        }

        [AllowAnonymous]
        [HttpPost]
        public async Task<IActionResult> Login(LoginViewModel model)
        {
            if (ModelState.IsValid)
            {
                try
                {
                    var user = _authService.Login(model.Username, model.Password);

                    // If the user is authenticated, store its claims to cookie
                    if (user != null)
                    {
                        var userClaims = new List<Claim>
                        {
                            new Claim(ClaimTypes.Name, user.Username),
                            new Claim(CustomClaimTypes.DisplayName, user.DisplayName),
                            new Claim(ClaimTypes.Email, user.Email)
                        };

                        // Roles
                        foreach (var role in user.Roles)
                        {
                            userClaims.Add(new Claim(ClaimTypes.Role, role));
                        }

                        var principal = new ClaimsPrincipal(
                            new ClaimsIdentity(userClaims, _authService.GetType().Name)
                        );

                        await HttpContext.SignInAsync(                            
                          CookieAuthenticationDefaults.AuthenticationScheme, 
                            principal,
                            new AuthenticationProperties
                            {
                                IsPersistent = model.RememberMe
                            }
                        );

                        return Redirect(Url.IsLocalUrl(model.ReturnUrl)
                            ? model.ReturnUrl
                            : "/");
                    }

                    ModelState.AddModelError("", @"Your username or password
                        is incorrect. Please try again.");
                }
                catch (Exception ex)
                {
                    ModelState.AddModelError("", ex.Message);
                }
            }
            return View(model);
        }
    }
}

Как читать информацию, хранящуюся в претензиях:

public class TopNavbarViewComponent : ViewComponent
{
    private readonly IHttpContextAccessor _httpContextAccessor;

    public TopNavbarViewComponent(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }

    public async Task<IViewComponentResult> InvokeAsync()
    {
        string loggedInUsername = _httpContextAccessor.HttpContext.User.Identity.Name;

        string loggedInUserDisplayName = _httpContextAccessor.HttpContext.User.GetDisplayName();

       ...
       return View(vm);
    }
}

Метод расширения для ClaimsPrincipal:

namespace DL.SO.Framework.Mvc.Extensions
{
    public static class ClaimsPrincipalExtensions
    {
        public static Claim GetClaim(this ClaimsPrincipal user, string claimType)
        {
            return user.Claims
                .SingleOrDefault(c => c.Type == claimType);
        }

        public static string GetDisplayName(this ClaimsPrincipal user)
        {
            var claim = GetClaim(user, CustomClaimTypes.DisplayName);

            return claim?.Value;
        }

        public static string GetEmail(this ClaimsPrincipal user)
        {
            var claim = GetClaim(user, ClaimTypes.Email);

            return claim?.Value;
        }
    }
}

Как использовать авторизацию политики:

namespace DL.SO.Web.UI.Areas.Admin.Controllers
{
    [Area("admin")]
    [Authorize(Policy = "AdminOnly")]
    public abstract class AdminControllerBase : Controller {}
}

Бонус

Вы можете загрузить AD Explorer от Microsoft, чтобы визуализировать AD вашей компании.

Оппс. Я планировал просто выдать что-нибудь для старта, но в итоге написал очень длинный пост.

Спасибо, Дэвид. Итак, насколько я понимаю, ваша реализация требует выполнять поиск / поиск в AD каждый раз, когда пользователь пытается получить доступ к приложению, и настроенный код будет проверять это на глобальном уровне, верно?

Xiao Han 02.05.2018 20:54

@XiaoHan: только когда пользователь не прошел аутентификацию? Если пользователь уже аутентифицирован, утверждения уже хранятся в файле cookie. Теперь я понимаю, что они не будут обновляться, если администратор AD изменит информацию о пользователе. Следовательно, было бы неплохо установить срок действия cookie на разумно короткий период, чтобы приложение потребовало от пользователя достаточно быстрой повторной аутентификации и обновления заявлений.

David Liang 02.05.2018 20:59

Спасибо за ваш ответ. Я еще не зашел так далеко. Все еще изучаем варианты этого распространенного сценария работы с группой AD для внутреннего приложения. Думаю, об аутентификации позаботились, так как она внутренняя, а ядро ​​.net имеет встроенную функцию. верно? Исправьте меня, если я ошибаюсь, чтобы заархивировать мою цель, мне нужно написать код настройки, чтобы узнать, находится ли пользователь (например, [имя домена] \ smith) в группе AD (например, [имя домена] \ dev group), верно? Пока у меня есть только части AuthorizationPolicyBuilder и AddAuthorization в ConfigureServices.

Xiao Han 02.05.2018 21:46

Смотрите мои обновления в посте. Да, если вы включите проверку подлинности Windows. Нет, если вы хотите использовать обычную проверку подлинности с помощью форм. В дальнейшем вам нужно будет написать часть аутентификации самостоятельно.

David Liang 02.05.2018 22:19

Спасибо. В коде поиска, который я пишу, у меня есть некоторая простая логика, но она всегда возвращает false при проверке, играет ли принципал в роли конкретной группы. Любая идея? var myIdentity = WindowsIdentity.GetCurrent (); var myPrincipal = новый WindowsPrincipal (myIdentity); вернуть myPrincipal.IsInRole (groupName);

Xiao Han 04.05.2018 21:18

На этот вопрос сложно ответить, потому что у меня нет доступа к активному каталогу вашей компании или я не знаю, как настроены компьютеры ваших парней. Если вы запустите командную строку и наберете gpresult /R, вы должны увидеть список групп, к которым присоединился ваш компьютер. IsInRole() в любой из этих групп должен возвращать True. Кстати, вам не нужно конвертировать текущего участника в Windows, если вам не нужна информация Windows. Смотрите мой обновленный пост.

David Liang 04.05.2018 22:10

Спасибо. Метод IsInRole работает при проверке по именам групп (без указания домена) с помощью команды «gpresult / R». Я сравнил имена групп, они выглядят иначе, чем то, что я вижу в проводнике AD под значением поля memberOf конкретной учетной записи. Как вы сказали, некоторые группы находятся в AD, но не отображают команду gpresult / r. Может разрешение?

Xiao Han 07.05.2018 17:26

Быстрый вопрос, эта строка кода в Startup.cs: var cookiesConfig = this.Configuration.GetSection ("cookies"). Get <CookiesConfig> (‌); Я предполагаю, что «cookies» - это имя раздела в файле конфигурации, является ли CookiesConfig настраиваемым классом для хранения данных конфигурации?

Xiao Han 09.05.2018 21:10

@XiaoHan: да, смотри мои обновления. И да, CookiesConfig - это просто класс, свойства которого совпадают со свойствами, определенными в файле appsettings.json, как и LdapConfig.

David Liang 09.05.2018 21:27

Если я буду следовать вашему подходу, означает ли это, что мне нужно указать атрибут авторизации, как в вашем примере: [Authorize (Policy = "AdminOnly")] для всего класса контроллера? Причина, по которой я думаю об использовании глобальной аутентификации / авторизации, заключается в том, чтобы не указывать везде авторизацию на основе политики / ролей. Возможно ли, что я все делаю в одном месте?

Xiao Han 09.05.2018 22:08

@XiaoHan: Нет, если ваш сайт не нуждается в защите с помощью ролей / политик, кроме аутентификации. И я уже настроил глобальный фильтр, для которого требуется RequireAuthenticatedUser(), поэтому ваш сайт должен быть защищен глобально от неаутентифицированных пользователей. Настройка политики AdminOnly приведена в примере, чтобы продемонстрировать, как вы можете защитить определенные области вашего сайта с помощью более конкретных ролей, таких как область Admin в примере. Обратите внимание, что даже пользователь аутентифицирован, если у него нет [ADMIN_ROLE_OF_YOUR_COMPANY], он не может получить доступ к области администратора. Английский - это сложно ..

David Liang 09.05.2018 22:12

Спасибо. Возможна ли авторизация на глобальном уровне? Точно так же, как аутентификация выполняется в Startup.cs, у меня есть настроенный код для проверки, принадлежит ли этот зарегистрированный пользователь к группе AD, которой сайт разрешает доступ к содержимому, если я вызываю функцию аналогичным образом в Startup.cs, Будет ли это проверять, авторизован ли вошедший в систему пользователь?

Xiao Han 09.05.2018 22:29

@XiaoHan: решать вам как разработчику, но если вы спросите меня, я разделю аутентификацию и авторизацию. Предыдущие структуры идентификации, такие как SimpleMembership и даже более ранние Asp.Net Identity 1.x, смешивали аутентификацию и авторизацию. Вы видите, что в Core 2.x они разделяются по уважительным причинам. Я имею в виду, что вы могли бы выполнить дополнительную проверку ролей внутри LdapAuthenticationService и вернуть Null в случае сбоя, но это не подходящее место для этого. LdapAuthenticationService предназначен для аутентификации! Лучшее место для этого - после .RequireAuthenticatedUser(). Смотрите обновления.

David Liang 09.05.2018 22:32

Спасибо, Дэвид. Я проверил ваши обновления в Startup.cs, так как в ваших комментариях сказано, что AddAuthorization предназначена «для защищенных более строгих областей. В противном случае они вам не нужны», поэтому, если я хочу аутентифицировать всех пользователей AD здесь, что было сделано вызывая RequireAuthenticatedUser, я хочу авторизовать только определенную группу пользователей AD, где вы рекомендуете реализовать логику? Я не уверен для каждого класса контроллера, я делаю что-то вроде проверки user.IsInGroup (groupname)? Или я могу сделать проверку в Startup.cs?

Xiao Han 10.05.2018 17:22

Я добавил несколько комментариев после .RequireAuthenticatedUser(). Вы видели их? В вашем случае вы могли бы авторизовать определенную группу пользователей AD, связав .RequireRole ("role1", "role2", "role3", ...) после .RequireAuthenticatedUser()? Поскольку .RequireAuthenticatedUser() и .RequireRole добавлены в глобальный фильтр, вам больше не нужно проверять, есть ли user.IsInGroup (). Если пользователь не входит в группу, то есть не авторизован, приложение должно выдать 403, что приведет к перенаправлению на accessDeniedPath в настройках файлов cookie из appsettings.json.

David Liang 10.05.2018 19:44

Попался. Я пробовал что-то вроде: var policy = new AuthorizationPolicyBuilder () .RequireAuthenticatedUser () .RequireRole ("[домен] [группа]") .Build (); config.Filters.Add (новый AuthorizeFilter (политика)); раньше, но не понял, почему не работает, я думаю, это было из-за того, что некоторые группы отображаются в AD Explorer, но не в gpresult / r. После того, как я добавил RequireRole () после RequireAuthenticatedUser, я получил ошибку «Не удалось установить доверительные отношения между основным доменом и доверенным доменом», похоже, это не удалось на System.Security.Principal.NTAccount.TranslateToSids. Нужно ли мне вместо этого использовать SID?

Xiao Han 10.05.2018 20:31

Я никогда не видел такой ошибки. Это вышло из вашего LdapAuthenticationService? Обратите внимание, что подход варианта 2 в основном заключается в том, чтобы сначала войти в систему с именем пользователя и паролем администратора (_config.Username / _config.Password), выполнить поиск, а затем войти в систему с найденным DN пользователя и его паролем из формы входа (user.DN / password). Также обратите внимание, что .RequireAuthenticatedUser() не выполняет аутентификацию за вас автоматически. Он просто задает задачу, чтобы ваше приложение перенаправляло на страницу входа. То же, что и .RequireRole(). Оно фактически проверяет утверждения, которые вы создаете для объекта principal.

David Liang 10.05.2018 20:36

Я не уверен, что это потому, что группа, которую я тестировал, отображается в проводнике AD (может быть список рассылки электронной почты), но не в gpresult / r. Другие группы, показанные в gpresult / r, которые я тестировал, работают. Я не использовал никакую другую службу аутентификации AD, только добавил RequireAuthenticatedUser () и RequireRole () для AuthorizationPolicyBuilder в ConfigureServices в Startup.cs и убедился, что аутентификация Windows верна в launchSettings.json.

Xiao Han 10.05.2018 21:19

Нет, если вы используете вариант 2, это должна быть проверка подлинности формы, а не проверка подлинности Windows. Вариант 1 предназначен для проверки подлинности Windows.

David Liang 10.05.2018 21:21

Если вы используете вариант 1, я не думаю, что код в разделе варианта 2 подходит для этого. С аутентификацией Windows вы в основном закончили без каких-либо дополнительных настроек. И единственная информация, которую вы можете получить, - это User.IsInRole() и User.Identity.Name. Из Microsoft Docs: «Когда проверка подлинности Windows включена и анонимный доступ отключен, атрибуты [Authorize] и [AllowAnonymous] не действуют». Теперь я помню, что в предыдущей версии .NET вы могли предоставить настроенные MembershipProvider и RoleProvider в web.config. Не уверен, что все еще возможно в .NET Core

David Liang 10.05.2018 21:36

Я пробую вариант 1, но с кодом, обновленным в исходном сообщении вверху, я обнаружил, что если использовать любую группу AD, возвращенную с помощью команды gpresult / r, она выдаст мне новую ошибку: InvalidOperationException: не было указано authenticationScheme, и была DefaultForbidScheme не найден. Я предполагаю, что предыдущая ошибка вызвана тем, что группа должна быть для рассылки электронной почты. Итак, чтобы устранить эту новую ошибку, я добавил services.AddAuthentication (IISDefaults.AuthenticationScheme) ‌; в ConfigureServices теперь я получаю страницу с сообщением HTTP 403. Веб-сайт отказался отображать эту веб-страницу, думаю, это то, что я хочу.

Xiao Han 10.05.2018 21:41

Другие вопросы по теме