Насмешливый пользователь. Идентичность в ASP.NET MVC - PullRequest
38 голосов
/ 12 июня 2010

Мне нужно создать модульные тесты для веб-сайта ASP.NET MVC 2.0. Сайт использует проверку подлинности Windows.

Я читал о необходимости макетировать HTTP-контекст для кода, который работает с HttpContext. Я чувствую, что начинаю разбираться с паттерном DI. (Дайте классу атрибут типа IRepository, а затем передайте объект Repository при создании экземпляра контроллера.)

Однако я не понимаю, как правильно смоделировать объект Windows Principal, доступный через User.Identity. Это часть HttpContext?

Есть ли в теле текст ссылки на статью, демонстрирующую это (или рекомендацию для книги)?

Спасибо

Трей Кэрролл

Ответы [ 6 ]

31 голосов
/ 12 июня 2010

Я использовал IoC, чтобы абстрагироваться с некоторым успехом. Сначала я определил класс для представления текущего пользователя, вошедшего в систему:

public class CurrentUser
{
    public CurrentUser(IIdentity identity)
    {
        IsAuthenticated = identity.IsAuthenticated;
        DisplayName = identity.Name;

        var formsIdentity = identity as FormsIdentity;

        if (formsIdentity != null)
        {
            UserID = int.Parse(formsIdentity.Ticket.UserData);
        }
    }

    public string DisplayName { get; private set; }
    public bool IsAuthenticated { get; private set; }
    public int UserID { get; private set; }
}

Требуется IIdentity в конструкторе, чтобы установить его значения. Для модульных тестов вы можете добавить другой конструктор, чтобы обойти зависимость IIdentity.

А затем я использую Ninject (выберите ваш любимый контейнер IoC, не имеет значения) и создал привязку для IIdentity как таковую:

Bind<IIdentity>().ToMethod(c => HttpContext.Current.User.Identity);

Затем внутри моего контроллера я объявляю зависимость в конструкторе:

CurrentUser _currentUser;

public HomeController(CurrentUser currentUser)
{
    _currentUser = currentUser;
}

Контейнер IoC видит, что HomeController принимает объект CurrentUser, а конструктор CurrentUser принимает IIdentity. Это разрешит зависимости автоматически, и вуаля! Ваш контроллер может знать, кто в данный момент вошел в систему. Похоже, с FormsAuthentication у меня все работает очень хорошо. Возможно, вы сможете адаптировать этот пример для аутентификации Windows.

18 голосов
/ 21 июня 2013

Я не знаю, для MVC 2.0, но в более новых версиях вы можете издеваться над ControllerContext:

// create mock principal
var mocks = new MockRepository(MockBehavior.Default);
Mock<IPrincipal> mockPrincipal = mocks.Create<IPrincipal>();
mockPrincipal.SetupGet(p => p.Identity.Name).Returns(userName);
mockPrincipal.Setup(p => p.IsInRole("User")).Returns(true);

// create mock controller context
var mockContext = new Mock<ControllerContext>();
mockContext.SetupGet(p => p.HttpContext.User).Returns(mockPrincipal.Object);
mockContext.SetupGet(p => p.HttpContext.Request.IsAuthenticated).Returns(true);

// create controller
var controller = new MvcController() { ControllerContext = mock.Object };

см. Также Как выполнить модульное тестирование действия контроллера MVC, которое зависит от аутентификации в c #?

10 голосов
/ 12 июня 2010

Скотт Хансельман показывает в своем блоге , как использовать IPrincipal и ModelBinder, чтобы упростить тестирование контроллера путем насмешки над IPrincipal.

5 голосов
/ 21 марта 2014

Пример для имитации имени пользователя и SID на MVC4. Необходимо проверить имя пользователя и SID (аутентификация Windows) в следующем действии:

[Authorize]
public class UserController : Controller
{
    public ActionResult Index()
    {
        // get Username
        ViewBag.Username = User.Identity.Name;

        // get SID
        var lIdentity = HttpContext.User.Identity as WindowsIdentity;
        ViewBag.Sid = lIdentity.User.ToString();

        return View();
    }
}

Я использую Moq и Инструменты тестирования Visual Studio .Тест реализован следующим образом:

[TestMethod]
public void IndexTest()
{
    // Arrange
    var myController = new UserController();
    var contextMock = new Mock<ControllerContext>();
    var httpContextMock = new Mock<HttpContextBase>();
    var lWindowsIdentity = new WindowsIdentity("Administrator");

    httpContextMock.Setup(x => x.User).Returns(new WindowsPrincipal(lWindowsIdentity));

    contextMock.Setup(ctx => ctx.HttpContext).Returns(httpContextMock.Object);
    myController.ControllerContext = contextMock.Object;

    // Act
    var lResult = myController.Index() as ViewResult;

    // Assert
    Assert.IsTrue(lResult.ViewBag.Username == "Administrator");
    Assert.IsTrue(lResult.ViewBag.Sid == "Any SID Pattern");
}
1 голос
/ 31 января 2013

Я изменил среду разработки global.asax и Web.Config для использования FormsAuth для принудительного использования определенного пользователя. Имя пользователя использует тот же формат WindowsAuth. См:

public override void Init()
    {
        base.Init();

        this.PostAuthenticateRequest += 
             new EventHandler(MvcApplication_PostAuthenticateRequest);
    }

    void MvcApplication_PostAuthenticateRequest(object sender, EventArgs e)
    {
        FormsAuthentication.SetAuthCookie("Domain\\login", true);
    }

Для Windows или Forms Auth используются одинаковые шаблоны входа .

Приложение будет работать как с аутентификацией Windows, так и с аутентификацией формы.

0 голосов
/ 08 марта 2018

Чтобы смоделировать WindowsIdentity, вы можете сделать следующее:

var mockedPrincipal = new Mock<WindowsPrincipal>(WindowsIdentity.GetCurrent());

mockedPrincipal.SetupGet(x => x.Identity.IsAuthenticated).Returns(true);
mockedPrincipal.SetupGet(x => x.Identity.Name).Returns("Domain\\User1");
mockedPrincipal.Setup(x => x.IsInRole("Domain\\Group1")).Returns(true);
mockedPrincipal.Setup(x => x.IsInRole("Domain\\Group2")).Returns(false);

, а затем использовать mockedPrincipal.Object, чтобы получить WindowsIdentity

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...