Pergunta

Eu tenho um cenário em que eu exigir que os usuários ser capaz de autenticar contra uma aplicação web ASP.NET MVC usando autenticação ou autenticação de formulários do Windows. Se o usuário estiver na rede interna eles vão usar a autenticação do Windows e se eles estão se conectando externamente eles vão usar a autenticação de formulários. Eu vi algumas pessoas fazendo a pergunta como faço para configurar uma aplicação web ASP.NET MVC para isso, mas eu não encontrei uma explicação completa.

Por favor, alguém pode fornecer uma explicação detalhada, com exemplos de código, sobre como isso seria feito?

Graças.

Alan T

Foi útil?

Solução

Isso é chamado modo de autenticação misto . Basicamente, você não pode conseguir isso dentro de um única aplicação, porque no IIS quando você configurar a autenticação do Windows para um diretório virtual que não aceitará mais usuários de diferentes domínios. Então, basicamente você precisa ter duas aplicações, o primeiro com a autenticação do Windows e o segundo (o aplicativo principal) usando a autenticação de formulários. A primeira aplicação será composto de um único endereço que simplesmente redirecionar para o aplicativo principal através da emissão de um bilhete de autenticação para o usuário de domínio.

Outras dicas

Isto pode ser feito. Reverter a configuração, definir o app / root para usar a autenticação anônima e formulários ... Desta forma, você pode configurar a autenticação mista dentro da mesma aplicação web, mas é complicado. Então, primeiro, configure você app para autenticação de formulários com loginUrl = "~ / WinLogin / WinLogin2.aspx". No MVC, regras de autenticação de roteamento substituições definido pelo IIS, por isso necessidade de usar uma página aspx, como IIS pode configurar a autenticação no arquivo. Habilitar autenticação anônima e formulários sobre a aplicação raiz web. Habilitar a autenticação do Windows e autenticação anônima disable na raiz diretório / WinLogin. Adicionar personalizados 401 e 401.2 páginas de erro para redirecionar de volta para a Conta / Signin URL.

Isso permitirá que qualquer navegador capaz de pass-through para o Windows usar a autenticação integrada para auto início de sessão. Enquanto alguns dispositivos vai ser solicitado para credenciais (como o iPhone) e outros dispositivos como amora redirecionado para a página de login.

Isso também cria um cookie acrescentando explicitamente os papéis de usuários e cria um princípio genérico de modo que a autorização baseada em função pode ser usado.

em WinLogin2.aspx (no diretório WinLogin sob a aplicação web "root" no IIS, e configurado para usar autenticação do Windows, anónimo desactivado e Formas habilitado (como não pode desligar ... nota IIS vai reclamar quando você habilita autenticação do Windows, apenas ignore):

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

Em IIS 7.5, clique em páginas de erro, defina a página 401 a caminho do arquivo do Redirect401.htm, com 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>

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

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

Crédito devido a http://msdn.microsoft.com/en-us /library/ms972958.aspx

Isto irá provavelmente ao vivo no fundo desta questão e nunca ser encontrado, mas eu era capaz de implementar o que foi descrito em

http://mvolo.com / iis-70-twolevel-autenticação-com-formas-autenticação de e-windows-autenticação /

Foi muito fácil e trivial. não requerem múltiplas aplicações ou hacks de biscoito, apenas estendendo o FormsAuthModule e fazer algumas mudanças web.config.

Eu sei que este é um post antigo - mas tudo vive para sempre na internet

De qualquer forma, eu tive que mudar um site antigo do IIS6 para IIS8. Este é um site WebForms, mas presumo que esta solução muito simples é o mesmo.

recebi o erro: Não é possível objeto fundido do tipo 'System.Security.Principal.WindowsIdentity' para digitar 'System.Web.Security.FormsIdentity'

.

Tudo que fiz foi criar um novo pool de aplicativos para o site. Ao criar este, eu definir o modo de pipeline gerenciado para 'Classic'. (Leia mais aqui - http://www.hanselman.com/blog/MovingOldAppsFromIIS6ToIIS8AndWhyClassicModeExists.aspx) Não se esqueça de definir pool de aplicativos do site para a nova piscina que você acabou de criar.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top