ad 单点登录 java 访问权限_AD 单点登录以及windows认证详细说明

上篇博客我谈到了一些关于ASP.NET Forms身份认证方面的话题,这次的博客将主要介绍ASP.NET Windows身份认证。

Forms身份认证虽然使用广泛,不过,如果是在 Windows Active Directory 的环境中使用ASP.NET, 那么使用Windows身份认证也会比较方便。 方便性表现为:我们不用再设计登录页面,不用编写登录验证逻辑。而且使用Windows身份认证会有更好的安全保障。

认识ASP.NET Windows身份认证

要使用Windows身份认证模式,需要在web.config设置:

Windows身份认证做为ASP.NET的默认认证方式,与Forms身份认证在许多基础方面是一样的。上篇博客我说过:我认为ASP.NET的身份认证的最核心部分其实就是HttpContext.User这个属性所指向的对象。在接下来的部分,我将着重分析这个对象在二种身份认证中有什么差别。

在ASP.NET身份认证过程中,IPrincipal和IIdentity这二个接口有着非常重要的作用。 前者定义用户对象的基本功能,后者定义标识对象的基本功能, 不同的身份认证方式得到的这二个接口的实例也是不同的。

ASP.NET Windows身份认证是由WindowsAuthenticationModule实现的。WindowsAuthenticationModule在ASP.NET管线的AuthenticateRequest事件中, 使用从IIS传递到ASP.NET的Windows访问令牌(Token)创建一个WindowsIdentity对象,Token通过调用context.WorkerRequest.GetUserToken()获得, 然后再根据WindowsIdentity 对象创建WindowsPrincipal对象, 然后把它赋值给HttpContext.User。

在Forms身份认证中,我们需要创建登录页面,让用户提交用户名和密码,然后检查用户名和密码的正确性, 接下来创建一个包含FormsAuthenticationTicket对象的登录Cookie供后续请求使用。FormsAuthenticationModule在ASP.NET管线的AuthenticateRequest事件中, 解析登录Cookie并创建一个包含FormsIdentity的GenericPrincipal对象, 然后把它赋值给HttpContext.User。

上面二段话简单了概括了二种身份认证方式的工作方式。

我们可以发现它们存在以下差别:

1. Forms身份认证需要Cookie表示登录状态,Windows身份认证则依赖于IIS

2. Windows身份认证不需要我们设计登录页面,不用编写登录验证逻辑,因此更容易使用。

在授权阶段,UrlAuthorizationModule仍然会根据当前用户检查将要访问的资源是否得到许可。 接下来,FileAuthorizationModule检查 HttpContext.User.Identity 属性中的 IIdentity 对象是否是 WindowsIdentity 类的一个实例。 如果 IIdentity 对象不是 WindowsIdentity 类的一个实例,则 FileAuthorizationModule 类停止处理。 如果存在 WindowsIdentity 类的一个实例,则 FileAuthorizationModule 类调用 AccessCheck Win32 函数(通过 P/Invoke) 来确定是否授权经过身份验证的客户端访问请求的文件。 如果该文件的安全描述符的随机访问控制列表 (DACL) 中至少包含一个 Read 访问控制项 (ACE),则允许该请求继续。 否则,FileAuthorizationModule 类调用 HttpApplication.CompleteRequest 方法并将状态码 401 返回到客户端。

在Windows身份认证中,验证工作主要是由IIS实现的,WindowsAuthenticationModule其实只是负责创建WindowsPrincipal和WindowsIdentity而已。 顺便介绍一下:Windows 身份验证又分为“NTLM 身份验证”和“Kerberos v5 身份验证”二种, 关于这二种Windows身份认证的更多说明可查看MSDN技术文章:解释:ASP.NET 2.0 中的 Windows 身份验证。 在我看来,IIS最终使用哪种Windows身份认证方式并不影响我们的开发过程,因此本文不会讨论这个话题。

根据我的实际经验来看,使用Windows身份认证时,主要的开发工作将是根据登录名从Active Directory获取用户信息。 因为,此时不需要我们再设计登录过程,IIS与ASP.NET已经为我们准备好了WindowsPrincipal和WindowsIdentity这二个与用户身份相关的对象。

访问 Active Directory

我们通常使用LDAP协议来访问Active Directory, 在.net framework中提供了DirectoryEntry和DirectorySearcher这二个类型让我们可以方便地从托管代码中访问 Active Directory 域服务。

