ASP.NET MVC和混合模式身份验证

Ala*_*n T 24 asp.net-mvc mixed-mode

我有一个场景,我要求用户能够使用Windows身份验证或Forms身份验证对ASP.NET MVC Web应用程序进行身份验证.如果用户在内部网络上,他们将使用Windows身份验证,如果他们在外部连接,他们将使用Forms身份验证.我见过很多人问这个问题我如何为此配置ASP.NET MVC Web应用程序,但我还没有找到完整的解释.

有人可以通过代码示例提供有关如何完成此操作的详细说明吗?

谢谢.

艾伦T.

Dar*_*rov 17

这称为混合认证模式.基本上,您无法在单个应用程序中实现此目的,因为在IIS中为虚拟目录设置Windows身份验证后,它将不再接受来自不同域的用户.所以基本上你需要有两个应用程序,第一个使用Windows身份验证,第二个(主应用程序)使用Forms身份验证.第一个应用程序将由单个地址组成,该地址将通过为域用户发出身份验证票证而直接重定向到主应用程序.


小智 15

这可以做到.反转配置,将app/root设置为使用匿名和表单身份验证...这样,您可以在同一个Web应用程序中配置混合身份验证,但这很棘手.首先,使用loginUrl ="〜/ WinLogin/WinLogin2.aspx"为您配置表单身份验证的应用程序.在MVC中,路由会覆盖IIS设置的身份验证规则,因此需要使用aspx页面,因为IIS可以在文件上设置身份验证.在根Web应用程序上启用匿名和表单身份验证.启用Windows身份验证并禁用root/WinLogin目录中的匿名身份验证.添加自定义401和401.2错误页面以重定向回帐户/登录URL.

这将允许任何能够传递的浏览器使用Windows集成身份验证来自动登录.虽然某些设备会被提示输入凭据(如iPhone)和其他设备,如黑莓重定向到登录页面.

这还会创建一个cookie,显式添加用户角色并创建一个通用原则,以便可以使用基于角色的授权.

