ASP.NET MVC и аутентификация в смешанном режиме

StackOverflow https://stackoverflow.com/questions/2432845

  •  19-09-2019
  •  | 
  •  

Вопрос

У меня есть сценарий, в котором я требую, чтобы пользователи могли проходить аутентификацию в веб-приложении ASP.NET MVC, используя либо аутентификацию Windows, либо аутентификацию форм.Если пользователь находится во внутренней сети, он будет использовать проверку подлинности Windows, а если он подключается извне, он будет использовать проверку подлинности с помощью форм.Я видел довольно много людей, задавших вопрос, как мне настроить для этого веб-приложение ASP.NET MVC, но я не нашел полного объяснения.

Пожалуйста, может ли кто-нибудь предоставить подробное объяснение с примерами кода, как это можно сделать?

Спасибо.

Алан Т

Это было полезно?

Решение

Это называется смешанный режим аутентификации.По сути, вы не можете достичь этого в течение одинокий приложение, потому что в IIS после настройки проверки подлинности Windows для виртуального каталога он больше не будет принимать пользователей из разных доменов.Итак, по сути, вам нужно иметь два приложения: первое с проверкой подлинности Windows, а второе (основное приложение) с проверкой подлинности с помощью форм.Первое приложение будет состоять из одного адреса, который будет просто перенаправляться на основное приложение, выдавая билет аутентификации для пользователя домена.

Другие советы

Это можно сделать.Измените конфигурацию, настройте приложение/корень на использование анонимной аутентификации и аутентификации с помощью форм...Таким образом, вы можете настроить смешанную аутентификацию в одном веб-приложении, но это сложно.Итак, сначала настройте приложение для проверки подлинности с помощью форм с помощью loginUrl="~/WinLogin/WinLogin2.aspx".В MVC маршрутизация переопределяет правила аутентификации, установленные IIS, поэтому необходимо использовать страницу aspx, поскольку IIS может установить аутентификацию для файла.Включите анонимную аутентификацию и аутентификацию с помощью форм в корневом веб-приложении.Включите аутентификацию Windows и отключите анонимную аутентификацию в корневом каталоге/WinLogin.Добавьте пользовательские страницы ошибок 401 и 401.2 для перенаправления обратно на URL-адрес учетной записи/входа.

Это позволит любому браузеру, поддерживающему сквозную аутентификацию, использовать встроенную аутентификацию Windows для автоматического входа.В то время как на некоторых устройствах будут запрашиваться учетные данные (например, iPhone), а другие устройства, такие как Blackberry, будут перенаправлены на страницу входа.

При этом также создается файл cookie, явно добавляющий роли пользователей, и создается общий принцип, позволяющий использовать авторизацию на основе ролей.

в WinLogin2.aspx (в каталоге WinLogin в «корневом» веб-приложении в IIS и настроен на использование проверки подлинности 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;
            }
        }
    }

В IIS 7.5 нажмите «Страницы ошибок», установите для страницы 401 путь к файлу Redirect401.htm с помощью следующего кода:

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

В Аккаунтконтроллере...

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

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

веб.конфигурация

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

Вероятно, это будет внизу этого вопроса и никогда не будет найдено, но я смог реализовать то, что было описано в

http://mvolo.com/iis-70-twolevel-authentication-with-forms-authentication-and-windows-authentication/

Это было довольно легко и тривиально.Не требовалось несколько приложений или взлом файлов cookie, просто расширили FormsAuthModule и внесли некоторые изменения в web.config.

Я знаю, что это старый пост, но в Интернете все живет вечно!

В любом случае мне пришлось перенести старый веб-сайт с IIS6 на IIS8.Это веб-сайт WebForms, но я предполагаю, что это очень простое решение такое же.

Я получил ошибку:Невозможно привести объект типа «System.Security.Principal.WindowsIdentity» к типу «System.Web.Security.FormsIdentity».

Все, что я сделал, это создал новый пул приложений для веб-сайта.При создании я установил для режима управляемого конвейера значение «Классический».(Подробнее здесь - http://www.hanselman.com/blog/MovingOldAppsFromIIS6ToIIS8AndWhyClassicModeExists.aspx) Не забудьте установить в качестве пула приложений веб-сайта новый пул, который вы только что создали.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top