吉日嘎了的Webform例子程序做的很好,但在我们公司,除了使用GPM通用权限管理自带的账户系统登录,还需要集成Windows域账户登录。对于如何实现,我思考了一段时间,大体的思路如下:
1、在GPM中创建的用户账号和其在Windows域中的账号一致,如域账号为Troy.Cui,那么GPM中登录userName也是Troy.Cui
2、GPM中的账号需要单独手工创建,因为涉及到的权限、角色的设定,如果使用域账号登录的时候,自动创建GPM的账号意义不大
3、不启用IIS中的Windows集成认证,因为我们还有一部分用户是没有域账号的,所以必须使用模拟域用户登录的方式进行认证
4、模拟域账号登录成功后,需要在GPM中增加一个DomainLogon的方法,直接使用域账号进行登录,无需密码。
昨天在实现的过程中,在DoNet.Business中增加了DomainLogon(string userName)的方法调用BaseUserManager.LogOnByUserName,但是在做模拟域用户登录的时候,一直报各种各样的错误:
1、There is no such object on the server.
2、0x80005000
3、A referral was returned from the server
最后通过参考《[URL=http://www.codeproject.com/Articles/18102/Howto-Almost-Everything-In-Active-Directory-via-C]Howto: (Almost) Everything In Active Directory via C#[/URL]》和《[URL=http://www.cnblogs.com/netlover/archive/2011/03/30/1999836.html]Asp.Net模拟域验证登录及密码修改[/URL]》,最后终于调试通过,代码如下:
创建DomainSigin.aspx,在DomainSigin.aspx.cs中增加引用:using System.DirectoryServices;
<br/>/// <summary><br/> /// 域用户登录<br/> /// </summary><br/> /// <param name="userName">用户名</param><br/> /// <param name="password">密码</param><br/> private void DomainUserLogOn(string userName, string password)<br/> {<br/> //China Only<br/> //string lDAP = "OU=Users,OU=China,DC=CORP,DC=yourdomain,DC=com";<br/> string lDAP = "DC=CORP,DC=yourdomain,DC=com";<br/> <br/> DirectoryEntry dirEntry = new DirectoryEntry();<br/> dirEntry.Path = string.Format("LDAP://{0}", lDAP);<br/> dirEntry.Username = "corpwaiglobal\\" + userName;<br/> dirEntry.Password = password;<br/> dirEntry.AuthenticationType = AuthenticationTypes.Secure;<br/> <br/> string checkInput = string.Empty;<br/><br/> try<br/> {<br/> DirectorySearcher searcher = new DirectorySearcher(dirEntry);<br/> searcher.Filter = String.Format("(&(objectClass=user)(samAccountName={0}))", userName);<br/> System.DirectoryServices.SearchResult result = searcher.FindOne();<br/> if (result != null)<br/> {<br/> // 正常登录<br/> <br/> try<br/> {<br/> string statusCode = string.Empty;<br/> string statusMessage = "没有此用户。";<br/><br/> // 有什么权限的人才可以登录到系统<br/> string permissionItemCode = string.Empty;<br/><br/> // 登录验证<br/> string openId = Utilities.GetOpenId();<br/> BaseUserInfo userInfo = Utilities.DomainLogOn(userName);<br/><br/> // txtVerifyCode.Text = string.Empty;<br/> // 登录结果<br/> if (userInfo!=null)<br/> {<br/> this.AfterLogOn(userInfo);<br/> // 登录成功,重新定向到跳转的页面<br/> // Page.Response.Redirect(this.ReturnURL);<br/> // 若是单点登录,还需要把OpenId传递过去,这样在其他子网站里可以获取到OpenId,而不是用户名密码了,可以进行加密登录了<br/> if (!string.IsNullOrEmpty(this.ReturnURL) && !string.IsNullOrEmpty(userInfo.OpenId))<br/> {<br/> if (this.ReturnURL.IndexOf('?') > 0)<br/>&nb
sp; {<br/> this.ReturnURL = this.ReturnURL + "&OpenId=" + userInfo.OpenId;<br/> }<br/> else<br/> {<br/> this.ReturnURL = this.ReturnURL + "?OpenId=" + userInfo.OpenId;<br/> }<br/> }<br/> Response.Redirect(this.ReturnURL, false);<br/> }<br/> else<br/> {<br/> checkInput = "<script>alert('提示信息:" + statusMessage + "');</script>";<br/> Page.ClientScript.RegisterStartupScript(this.GetType(), "message", checkInput);<br/> this.txtUserName.Focus();<br/> }<br/> }<br/> catch (System.Exception exception)<br/> {<br/> Page.Response.Write(exception.Message);<br/> checkInput = "<script>alert('提示信息:登录失败,请检查你的用户名和密码是否输入有误。');</script>";<br/> Page.ClientScript.RegisterStartupScript(this.GetType(), "message", checkInput);<br/> this.txtUserName.Focus();<br/> }<br/> }<br/> dirEntry.Close();<br/> }<br/> catch (Exception ex)<br/> {<br/> Page.Response.Write(ex.Message);<br/> checkInput = "<script>alert('提示信息:登录失败,请检查你的用户名和密码是否输入有误。');</script>";<br/> Page.ClientScript.RegisterStartupScript(this.GetType(), "message", checkInput);<br/> this.txtUserName.Focus();<br/> }<br/> }<br/>
坦白的说,这么实现的话,对DotNet.Business部分暴漏出来一个无需密码的LogOnByUserName登录,的确是一个风险,最好的做法是把域验证的部分也放到DotNet.Business,但是这么做,又有缺点,会对不需要域认证的用户早成负担。