Как я могу аутентифицироваться в Active Directory в Нэнси?

Это устаревшая статья, но http://msdn.microsoft.com/en-us/library/ff650308.aspx#paght000026_step3 иллюстрирует то, что я хочу сделать. Я выбрал Nancy как свою веб-инфраструктуру из-за ее простоты и подхода с низкой оценкой. Итак, мне нужен способ аутентификации Active Directory с помощью Nancy.

В ASP.NET, похоже, вы можете просто переключаться между поставщиком членства на базе db и Active Directory только по некоторым параметрам в файле web.config. Мне это не нужно специально, но способность переключаться между dev и production будет потрясающей.

Как это можно сделать?

Ответ 1

Действительно, решение намного проще, чем может показаться. Просто подумайте о Active Directory как репозитории для своих пользователей (точно так же, как база данных). Все, что вам нужно сделать, это запрос AD, чтобы убедиться, что введенное имя пользователя и пароль действительны. SO, просто используйте Nancy Forms Validation и обрабатывайте связь с AD в вашей реализации IUserMapper. Вот что я придумал для своего пользовательского картографа:

public class ActiveDirectoryUserMapper : IUserMapper, IUserLoginManager
{
    static readonly Dictionary<Guid, long> LoggedInUserIds = new Dictionary<Guid, long>(); 

    readonly IAdminUserValidator _adminUserValidator;
    readonly IAdminUserFetcher _adminUserFetcher;
    readonly ISessionContainer _sessionContainer;

    public ActiveDirectoryUserMapper(IAdminUserValidator adminUserValidator, IAdminUserFetcher adminUserFetcher, ISessionContainer sessionContainer)
    {
        _adminUserValidator = adminUserValidator;
        _adminUserFetcher = adminUserFetcher;
        _sessionContainer = sessionContainer;
    }

    public IUserIdentity GetUserFromIdentifier(Guid identifier, NancyContext context)
    {
        _sessionContainer.OpenSession();
        var adminUserId = LoggedInUserIds.First(x => x.Key == identifier).Value;
        var adminUser = _adminUserFetcher.GetAdminUser(adminUserId);
        return new ApiUserIdentity(adminUser);
    }

    public Guid Login(string username, string clearTextPassword, string domain)
    {
        var adminUser = _adminUserValidator.ValidateAndReturnAdminUser(username, clearTextPassword, domain);
        var identifier = Guid.NewGuid();
        LoggedInUserIds.Add(identifier, adminUser.Id);
        return identifier;
    }
}

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

public class AdminUserValidator : IAdminUserValidator
{
    readonly IActiveDirectoryUserValidator _activeDirectoryUserValidator;
    readonly IAdminUserFetcher _adminUserFetcher;

    public AdminUserValidator(IAdminUserFetcher adminUserFetcher,
                              IActiveDirectoryUserValidator activeDirectoryUserValidator)
    {
        _adminUserFetcher = adminUserFetcher;
        _activeDirectoryUserValidator = activeDirectoryUserValidator;
    }

    #region IAdminUserValidator Members

    public AdminUser ValidateAndReturnAdminUser(string username, string clearTextPassword, string domain)
    {
        _activeDirectoryUserValidator.Validate(username, clearTextPassword, domain);

        return _adminUserFetcher.GetAdminUser(1);            
    }

    #endregion
}

И этот класс фактически проверяет, что комбинация имени пользователя и пароля существует в Active Directory:

public class ActiveDirectoryUserValidator : IActiveDirectoryUserValidator
{
    public void Validate(string username, string clearTextPassword, string domain)
    {
        using (var principalContext = new PrincipalContext(ContextType.Domain, domain))
        {
            // validate the credentials
            bool isValid = principalContext.ValidateCredentials(username, clearTextPassword);
            if (!isValid)
                throw new Exception("Invalid username or password.");
        }

    }
}