2010-03-12 30 views
22

Tôi có một kịch bản theo đó tôi yêu cầu người dùng có thể xác thực đối với ứng dụng web ASP.NET MVC bằng cách sử dụng xác thực Windows hoặc Xác thực mẫu. Nếu người dùng trên mạng nội bộ họ sẽ sử dụng xác thực Windows và nếu họ đang kết nối bên ngoài, họ sẽ sử dụng Xác thực biểu mẫu. Tôi đã thấy một vài người hỏi câu hỏi làm thế nào để cấu hình một ứng dụng web ASP.NET MVC cho điều này, nhưng tôi đã không tìm thấy một lời giải thích đầy đủ.ASP.NET MVC và xác thực chế độ hỗn hợp

Xin vui lòng ai đó có thể cung cấp giải thích chi tiết, với các ví dụ về mã, về cách thực hiện điều này?

Cảm ơn.

Alan T

Trả lời

14

Điều này được gọi là mixed authentication mode. Về cơ bản, bạn không thể đạt được điều này trong một ứng dụng đơn vì trong IIS khi bạn thiết lập xác thực Windows cho một thư mục ảo, nó sẽ không còn chấp nhận người dùng từ các miền khác nhau. Vì vậy, về cơ bản bạn cần phải có hai ứng dụng, đầu tiên với Windows Authentication và lần thứ hai (ứng dụng chính) sử dụng xác thực Forms. Ứng dụng đầu tiên sẽ bao gồm một địa chỉ đơn giản sẽ chuyển hướng đến ứng dụng chính bằng cách phát hành một vé xác thực cho người dùng miền.

+0

Cảm ơn thông tin và liên kết. Tôi sẽ thử. –

+0

Điều này sẽ không hoạt động trong IIS7 sử dụng chế độ tích hợp: http://stackoverflow.com/questions/289317/iis7-and-authentication-problems –

+0

Tôi thấy rằng quá Garry. Tôi vẫn đang tìm kiếm một giải pháp cho điều này vì tôi có hai ứng dụng MVC bây giờ sẽ yêu cầu chức năng này. –

13

Điều này có thể được thực hiện. Đảo ngược cấu hình, đặt ứng dụng/gốc để sử dụng Xác thực Mẫu và Ẩn danh ... Bằng cách này, bạn có thể định cấu hình xác thực hỗn hợp trong cùng một ứng dụng web, nhưng nó rất phức tạp. Trước tiên, hãy định cấu hình ứng dụng của bạn cho Xác thực biểu mẫu bằng loginUrl = "~/WinLogin/WinLogin2.aspx". Trong MVC, định tuyến ghi đè các quy tắc xác thực được thiết lập bởi IIS, vì vậy cần sử dụng trang aspx, vì IIS có thể đặt xác thực trên tệp. Bật Xác thực Mẫu và Ẩn danh trên ứng dụng web gốc. Bật Xác thực Windows và tắt xác thực ẩn danh trong thư mục gốc/WinLogin. Thêm các trang lỗi 401 và 401.2 tùy chỉnh để chuyển hướng trở lại URL Tài khoản/Đăng nhập.

Điều này sẽ cho phép bất kỳ trình duyệt nào có khả năng truyền qua để sử dụng xác thực tích hợp cửa sổ để tự động đăng nhập. Trong khi một số thiết bị sẽ được nhắc về thông tin đăng nhập (như iPhone) và các thiết bị khác như blackberry được chuyển hướng đến trang đăng nhập.

Điều này cũng tạo một cookie rõ ràng thêm vai trò người dùng và tạo nguyên tắc chung để có thể sử dụng ủy quyền dựa trên vai trò.

trong WinLogin2.aspx (trong thư mục WinLogin trong ứng dụng web "root" trong IIS và được định cấu hình để sử dụng Xác thực Windows, Vô hiệu hóa ẩn danh và Biểu mẫu được bật (vì không thể tắt ... lưu ý IIS sẽ khiếu nại khi bạn cho phép cửa sổ xác thực, chỉ cần bỏ qua):

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

trong IIS 7.5, nhấp vào trang lỗi, thiết lập trang 401 file đường dẫn của file Redirect401.htm, với mã này:

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

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

Trong 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.cấu hình

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

tín dụng nợ http://msdn.microsoft.com/en-us/library/ms972958.aspx

+1

Xin chào - Bạn hiển thị tệp Redirect401.htm chuyển hướng qua tập lệnh được thêm. Bạn có thể không đạt được điều này bằng cách thiết lập xử lý lỗi cho 401.1 làm chuyển hướng không? Trong IIS, điều này có nghĩa là thay đổi tùy chọn 'trả lời bằng 302 chuyển hướng' cho trang lỗi 401. Được cho là sử dụng một url tuyệt đối, nhưng thân nhân gốc cũng hoạt động. –

4

Điều này có lẽ sẽ sống ở dưới cùng của câu hỏi này và không bao giờ được tìm thấy nhưng tôi đã có thể thực hiện những gì đã được mô tả ở

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

Nó khá dễ dàng và tầm thường. Không yêu cầu nhiều ứng dụng hoặc hack cookie, chỉ cần mở rộng FormsAuthModule và thực hiện một số thay đổi về web.config.

+1

Tôi nghĩ rằng kịch bản bạn đã đề cập khác với kịch bản được đề cập. xác thực hai cấp yêu cầu người dùng phải được xác thực bằng cả hai cửa sổ cũng như xác thực biểu mẫu. Tuy nhiên, chúng tôi yêu cầu dựa trên loại người dùng (intranet/internet), chúng phải được xác thực bằng xác thực dựa trên cửa sổ hoặc biểu mẫu – Samra

0

Tôi biết đây là một bài đăng cũ - nhưng mọi thứ đều tồn tại mãi mãi trên internet!

Dù sao, tôi phải di chuyển một trang web cũ từ IIS6 sang IIS8. Đây là một trang web WebForms, nhưng tôi cho rằng giải pháp rất đơn giản này là như nhau.

Tôi đã nhận được lỗi: Không thể truyền đối tượng thuộc loại 'System.Security.Principal.WindowsIdentity' để nhập 'System.Web.Security.FormsIdentity'.

Tất cả những gì tôi đã làm là tạo một hồ bơi ứng dụng mới cho trang web. Khi tạo điều này, tôi đặt chế độ Quản lý đường ống thành 'Cổ điển'. (Đọc thêm tại đây - http://www.hanselman.com/blog/MovingOldAppsFromIIS6ToIIS8AndWhyClassicModeExists.aspx) Đừng quên thiết lập hồ bơi ứng dụng của trang web cho nhóm mới mà bạn vừa tạo.

Các vấn đề liên quan