当前位置: 代码迷 >> Web前端 >> Java Web应用集成域用户登陆有关问题
  详细解决方案

Java Web应用集成域用户登陆有关问题

热度:275   发布时间:2012-10-24 14:15:58.0
Java Web应用集成域用户登陆问题
最近在项目中遇到Java Web应用需要集成域用户登陆问题,
初看很简单,分析一下要解决的问题还是很多的,特拿出来讨论,听听大家的思路
不知道是否有成熟的方案可以直接借鉴,最好是开源社区的东西。

补充业务需求:
已经通过域帐号登陆的用户在登陆Web应用时不需要验证直接进入系统,否则提示输入用户名和密码

我现在从以下几个问题考虑
问题1:
客户端如何获取域用户信息?
AtiveX, applet, js, flash都可以拿到当前登陆的用户,好像密码拿不到

问题2:
服务器用户如何验证?
LDAP验证是一种方式,或者Jaas的NTLoginModule,还未测试过

问题3:
用户信息如何同步
只需要单向同步,从域服务器同步过来,如果发现有新的登陆名则在系统中建立新用户

问题4:
如果应用服务器在外网而域控制器有什么解决方案?
(这种方案中客户端和域控制服务器必然在一个子网中)



1 楼 bobo 2009-07-23  
问题1找到NTLM做身份验证,但只IE支持,还未做测试
问题2找到开源产品JCIFS做单点登陆,计划移植到cas中去
2 楼 bobo 2009-07-24  
找到一个IE only的方案,用Javascript在本地判断是否为登陆域的用户以及是否特定域服务器,是则直接用该用户进入系统
3 楼 bobo 2009-07-25  
通过IE可以实现功能,但是遇到activex的权限问题,还得另外找路

4 楼 xieke 2009-07-27  
		try {
			UniAddress dc = UniAddress.getByName(DomainIP2);
			jcifs.smb.NtlmPasswordAuthentication auth = new jcifs.smb.NtlmPasswordAuthentication(
					DomainIP2, userId, password);
			// jcifs.smb.SmbSession.getChallengeForDomain().
			jcifs.smb.SmbSession.logon(dc, auth);

		} catch (jcifs.smb.SmbAuthException e) {
			url = "domainlogin.jsp";
			msg = e.toString();
			// request.setAttribute("errMsg", "密码或用户名错误");
			// request.getRequestDispatcher(url).forward(request, response);
			// json="{result:0}";
			return 0;

		} catch (jcifs.smb.SmbException e) {
			// ip2 无法访问, 转 ip1
 ...
 }


5 楼 bobo 2009-07-27  
谢谢xieke的帮助,jcifs实现了服务器端通过Java来调用NTDomain验证

“已经通过域帐号登陆的用户在登陆Web应用时不需要验证直接进入系统,否则提示输入用户名和密码”,可以解决输入用户名和密码后通过NTDomain验证,但是如何让已经登陆的用户不用输入用户名和密码就完成验证呢?
6 楼 bobo 2009-07-27  
考虑比较理想的方案

本地ntml(如kerboros方式)认证通过将认证结果传给服务器,这样避免无法拿到密码以及应用服务器可能无法访问局域网内的域控制服务器等问题
7 楼 bobo 2009-07-27  
谢谢prosong提供帮助找到Java验证NTLM的代码
String auth = request.getHeader("Authorization");
if (auth == null)
{
  response.setStatus(response.SC_UNAUTHORIZED);
  response.setHeader("WWW-Authenticate", "NTLM");
  response.flushBuffer();
  return;
}
if (auth.startsWith("NTLM "))
{
  byte[] msg = new sun.misc.BASE64Decoder().decodeBuffer(auth.substring(5));
  int off = 0, length, offset;
  if (msg[8] == 1)
  {
    byte z = 0;
    byte[] msg1 = {(byte)'N', (byte)'T', (byte)'L', (byte)'M', (byte)'S', (byte)'S', (byte)'P', 
      z,(byte)2, z, z, z, z, z, z, z,(byte)40, z, z, z, 
      (byte)1, (byte)130, z, z,z, (byte)2, (byte)2,
      (byte)2, z, z, z, z, z, z, z, z, z, z, z, z};
    response.setHeader("WWW-Authenticate", "NTLM " + 
       new sun.misc.BASE64Encoder().encodeBuffer(msg1));
    response.sendError(response.SC_UNAUTHORIZED);
    return;
  }
  else if (msg[8] == 3)
  {
    off = 30;

    length = msg[off+17]*256 + msg[off+16];
    offset = msg[off+19]*256 + msg[off+18];
    String remoteHost = new String(msg, offset, length);

    length = msg[off+1]*256 + msg[off];
    offset = msg[off+3]*256 + msg[off+2];
    String domain = new String(msg, offset, length);

    length = msg[off+9]*256 + msg[off+8];
    offset = msg[off+11]*256 + msg[off+10];
    String username = new String(msg, offset, length);

    out.println("Username:"+username+"<BR>");
    out.println("RemoteHost:"+remoteHost+"<BR>");
    out.println("Domain:"+domain+"<BR>");
  }
}
8 楼 luocolor 2009-07-28  
不明白的是,lz的应用不是sso擅长的么?
9 楼 lcllcl987 2009-07-30  
传说有个东西叫sso
10 楼 shenjianwangyi 2009-07-30  
楼主要的功能就是sso 哇哈哈 建议去看看吧
11 楼 grandboy 2009-07-30  
如果要做sso,可不只是拿到用户名那么简单。拿到用户名和密码摘要有多种方法,但是想和操作系统集成,好像只有一种方法。
12 楼 KimShen 2009-07-31  
谢谢LZ和各位的贡献,此方法验证可行.
基础的NT登陆完全没有问题.
如果方便的话能不能共享下jcifs文档?官网的例子不知所云
13 楼 bobo 2009-07-31  
项目环境有点复杂,在外网的web应用要集成局域网内的window验证,和单纯的SSO还是有点差别。


14 楼 infante_yin 2009-09-22  
楼主,可以共享你的解决方法吗?目前我做的集成,采用CAS做单点登录,传过去的也就一个UserName,子系统还是要根据UserName重新加载用户信息.....
15 楼 san586 2009-11-14  
JAAS com.sun.security.auth.module.NTLoginModule 这个类可以解决你的问题
  相关解决方案