在現有 ASP.NET MVC 4.6 Web 項目中實現 Active Directory 登錄
我必須使用 Active Directory 身份驗證更改我的 ASP.NET MVC + Knockout 應用程序的現有 (Windows) 登錄。它由 mvc 控制器和 webapi 控制器組成。兩者都必須經過身份驗證。
我想我會通過更改
forms authentication並創建一個登錄頁面來做到這一點,當使用者點擊登錄時,使用System.DirectoryServices.DirectoryEntry. 然後其他程序(如更改密碼、註冊等)也將獲得一個自定義 html 頁面並通過System.DirectoryServices.DirectoryEntry我們的 Active Directory 執行它們的操作。(也就是說,我找不到人們會這樣做的任何其他方式,而且我確實找到了一些會這樣做的人,這聽起來就像
forms authentication我以前見過的一樣。在這種情況下,使用者/密碼將不在數據庫表中,而是在 Active Directory 中。同樣的想法,通過 Active Directory 交換數據庫表)。為了了解在一個全新的項目中這將如何,我創建了一個新的 ASP.NET MVC 項目並選擇“工作或學校帳戶”(表示“用於使用 Active Directory 對使用者進行身份驗證的應用程序)並選擇“內部部署”。但是,我必須提供這些項目:
- 本地權限
- 應用 ID 網址
我不知道該怎麼辦。我唯一擁有的是一個活動目錄 url,例如
ldap://etc..這是另一種/更新/更好的活動目錄登錄方式嗎?還是唯一正確的(表單身份驗證錯誤?)還是錯誤的?
我糊塗了。
您可以使用以下方法在
ASP.NET MVC.***步驟1:***修改
AccountController如下所示的登錄方法(同時添加必要的引用):[HttpPost] [AllowAnonymous] [ValidateAntiForgeryToken] public async Task<ActionResult> Login(LoginViewModel model, string returnUrl) { try { if (!ModelState.IsValid) { return View(model); } // Check if the User exists in LDAP if (Membership.GetUser(model.UserName) == null) { ModelState.AddModelError("", "Wrong username or password"); return this.View(model); } ApplicationGroupManager groupManager = new ApplicationGroupManager(); // Validate the user using LDAP if (Membership.ValidateUser(model.UserName, model.Password)) { FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe); // FormsAuthentication.SetAuthCookie(model.UserName, false); // Check if the User exists in the ASP.NET Identity table (AspNetUsers) string userName = model.UserName.ToString().ToLower(new CultureInfo("en-US", false)); // When UserName is entered in uppercase containing "I", the user cannot be found in LDAP //ApplicationUser user = UserManager.FindByName(userName); ApplicationUser user = await UserManager.FindByNameAsync(userName); //Asynchronous method if (user == null) // If the User DOES NOT exists in the ASP.NET Identity table (AspNetUsers) { // Create a new user using the User data retrieved from LDAP // Create an array of properties that we would like and add them to the search object string[] requiredProperties = new string[] { "samaccountname", "givenname", "sn", "mail", "physicalDeliveryOfficeName", "title" }; var userInfo = CreateDirectoryEntry(model.UserName, requiredProperties); user = new ApplicationUser(); // For more information about "User Attributes - Inside Active Directory" : http://www.kouti.com/tables/userattributes.htm user.UserName = userInfo.GetDirectoryEntry().Properties["samaccountname"].Value.ToString(); user.Name = userInfo.GetDirectoryEntry().Properties["givenname"].Value.ToString(); user.Surname = userInfo.GetDirectoryEntry().Properties["sn"].Value.ToString(); user.Email = userInfo.GetDirectoryEntry().Properties["mail"].Value.ToString(); user.EmailConfirmed = true; //user.PasswordHash = null; //user.Department = GetDepartmentId(userInfo.GetDirectoryEntry().Properties["physicalDeliveryOfficeName"].Value.ToString()); //await Register(user); var result = await UserManager.CreateAsync(user); //Asynchronous method //If the User has succesfully been created //if (result.Succeeded) //{ // //var code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id); // //var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme); // //await UserManager.SendEmailAsync(user.Id, "Confirm your account", "Please confirm your account by clicking this link: <a href=\"" + callbackUrl + "\">link</a>"); // //ViewBag.Link = callbackUrl; // //return View("DisplayEmail"); //} // Define user group (and roles) var defaultGroup = "751b30d7-80be-4b3e-bfdb-3ff8c13be05e"; // Id of the ApplicationGroup for the Default roles //groupManager.SetUserGroups(newUser.Id, new string[] { defaultGroup }); await groupManager.SetUserGroupsAsync(user.Id, new string[] { defaultGroup }); //Asynchronous method //groupManager.SetGroupRoles(newGroup.Id, new string[] { role.Name }); } // !!! THERE IS NO NEED TO ASSIGN ROLES AS IT IS ASSIGNED AUTOMATICALLY IN ASP.NET Identity 2.0 //else // If the User exists in the ASP.NET Identity table (AspNetUsers) //{ // //##################### Some useful ASP.NET Identity 2.0 methods (for Info) ##################### // //ApplicationGroupManager gm = new ApplicationGroupManager(); // //string roleName = RoleManager.FindById("").Name; // Returns Role Name by using Role Id parameter // //var userGroupRoles = gm.GetUserGroupRoles(""); // Returns Group Id and Role Id by using User Id parameter // //var groupRoles = gm.GetGroupRoles(""); // Returns Group Roles by using Group Id parameter // //string[] groupRoleNames = groupRoles.Select(p => p.Name).ToArray(); // Assing Group Role Names to a string array // //############################################################################################### // // Assign Default ApplicationGroupRoles to the User // // As the default roles are already defined to the User after the first login to the system, there is no need to check if the role is NULL (otherwise it must be checked!!!) // //var groupRoles = groupManager.GetGroupRoles("751b30d7-80be-4b3e-bfdb-3ff8c13be05e"); // Returns Group Roles by using Group Id parameter // var groupRoles = await groupManager.GetGroupRolesAsync("751b30d7-80be-4b3e-bfdb-3ff8c13be05e"); // Returns Group Roles by using Group Id parameter (Asynchronous method) // foreach (var role in groupRoles) // { // //Assign ApplicationGroupRoles to the User // string roleName = RoleManager.FindById(role.Id).Name; // UserManager.AddToRole(user.Id, roleName); // } //} //Sign in the user await SignInAsync(user, model.RememberMe); if (this.Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/") && !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\")) { return this.Redirect(returnUrl); //return RedirectToLocal(returnUrl); } return this.RedirectToAction("Index", "Home"); } else { ModelState.AddModelError("", "Wrong username or password"); return this.View(model); } } catch (Exception ex) { TempData["ErrorMessage"] = ex.Message.ToString(); return View("Error", TempData["ErrorMessage"]); } } /* Since ASP.NET Identity and OWIN Cookie Authentication are claims-based system, the framework requires the app to generate a ClaimsIdentity for the user. ClaimsIdentity has information about all the claims for the user, such as what roles the user belongs to. You can also add more claims for the user at this stage. The highlighted code below in the SignInAsync method signs in the user by using the AuthenticationManager from OWIN and calling SignIn and passing in the ClaimsIdentity. */ private async Task SignInAsync(ApplicationUser user, bool isPersistent) { AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie); var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie); AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity); } static SearchResult CreateDirectoryEntry(string sAMAccountName, string[] requiredProperties) { DirectoryEntry ldapConnection = null; try { // Create LDAP connection object //ldapConnection = new DirectoryEntry("alpha.company.com"); ldapConnection = new DirectoryEntry("LDAP://OU=Company_Infrastructure, DC=company, DC=mydomain", "******", "******"); //ldapConnection.Path = connectionPath; ldapConnection.AuthenticationType = AuthenticationTypes.Secure; DirectorySearcher search = new DirectorySearcher(ldapConnection); search.Filter = String.Format("(sAMAccountName={0})", sAMAccountName); foreach (String property in requiredProperties) search.PropertiesToLoad.Add(property); SearchResult result = search.FindOne(); //SearchResultCollection searchResultCollection = search.FindAll(); if (result != null) { //foreach (String property in requiredProperties) // foreach (Object myCollection in result.Properties[property]) // Console.WriteLine(String.Format("{0,-20} : {1}", // property, myCollection.ToString())); // return searchResultCollection; return result; } else { return null; //Console.WriteLine("User not found!"); } //return ldapConnection; } catch (Exception e) { Console.WriteLine("Exception caught:\n\n" + e.ToString()); } return null; }***注意:***為了在
LDAP身份驗證FormsAuthentication.SignOut()請在LogOff()方法中添加如下所示的行:[HttpPost] [ValidateAntiForgeryToken] public ActionResult LogOff() { AuthenticationManager.SignOut(); FormsAuthentication.SignOut(); //In order to force logout in LDAP authentication return RedirectToAction("Login", "Account"); }***第 2 步:***更新您的
LoginViewModel(或任何您的 Account 模型類的名稱)以僅包含此類LoginModel:public class LoginViewModel { [Required] public string UserName { get; set; } [Required] [EmailAddress] public string Email { get; set; } [Required] [DataType(DataType.Password)] public string Password { get; set; } public bool RememberMe { get; set; } }另一方面,將自定義屬性(即姓名、姓氏、使用者名、部門等)添加到必要的模型中
ApplicationUser,即RegisterViewModel.***第 3 步:***最後,更新您的
Web.config文件以包含以下元素:<connectionStrings> <!-- for LDAP --> <add name="ADConnectionString" connectionString="LDAP://**.**.***:000/DC=abc,DC=xyz" /> </connectionStrings> <system.web> <!-- For LDAP --> <httpCookies httpOnlyCookies="true" /> <authentication mode="Forms"> <forms name=".ADAuthCookie" loginUrl="~/Account/Login" timeout="30" slidingExpiration="true" protection="All" /> </authentication> <membership defaultProvider="ADMembershipProvider"> <providers> <clear /> <add name="ADMembershipProvider" type="System.Web.Security.ActiveDirectoryMembershipProvider" connectionStringName="ADConnectionString" attributeMapUsername="sAMAccountName" connectionUsername="******" connectionPassword="******" /> </providers> </membership> ... </system.web>***更新:***這是
ApplicationUser範例中使用的類:// Must be expressed in terms of our custom Role and other types: public class ApplicationUser : IdentityUser<int, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>, IUser<int> { public string Name { get; set; } public string Surname { get; set; } public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser, int> manager) { var userIdentity = await manager .CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie); return userIdentity; } }希望這可以幫助…