如果我们要在"test.corp”这个域中搜索某个用户信息,我们可以使用下面的语句构造一个DirectoryEntry对象:DirectoryEntryentry =newDirectoryEntry("LDAP://test.corp");

在这段代码中,我采用硬编码的方式把域名写进了代码。

我们如何知道当前电脑所使用的是哪个域名呢?

答案是:查看“我的电脑”的属性对话框:

42865919_1.png

注意:这个域名不一定与System.Environment.UserDomainName相同。

除了可以查看“我的电脑”的属性对话框外,我们还可以使用代码的方式获取当前电脑所使用的域名:private static stringGetDomainName()

{

// 注意:这段代码需要在Windows XP及较新版本的操作系统中才能正常运行。SelectQueryquery =newSelectQuery("Win32_ComputerSystem");

using( ManagementObjectSearchersearcher =newManagementObjectSearcher(query) ) {

foreach( ManagementObjectmo insearcher.Get() ) {

if( (bool)mo["partofdomain"] )

returnmo["domain"].ToString();

}

}

return null;

}

当构造了DirectorySearcher对象后,我们便可以使用DirectorySearcher来执行对Active Directory的搜索。

我们可以使用下面的步骤来执行搜索:

1. 设置 DirectorySearcher.Filter 指示LDAP格式筛选器,这是一个字符串。

2. 多次调用PropertiesToLoad.Add() 设置搜索过程中要检索的属性列表。

3. 调用FindOne() 方法获取搜索结果。

下面的代码演示了如何从Active Directory中搜索登录名为“fl45”的用户信息:static voidMain(string[] args)

{

Console.WriteLine(Environment.UserDomainName);

Console.WriteLine(Environment.UserName);

Console.WriteLine("------------------------------------------------");

ShowUserInfo("fl45", GetDomainName());

}

private static stringAllProperties ="name,givenName,samaccountname,mail";

public static voidShowUserInfo(stringloginName, stringdomainName)

