문제

사용자가 Windows 인증 또는 양식 인증을 사용하여 ASP.NET MVC 웹 응용 프로그램에 대해 인증 할 수 있어야하는 시나리오가 있습니다. 사용자가 내부 네트워크에 있으면 Windows 인증을 사용하고 외부로 연결하는 경우 양식 인증을 사용합니다. 이를 위해 ASP.NET MVC 웹 애플리케이션을 어떻게 구성하는지 질문하는 사람들이 꽤 많이 보았지만 완전한 설명을 찾지 못했습니다.

누군가가 코드 예제와 함께이 작업이 어떻게 이루어질 지에 대한 자세한 설명을 제공 할 수 있습니까?

감사.

앨런 t

도움이 되었습니까?

해결책

이것은 ... 불리운다 혼합 인증 모드. 기본적으로 당신은 이것을 달성 할 수 없습니다 하나의 IIS에서 가상 디렉토리에 대한 Windows 인증을 설정하면 응용 프로그램은 더 이상 다른 도메인에서 사용자를 허용하지 않습니다. 따라서 기본적으로 Windows 인증이있는 첫 번째 응용 프로그램과 양식 인증을 사용하여 두 번째 응용 프로그램이 필요합니다. 첫 번째 애플리케이션은 단일 주소로 구성되며 도메인 사용자에 대한 인증 티켓을 발행하여 기본 응용 프로그램으로 간단하게 리디렉션됩니다.

다른 팁

이것은 할 수 있습니다. 구성을 되돌리고 익명 및 양식 인증을 사용하도록 앱/루트를 설정하십시오 ... 이러한 방식으로 동일한 웹 응용 프로그램 내에서 혼합 인증을 구성 할 수 있지만 까다 롭습니다. 먼저 LoginUrl = "~/winlogin/winlogin2.aspx"를 사용하여 Forms 인증에 대한 앱을 구성하십시오. MVC에서 라우팅은 IIS에서 설정 한 인증 규칙을 무시하므로 IIS가 파일에서 인증을 설정할 수 있으므로 ASPX 페이지를 사용해야합니다. 루트 웹 응용 프로그램에서 익명 및 양식 인증을 활성화합니다. Root/Winlogin 디렉토리에서 Windows 인증을 활성화하고 익명 인증을 비활성화합니다. Custom 401 및 401.2 오류 페이지를 추가하여 계정/서명 URL로 다시 리디렉션하십시오.

이를 통해 통과 할 수있는 브라우저는 Windows 통합 인증을 자동 서명에 사용할 수 있습니다. 일부 장치는 자격 증명 (iPhone과 같은) 및 BlackBerry와 같은 다른 장치가 사인 페이지로 리디렉션됩니다.

또한 사용자 역할을 명시 적으로 추가하는 쿠키를 생성하고 역할 기반 인증을 사용할 수 있도록 일반적인 원칙을 만듭니다.

winlogin2.aspx (IIS의 "루트"웹 응용 프로그램의 Winlogin 디렉토리에서 Windows 인증, 익명 비활성화 및 양식을 사용하도록 구성된 (Windows 인증을 활성화 할 때 Note IIS는 불만을 제기합니다. 그냥 무시해) :

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 페이지를 리디렉션 401.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>

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

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

이것은 아마도이 질문의 맨 아래에 살 것이며 결코 찾을 수 없지만 설명한 것을 구현할 수있었습니다.

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

아주 쉽고 사소했습니다. 여러 응용 프로그램이나 쿠키 해킹이 필요하지 않았으며 FormsAuthModule을 확장하고 Web.Config 변경 만 수행합니다.

나는 이것이 오래된 게시물이라는 것을 알고 있습니다. 그러나 모든 것이 인터넷에서 영원히 살고 있습니다!

어쨌든, 나는 이전 웹 사이트를 IIS6에서 IIS8로 옮겨야했습니다. 이것은 WebForms 웹 사이트이지만이 매우 간단한 솔루션이 동일하다고 생각합니다.

'System.security.principal.windowsidentity'유형의 객체를 캐스트 할 수 없습니다.

내가 한 것은 웹 사이트를위한 새로운 애플리케이션 풀을 만드는 것뿐입니다. 이를 만들 때 관리 된 파이프 라인 모드를 '클래식'으로 설정했습니다. (여기에서 자세히 알아보십시오 - http://www.hanselman.com/blog/movingoldappsfromiis6toiis8andwhyclassicmodeexists.aspx) 웹 사이트의 애플리케이션 풀을 방금 만든 새 풀로 설정하는 것을 잊지 마십시오.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top