2010-03-12 44 views
22

我有一種情況,其中我需要用戶能夠對使用Windows身份驗證或窗體身份驗證的ASP.NET MVC的Web應用程序進行身份驗證。如果用戶在內部網絡上,他們將使用Windows身份驗證,如果他們在外部連接,他們將使用表單身份驗證。我見過不少人問這個問題,我如何爲此配置一個ASP.NET MVC Web應用程序,但我還沒有找到完整的解釋。ASP.NET MVC和混合模式身份驗證

請有人可以提供詳細的解釋,有代碼實例,如何做到這一點呢?

謝謝。

艾倫牛逼

回答

14

這就是所謂的mixed authentication mode。基本上你不能在應用程序中,因爲在IIS一旦您設置Windows身份驗證的虛擬目錄,將不再接受來自不同域的用戶實現這一目標。所以基本上你需要有兩個應用程序,第一個使用Windows身份驗證,第二個使用表單身份驗證(主應用程序)。第一個應用程序將包含一個地址,該地址將通過爲域用戶發佈身份驗證票據而簡單地重定向到主應用程序。

+0

感謝您的信息和鏈接。我會試一試。 – 2010-03-13 09:31:29

+0

這將無法在IIS7中使用集成模式:http://stackoverflow.com/questions/289317/iis7-and-authentication-problems – 2011-12-09 22:06:27

+0

我發現太Garry。我仍然在尋找一個解決方案,因爲我現在有兩個MVC應用程序需要這個功能。 – 2012-02-03 16:29:44

13

這是可以做到。反轉配置,將app/root設置爲使用匿名和表單身份驗證...通過這種方式,您可以在同一個Web應用程序中配置混合身份驗證,但這很棘手。因此,首先,使用loginUrl =「〜/ WinLogin/WinLogin2.aspx」配置您的Forms身份驗證應用程序。在MVC中,路由覆蓋由IIS設置的身份驗證規則,因此需要使用aspx頁面,因爲IIS可以在文件上設置身份驗證。在根Web應用程序上啓用匿名和表單身份驗證。啓用Windows身份驗證並禁用root/WinLogin目錄中的匿名身份驗證。添加自定義401和401.2錯誤頁面以重定向回帳戶/登錄URL。

這將使能夠傳遞到使用集成身份驗證自動登入窗口的任何瀏覽器。雖然有些設備會提示輸入憑據(如iPhone),而其他設備(如黑莓手機)會重定向到登錄頁面。

這也創造了一個cookie明確添加用戶的角色,並創建一個通用的原則,使基於角色的授權可以使用。 (WinLogin目錄下的WinLogin目錄下的「root」web應用程序中,並且配置爲使用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> 

在的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); 
     } 
    } 

網絡。配置

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

+1

嗨 - 您將通過添加的腳本顯示Redirect401.htm文件重定向。您是否可以通過將401.1的錯誤處理設置爲重定向來達到此目的? 在IIS中,這意味着要更改爲401錯誤頁面的'用302重定向響應'選項。據說使用絕對網址,但根相對也可以。 – 2012-06-13 09:43:43

4

這可能會住在這個問題的底部,永遠不會被發現,但我還是能夠實現什麼樣的

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

它被描述是相當簡單和微不足道的。不需要多個應用程序或cookie黑客,只需擴展FormsAuthModule並進行一些web.config更改即可。

+1

我認爲你提到的場景與有問題的場景不同。兩級身份驗證要求用戶使用兩個窗口以及表單身份驗證進行身份驗證。但是,我們要求基於用戶(Intranet/Internet)的類型,他們應該通過Windows或基於表單的身份驗證進行身份驗證 – Samra 2017-09-20 04:03:59

0

我知道這是一箇舊帖子 - 但所有東西都永遠活在互聯網上!

無論如何,我不得不將一箇舊的網站從IIS6移到IIS8。這是一個WebForms網站,但我認爲這個非常簡單的解決方案是一樣的。

我收到錯誤:無法將類型爲「System.Security.Principal.WindowsIdentity」的對象轉換爲鍵入「System.Web.Security.FormsIdentity」。

我所做的只是爲網站創建一個新的應用程序池。創建這個時,我將Managed pipeline模式設置爲'Classic'。 (在這裏閱讀更多 - http://www.hanselman.com/blog/MovingOldAppsFromIIS6ToIIS8AndWhyClassicModeExists.aspx)不要忘記將網站的應用程序池設置爲您剛剛創建的新池。