Pregunta

Tengo un escenario en el que requiero usuarios puedan autenticarse en una aplicación Web ASP.NET MVC mediante autenticación de Windows o la autenticación de formularios. Si el usuario está en la red interna van a utilizar la autenticación de Windows y si se están conectando externamente van a utilizar la autenticación de formularios. He visto un buen número de gente que pide la pregunta ¿Cómo se configura una aplicación Web ASP.NET MVC para esto, pero no he encontrado una explicación completa.

Por favor, alguien puede proporcionar una explicación detallada, con ejemplos de código, en la forma en que esto se haría?

Gracias.

Alan T

¿Fue útil?

Solución

Esto se llama modo de autenticación mixta . Básicamente no se puede lograr esto dentro de un solo aplicación porque en IIS después de configurar la autenticación de Windows para un directorio virtual ya no aceptará usuarios de diferentes dominios. Así que, básicamente, es necesario tener dos aplicaciones, la primera con la autenticación de Windows y la segunda (la aplicación principal) utilizando la autenticación de formularios. La primera aplicación consistirá en una única dirección que se limitará a redirigir a la aplicación principal mediante la emisión de un billete de autenticación para el usuario de dominio.

Otros consejos

Esto se puede hacer. Revertir la configuración, configurar la aplicación / root para uso anónimo y Autenticación de formularios ... De esta manera, se puede configurar la autenticación mixta dentro de la misma aplicación web, pero es complicado. Así que, primero, se configura la aplicación para la autenticación de formularios con loginUrl = "~ / WinLogin / WinLogin2.aspx". En MVC, enrutamiento anula reglas de autenticación definidas por IIS, por lo que es necesario utilizar una página aspx, como IIS puede configurar la autenticación en el archivo. Habilitar anónimo y autenticación de formularios de la aplicación web raíz. Habilitar la autenticación de Windows y desactivar la autenticación anónima en el directorio / WinLogin raíz. Añadir personalizados 401 y 401.2 páginas de error para redirigir de nuevo a la Cuenta / Signin URL.

Esto permitirá que cualquier navegador capaz de paso a través para utilizar la autenticación de Windows integrada a signin automático. Mientras que algunos dispositivos conseguirán le solicitan credenciales (como el iPhone) y otros dispositivos como Blackberry redirigido a la página de acceso.

Esto también crea una cookie añadiendo explícitamente los roles de los usuarios y crea un principio genérico de manera que la autorización basada en roles se puede utilizar.

en WinLogin2.aspx (en el directorio WinLogin bajo la aplicación web "raíz" en IIS, y configurado para utilizar la autenticación de Windows, Anónimo deshabilitado y habilitado formularios (como no se puede apagar ... note IIS se quejará cuando se habilita La autenticación de windows, simplemente ignorar):

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;
            }
        }
    }

En IIS 7.5, haga clic en las páginas de error, establecer la página 401 a la ruta del archivo Archivo Redirect401.htm, con este código:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org /TR/xhtml1/DTD/xhtml1-transitional.dtd">

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

  </body>
   </html>

En 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");

En 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);
        }
    }

web.config

<!--<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>

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

Esto probablemente viven en el fondo de esta cuestión y nunca ser encontrado pero yo era capaz de poner en práctica lo que se describió en el

http://mvolo.com / iis-70-twolevel-autenticación-con-formas-autenticación-y-windows-autenticación /

Fue bastante fácil y trivial. No requerir múltiples aplicaciones o hacks para galletas, simplemente extendiendo el FormsAuthModule y hacer algunos cambios web.config.

Sé que esto es una entrada antigua - pero todo permanece para siempre en el Internet

!

De todos modos, tenía que mover un sitio web de edad, de IIS6 a IIS8. Este es un sitio Web Forms, pero supongo que esta solución muy simple es el mismo.

he recibido el error:. No se puede convertir objeto de tipo 'System.Security.Principal.WindowsIdentity' al tipo 'System.Web.Security.FormsIdentity'

Todo lo que hice fue crear un nuevo grupo de aplicaciones para el sitio web. Al crear esto, establecer el modo de canalización administrada a 'Classic'. (Lea más aquí - http://www.hanselman.com/blog/MovingOldAppsFromIIS6ToIIS8AndWhyClassicModeExists.aspx) No se olvide de configurar el grupo de aplicaciones de la página web a la nueva piscina que acaba de crear.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top