{

if( string.IsNullOrEmpty(loginName) ||string.IsNullOrEmpty(domainName) )

return;

string[] properties =AllProperties.Split(new char[] { '\r', '\n', ','},

StringSplitOptions.RemoveEmptyEntries);

try{

DirectoryEntryentry =newDirectoryEntry("LDAP://"+domainName);

DirectorySearchersearch =newDirectorySearcher(entry);

search.Filter ="(samaccountname="+loginName +")";

foreach( stringp inproperties )

search.PropertiesToLoad.Add(p);

SearchResultresult =search.FindOne();

if( result !=null) {

foreach( stringp inproperties ) {

ResultPropertyValueCollectioncollection =result.Properties[p];

for( inti =0; i

Console.WriteLine(p +": "+collection[i]);

}

}

}

catch( Exceptionex ) {

Console.WriteLine(ex.ToString());

}

}

结果如下:

42865919_2.png

在前面的代码,我在搜索Active Directory时,只搜索了"name,givenName,samaccountname,mail"这4个属性。 然而,LDAP还支持更多的属性,我们可以使用下面的代码查看更多的用户信息:private static stringAllProperties =@"

homemdb

distinguishedname

countrycode

cn

lastlogoff

mailnickname

dscorepropagationdata

msexchhomeservername

msexchmailboxsecuritydescriptor

msexchalobjectversion

usncreated

objectguid

whenchanged

memberof

msexchuseraccountcontrol

accountexpires

displayname

primarygroupid

badpwdcount

objectclass

instancetype

objectcategory

samaccounttype

whencreated

lastlogon

useraccountcontrol

physicaldeliveryofficename

samaccountname

usercertificate

givenname

mail

userparameters

adspath

homemta

msexchmailboxguid

pwdlastset

logoncount

codepage

name

usnchanged

legacyexchangedn

proxyaddresses

department

userprincipalname

badpasswordtime

objectsid

sn

mdbusedefaults

telephonenumber

showinaddressbook

msexchpoliciesincluded

textencodedoraddress

lastlogontimestamp

company

";

在ASP.NET中访问Active Directory

前面我在一个控制台程序中演示了访问Active Directory的方法,通过示例我们可以看到:在代码中,我用Environment.UserName就可以得到当前用户的登录名。 然而,如果是在ASP.NET程序中,访问Environment.UserName就很有可能得不到真正用户登录名。 因为:Environment.UserName是使用WIN32API中的GetUserName获取线程相关的用户名,但ASP.NET运行在IIS中,线程相关的用户名就不一定是客户端的用户名了。 不过,ASP.NET可以模拟用户方式运行,通过这种方式才可以得到正确的结果。关于“模拟”的话题在本文的后面部分有说明。

在ASP.NET中,为了能可靠的获取登录用户的登录名,我们可以使用下面的代码:///

///根据指定的HttpContext对象,获取登录名。///

///

/// public static stringGetUserLoginName(HttpContextcontext)

{

if( context ==null)

return null;

if( context.Request.IsAuthenticated ==false)

return null;

stringuserName =context.User.Identity.Name;

// 此时userName的格式为:UserDomainName\LoginName

// 我们只需要后面的LoginName就可以了。string[] array =userName.Split(new char[] { '\\'}, StringSplitOptions.RemoveEmptyEntries);

if( array.Length ==2)

returnarray[1];

return null;

}

在ASP.NET中使用Windows身份认证时,IIS和WindowsAuthenticationModule已经做了许多验证用户的相关工作, 虽然我们可以使用前面的代码获取到用户的登录名,但用户的其它信息即需要我们自己来获取。 在实际使用Windows身份认证时,我们要做的事:基本上就是从Active Directory中根据用户的登录名获取所需的各种信息。

比如:我的程序在运行时,还需要使用以下与用户相关的信息:public sealed classUserInfo{

public stringGivenName;

public stringFullName;

public stringEmail;

}

那么,我们可以使用这样的代码来获取所需的用户信息:public static classUserHelper{

///

///活动目录中的搜索路径,也可根据实际情况来修改这个值。/// public static stringDirectoryPath ="LDAP://"+GetDomainName();

///

///获取与指定HttpContext相关的用户信息///

///

/// public staticUserInfoGetCurrentUserInfo(HttpContextcontext)

{

stringloginName =GetUserLoginName(context);

if( string.IsNullOrEmpty(loginName) )

return null;

returnGetUserInfoByLoginName(loginName);

}

///

///根据指定的HttpContext对象,获取登录名。///

///

/// public static stringGetUserLoginName(HttpContextcontext)

{

if( context ==null)

return null;

if( context.Request.IsAuthenticated ==false)

return null;

stringuserName =context.User.Identity.Name;

// 此时userName的格式为:UserDomainName\LoginName

// 我们只需要后面的LoginName就可以了。string[] array =userName.Split(new char[] { '\\'}, StringSplitOptions.RemoveEmptyEntries);

if( array.Length ==2)

returnarray[1];

return null;

}

///

///根据登录名查询活动目录,获取用户信息。///

///

/// public staticUserInfoGetUserInfoByLoginName(stringloginName)

{

if( string.IsNullOrEmpty(loginName) )

return null;

// 下面的代码将根据登录名查询用户在AD中的信息。

// 为了提高性能,可以在此处增加一个缓存容器(Dictionary or Hashtable)。try{

DirectoryEntryentry =newDirectoryEntry(DirectoryPath);

DirectorySearchersearch =newDirectorySearcher(entry);

search.Filter ="(SAMAccountName="+loginName +")";

search.PropertiesToLoad.Add("givenName");

search.PropertiesToLoad.Add("cn");

search.PropertiesToLoad.Add("mail");

// 如果还需要从AD中获取其它的用户信息,请参考ActiveDirectoryDEMOSearchResultresult =search.FindOne();

if( result !=null) {

UserInfoinfo =newUserInfo();

info.GivenName =result.Properties["givenName"][0].ToString();

info.FullName =result.Properties["cn"][0].ToString();

info.Email =result.Properties["mail"][0].ToString();

returninfo;

}

}

catch{

// 如果需要记录异常,请在此处添加代码。}

return null;

}

private static stringGetDomainName()

{

// 注意:这段代码需要在Windows XP及较新版本的操作系统中才能正常运行。SelectQueryquery =newSelectQuery("Win32_ComputerSystem");

using( ManagementObjectSearchersearcher =newManagementObjectSearcher(query) ) {

foreach( ManagementObjectmo insearcher.Get() ) {

if( (bool)mo["partofdomain"] )

returnmo["domain"].ToString();

}

}

return null;

}

}

使用UserHelper的页面代码:

WindowsAuthentication DEMO - http://www.cnblogs.com/fish-li/
用户短名:
用户全名:
邮箱地址:

当前用户还未登录。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值