在WinLogin2.aspx中(在IIS中的"根"Web应用程序下的WinLogin目录中,并配置为使用Windows身份验证,禁用匿名和启用表单(因为无法关闭...注意IIS将在您启用Windows身份验证时抱怨,直接无视(好了) :

var logonUser = Request.ServerVariables["LOGON_USER"];
if (!String.IsNullOrWhiteSpace(logonUser))
{
    if (logonUser.Split('\\').Length > 1)
    {
        var domain = logonUser.Split('\\')[0];
        var username = logonUser.Split('\\')[1];

        var timeout = 30;

        var encTicket = CreateTicketWithSecurityGroups(false, username, domain, timeout);

        var authCookie = new HttpCookie(".MVCAUTH", encTicket) { HttpOnly = true };
        Response.Cookies.Add(authCookie);
    }
    //else
    //{
    // this is a redirect due to returnUrl being WinLogin page, in which logonUser will no longer have domain attached
    // ignore as forms ticket should already exist
    //}

    string returnUrl = Request.QueryString["ReturnUrl"];

    if (returnUrl.IsEmpty())
    {
        Response.Redirect("~/");
    }
    else
    {
        Response.Redirect(returnUrl);
    }
}

public static string CreateTicketWithSecurityGroups(bool rememberMe, string username, string domain, int timeout)
{
    using (var context = new PrincipalContext(ContextType.Domain, domain))
    {
        using (var principal = UserPrincipal.FindByIdentity(context, IdentityType.SamAccountName, username))
        {
            var securityGroups = String.Join(";", principal.GetAuthorizationGroups());

            var ticket =
                new FormsAuthenticationTicket(1,
                                                username,
                                                DateTime.UtcNow,
                                                DateTime.UtcNow.AddMinutes(timeout),
                                                rememberMe,
                                                securityGroups,
                                                "/");

            string encTicket = FormsAuthentication.Encrypt(ticket);
            return encTicket;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在IIS 7.5中,单击"错误页面",将401页面设置为Redirect401.htm文件的文件路径,使用以下代码:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
    <script>
      window.location.assign('../Account/Signin');
    </script>
</head>
<body>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)

在AccountController中......

public ActionResult SignIn()
{
    return View(new SignInModel());
}

//
// POST: /Account/SignIn
[HttpPost]
public ActionResult SignIn(SignInModel model, string returnUrl)
{
    if (ModelState.IsValid)
    {
        if (Membership.ValidateUser(model.UserName, model.Password))
        {
            string encTicket = CreateTicketWithSecurityGroups(model.RememberMe,  model.UserName, model.Domain, FormsAuthentication.Timeout.Minutes);

            Response.Cookies.Add(new HttpCookie(".MVCAUTH", encTicket));

            //var returnUrl = "";
            for (var i = 0; i < Request.Cookies.Count; i++)
            {
                HttpCookie cookie = Request.Cookies[i];
                if (cookie.Name == ".MVCRETURNURL")
                {
                    returnUrl = cookie.Value;
                    break;
                }
            }

            if (returnUrl.IsEmpty())
            {
                return Redirect("~/");
            }

            return Redirect(returnUrl);
        }

        ModelState.AddModelError("Log In Failure", "The username/password combination is invalid");
    }

    return View(model);
}

//
// GET: /Account/SignOut
public ActionResult SignOut()
{
    FormsAuthentication.SignOut();

    if (Request.Cookies[".MVCRETURNURL"] != null)
    {
        var returnUrlCookie = new HttpCookie(".MVCRETURNURL") { Expires = DateTime.Now.AddDays(-1d) };
        Response.Cookies.Add(returnUrlCookie);
    }

    // Redirect back to sign in page so user can 
    //   sign in with different credentials

    return RedirectToAction("SignIn", "Account");
}
Run Code Online (Sandbox Code Playgroud)

在global.asax中:

protected void Application_BeginRequest(object sender, EventArgs e)
{
    try
    {
        bool cookieFound = false;

        HttpCookie authCookie = null;

        for (int i = 0; i < Request.Cookies.Count; i++)
        {
            HttpCookie cookie = Request.Cookies[i];
            if (cookie.Name == ".MVCAUTH")
            {
                cookieFound = true;
                authCookie = cookie;
                break;
            }
        }

        if (cookieFound)
        {
            // Extract the roles from the cookie, and assign to our current principal, which is attached to the HttpContext.
            FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(authCookie.Value);
            HttpContext.Current.User = new GenericPrincipal(new FormsIdentity(ticket), ticket.UserData.Split(';'));
        }
    }
    catch (Exception ex)
    {
        throw;
    }
}


protected void Application_AuthenticateRequest()
{
    var returnUrl = Request.QueryString["ReturnUrl"];
    if (!Request.IsAuthenticated && !String.IsNullOrWhiteSpace(returnUrl))
    {
        var returnUrlCookie = new HttpCookie(".MVCRETURNURL", returnUrl) {HttpOnly = true};
        Response.Cookies.Add(returnUrlCookie);
    }
}
Run Code Online (Sandbox Code Playgroud)

web.config中

<system.web>
  <!--<authorization>
    <deny users="?"/>
  </authorization>-->
  <authentication mode="Forms">
    <forms name=".MVCAUTH" loginUrl="~/WinLogin/WinLogin2.aspx" timeout="30" enableCrossAppRedirects="true"/>
  </authentication>
  <membership defaultProvider="AspNetActiveDirectoryMembershipProvider">
    <providers>
      <add
           name="AspNetActiveDirectoryMembershipProvider"
           type="System.Web.Security.ActiveDirectoryMembershipProvider, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
           connectionStringName="ADService" connectionProtection="Secure" enablePasswordReset="false" enableSearchMethods="true" requiresQuestionAndAnswer="true"
           applicationName="/" description="Default AD connection" requiresUniqueEmail="false" clientSearchTimeout="30" serverSearchTimeout="30"
           attributeMapPasswordQuestion="department" attributeMapPasswordAnswer="division" attributeMapEmail="mail" attributeMapUsername="sAMAccountName"
           maxInvalidPasswordAttempts="5" passwordAttemptWindow="10" passwordAnswerAttemptLockoutDuration="30" minRequiredPasswordLength="7"
           minRequiredNonalphanumericCharacters="1" />
    </providers>
  </membership>
  <machineKey decryptionKey="..." validationKey="..." />
</system.web>
<connectionStrings>
  <add name="ADService" connectionString="LDAP://SERVER:389"/>
</connectionStrings>
Run Code Online (Sandbox Code Playgroud)

信用欠http://msdn.microsoft.com/en-us/library/ms972958.aspx