c# - 如何使用 ASP.NET MVC 伪造或模拟用户登录(身份验证)以进行功能测试

标签 c# asp.net-mvc asp.net-mvc-5 automated-tests asp.net-identity

我正在为 ASP.NET MVC 构建自定义权限系统,因为 MVC 附带的授权系统不够灵活,无法满足我们的需求。这包括与 View 、CSS 和 JavaScript 一起打包到 DLL 中的 MVC 区域。我已经进行了单元测试,但现在我正在尝试通过浏览器创建功能测试。这些功能测试将在我的计算机本地或持续集成服务器上运行。

我正在构建的权限系统不进行身份验证。它只是处理授权。理想情况下,我想为每个测试伪造用户登录。我想从任意用户名和密码创建一个用户 session ,而不是使用他们的密码保留一个单独的用户表,并针对它进行身份验证。

我尝试在 AccountController 的 session 中设置 GenericPrincipal 对象,然后在每次请求之前设置 HttpContext.Current.User,但是该请求始终被视为未经身份验证:

账户 Controller

[Authorize]
public class AccountController : Controller
{
    //
    // POST: /Account/Login
    [HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public ActionResult Login(LoginViewModel model, string ReturnUrl)
    {
        if (ModelState.IsValid)
        {
            FormsAuthentication.SetAuthCookie(model.Username, model.RememberMe);

            // Add the fake user to the current session so Global.asax can set
            // the user on the current HttpContext to this mock object. (See
            // Global.asax, Application_AcquireRequestState)
            HttpContext.Session["CurrentUser"] = new GenericPrincipal(new GenericIdentity(model.Username), new string[0]);

            if (Url.IsLocalUrl(ReturnUrl))
                return Redirect(ReturnUrl);

            return RedirectToAction("Index", "Home");
        }

        ModelState.AddModelError(string.Empty, "Username or Password is incorrect");

        return View(model);
    }
}

Global.asax

public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_AcquireRequestState(object sender, EventArgs e)
    {
        if (HttpContext.Current.Session != null)
        {
            // Try to get the mock user from the session, which is set in
            // AccountController.Login...
            HttpContext.Current.User = HttpContext.Current.Session["CurrentUser"] as IPrincipal;
        }
    }
}

我创建了一个自定义 Authorize 属性以在我的 MVC Controller 中使用:

public class PermissionLevelAttribute : System.Web.Mvc.AuthorizeAttribute
{
    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        if (!filterContext.HttpContext.Request.IsAuthenticated || CurrentPrincipal == null)
        {
            base.OnAuthorization(filterContext);

            return;
        }

        // Custom permissions logic...
    }
}

Controller 中此属性的示例用法:

public class BlogPostsController : Controller
{
    [PermissionLevel(Roles="Blogs.Posts.Edit.Update")]
    public ActionResult Edit(int id)
    {
        // ...
    }
}

当我执行此操作时,filterContext.HttpContext.Request.IsAuthenticated 属性始终为 false,并且它会退出 OnAuthorization 方法。


如何在 ASP.NET MVC 中伪造或模拟用户登录,以便创建 HttpContext.Current.Session 对象并设置 HttpContext.Current.User

最佳答案

这个解决方案并没有真正创建一个“模拟”用户,而是创建了一个假用户并且不检查用户名和密码。为此,您需要进行两项主要更改:

  1. 重写 AccountController,使其实际上不检查用户名和密码

    [Authorize]
    public class AccountController : Controller
    {
        //
        // GET: /Account/Login
        [AllowAnonymous]
        public ActionResult Login(string returnUrl)
        {
            ViewBag.ReturnUrl = returnUrl;
            return View();
        }
    
        //
        // POST: /Account/Login
        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public ActionResult Login(LoginViewModel model, string ReturnUrl)
        {
            if (ModelState.IsValid)
            {
                FormsAuthentication.SetAuthCookie(model.Username, model.RememberMe);
    
                if (Url.IsLocalUrl(ReturnUrl))
                    return Redirect(ReturnUrl);
    
                return RedirectToAction("Index", "Home");
            }
    
            ModelState.AddModelError(string.Empty, "Username or Password is incorrect");
    
            return View(model);
        }
    
        //
        // GET: /Account/LogOff
        public ActionResult LogOff()
        {
            FormsAuthentication.SignOut();
    
            return RedirectToAction("Index", "Home");
        }
    }
    
  2. 删除或注释掉 Web.config 中与 OWIN 相关的配置设置:

    <configuration>
      <system.webServer>
        <modules>
          <!--<remove name="FormsAuthentication" />-->
        </modules>
      </system.webServer>
      <runtime>
        <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
          <!--<dependentAssembly>
            <assemblyIdentity name="Microsoft.Owin.Security" publicKeyToken="31bf3856ad364e35" />
            <bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
          </dependentAssembly>
          <dependentAssembly>
            <assemblyIdentity name="Microsoft.Owin.Security.OAuth" publicKeyToken="31bf3856ad364e35" />
            <bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
          </dependentAssembly>
          <dependentAssembly>
            <assemblyIdentity name="Microsoft.Owin.Security.Cookies" publicKeyToken="31bf3856ad364e35" />
            <bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
          </dependentAssembly>
          <dependentAssembly>
            <assemblyIdentity name="Microsoft.Owin" publicKeyToken="31bf3856ad364e35" />
            <bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
          </dependentAssembly>-->
        </assemblyBinding>
      </runtime>
    </configuration>
    

这将允许您以任意用户身份使用任意密码登录。

重要提示:显然,我不会为 Web 应用程序的生产版本执行此操作。我正在构建一个 MVC 区域作为 NuGet 包,并将该包安装在一个干净的 MVC 项目上,以针对集成的 NuGet 包和 MVC 应用程序编写自动化测试。这就是我能够使用此解决方案的原因。

关于c# - 如何使用 ASP.NET MVC 伪造或模拟用户登录(身份验证)以进行功能测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35039978/

相关文章:

c# - 如果返回格式是 xml,如何删除 web api 中的模式节点?

c# - 字典和获取一种类型的值

c# - 按升序排列 List<>

c# - 按\t 拆分字符串 - 连续的制表符会导致问题吗?

c# - 如何在 C# mvc 中将 Json 结果转换为对象

c# - ASP.NET MVC 2 - Html.EditorFor 可空类型?

jquery - 根据字段值动态生成超链接的查询字符串

c# - 使 Controller 异步的最简单方法

c# - 代码首次尝试创建数据库时出现异常

javascript - 如何全屏显示媒体播放器顶部的文本?