在现有的ASP.NET MVC 4.6 Web项目中实现Active Directory登录

Mic*_*hel 10 asp.net-mvc login active-directory

我必须使用Active Directory身份验证更改ASP.NET MVC + Knockout应用程序的现有(Windows)登录.它由mvc控制器和webapi控制器组成.两者都必须经过身份验证.

我想我会通过更改forms authentication并创建一个登录页面来做到这一点,当用户点击登录时,用System.DirectoryServices.DirectoryEntry.查询Active Directory .然后其他过程,如更改密码,注册等,也将获得一个自定义的HTML页面,并通过System.DirectoryServices.DirectoryEntry我们的Active Directory 执行他们的操作.

(也就是说,我找不到人们会这样做的任何其他方式,我确实找到了一些像这样做的人,听起来像forms authentication我以前见过的那样.在这种情况下,用户/密码会不是在数据库表中而是在Active Directory中.同样的想法,通过活动目录交换数据库表).

为了了解这将如何在一个全新的项目中,我创建了一个新的ASP.NET MVC项目,并选择"工作或学校帐户"(用于对使用活动目录对用户进行身份验证的应用程序)并选择"on premise".但是,我必须提供这些项目:

  • 内部部门
  • app Id url

我不知道该怎么做.我唯一拥有的是活动目录网址ldap://etc..

这是进行活动目录登录的另一种/更新/更好的方法吗?或唯一正确的(表单身份验证错误?)或错误的?

我糊涂了.

Mur*_*dız 6

为了实现Active Directory身份验证,我使用了以下方法,ASP.NET MVC 5并且这种方法很有吸引力:

步骤1:修改,AccountController如下所示的Login方法(还添加必要的引用):

[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;
}
Run Code Online (Sandbox Code Playgroud)

注意:为了强制注销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");
}
Run Code Online (Sandbox Code Playgroud)


第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; }
}
Run Code Online (Sandbox Code Playgroud)

另一方面,将自定义属性(即名称,姓氏,用户名,部门等)添加到必要的模型(即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>
Run Code Online (Sandbox Code Playgroud)


希望这可以帮助...