JCIFS实现域单点登入遇到的问题

需求说明
局方所有人的电脑都在一个域中管理,员工通过域账号和密码登录他的计算机之后,在登录应用系统之后不再需要做登入操作,直接进入系统;

实现方法
通过查询资料,JCIFS可以实现域单点登入,实现原理可以查看这个链接:

http://www.cnblogs.com/adylee/articles/975213.html

实现方法也比较简单,步骤如下:
1.jcifs官网http://jcifs.samba.org/下载最新jar包
2.配置过滤器

      <filter>
		<filter-name>NtlmHttpFilter</filter-name>
		<filter-class>jcifs.http.NtlmHttpFilter</filter-class>
		<init-param>
			<param-name>jcifs.http.domainController</param-name>
			<param-value>10.45.40.222</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>NtlmHttpFilter</filter-name>
		<url-pattern>*.do</url-pattern>
	</filter-mapping>



由于我只要通过JCIFS获取客户端的系统用户,并没有通过JCIFS登入AD验证用户(用户登入的时候已经验证了),所有这里配的参数就一个。
3.修改过滤器NtlmHttpFilter的代码,去掉AD登入
protected NtlmPasswordAuthentication negotiate(HttpServletRequest req, HttpServletResponse resp,
			boolean skipAuthentication) throws IOException, ServletException {
		UniAddress dc;
		String msg;
		NtlmPasswordAuthentication ntlm = null;
		msg = req.getHeader("Authorization");

		boolean offerBasic = enableBasic && (insecureBasic || req.isSecure());
		logger.info("NtlmHttpFilter negotiate msg:" + msg);
		logger.info("NtlmHttpFilter negotiate offerBasic:" + offerBasic);

		if (msg != null && (msg.startsWith("NTLM ") || (offerBasic && msg.startsWith("Basic ")))) {
			if (msg.startsWith("NTLM ")) {
				HttpSession ssn = req.getSession();
				byte[] challenge;

				logger.info("NtlmHttpFilter negotiate loadBalance:" + loadBalance);

				if (loadBalance) {
					NtlmChallenge chal = (NtlmChallenge) ssn.getAttribute("NtlmHttpChal");
					if (chal == null) {
						chal = SmbSession.getChallengeForDomain();
						ssn.setAttribute("NtlmHttpChal", chal);
					}
					dc = chal.dc;
					challenge = chal.challenge;
				} else {
					dc = UniAddress.getByName(domainController, true);
					challenge = SmbSession.getChallenge(dc);
				}

				if ((ntlm = NtlmSsp.authenticate(req, resp, challenge)) == null) {
					return null;
				}
				/* negotiation complete, remove the challenge object */
				ssn.removeAttribute("NtlmHttpChal");
			} else {
				String auth = new String(Base64.decode(msg.substring(6)), "US-ASCII");
				int index = auth.indexOf(':');
				String user = (index != -1) ? auth.substring(0, index) : auth;
				String password = (index != -1) ? auth.substring(index + 1) : "";
				index = user.indexOf('\\');
				if (index == -1)
					index = user.indexOf('/');
				String domain = (index != -1) ? user.substring(0, index) : defaultDomain;
				user = (index != -1) ? user.substring(index + 1) : user;
				ntlm = new NtlmPasswordAuthentication(domain, user, password);
				dc = UniAddress.getByName(domainController, true);
			}

			/*
			 * try { logger.info(
			 * "NtlmHttpFilter SmbSession logon....ntlm.getName():"
			 * +ntlm==null?null:ntlm.getName()); SmbSession.logon( dc, ntlm );
			 * 
			 * if( log.level > 2 ) { logger.info( "NtlmHttpFilter: " + ntlm +
			 * " successfully authenticated against " + dc ); } logger.info(
			 * "NtlmHttpFilter SmbSession logon successfully...."); }
			 * catch(SmbException sae ) { logger.info(
			 * "NtlmHttpFilter SmbSession logon error....msg:"+ntlm.getName()+
			 * " auth error:"+sae.getMessage());
			 * 
			 * if( log.level > 1 ) { logger.info( "NtlmHttpFilter: " +
			 * ntlm.getName() + ": 0x" + jcifs.util.Hexdump.toHexString(
			 * sae.getNtStatus(), 8 ) + ": " + sae ); } if( sae.getNtStatus() ==
			 * SmbAuthException.NT_STATUS_ACCESS_VIOLATION ) { Server challenge
			 * no longer valid for externally supplied password hashes.
			 * 
			 * HttpSession ssn = req.getSession(false); if (ssn != null) {
			 * ssn.removeAttribute( "NtlmHttpAuth" ); } } resp.setHeader(
			 * "WWW-Authenticate", "NTLM" ); if (offerBasic) { resp.addHeader(
			 * "WWW-Authenticate", "Basic realm=\"" + realm + "\""); }
			 * if(showDlg){ resp.setStatus( HttpServletResponse.SC_UNAUTHORIZED
			 * ); resp.setContentLength(0); Marcel Feb-15-2005
			 * resp.flushBuffer(); }
			 * 
			 * 
			 * return null; } req.getSession().setAttribute( "NtlmHttpAuth",
			 * ntlm );
			 */
		} else {
			if (!skipAuthentication) {
				HttpSession ssn1 = req.getSession(false);
				if (ssn1 == null || (ntlm = (NtlmPasswordAuthentication) ssn1.getAttribute("NtlmHttpAuth")) == null) {
					resp.setHeader("WWW-Authenticate", "NTLM");
					if (offerBasic) {
						resp.addHeader("WWW-Authenticate", "Basic realm=\"" + realm + "\"");
					}
					resp.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
					resp.setContentLength(0);
					resp.flushBuffer();

					return null;
				}
			}
		}
		return ntlm;
	}

完成以上几步,就可以通过request.getUserPrincipal();获取客户端系统用户名了。

在项目中,把过滤器整合进去,虽然实现了需求,但是遇到个问题。
加了这个过滤器后,之后的所有请求都会发多次,查看附件图片

这个也能理解,因为JCIFS实现的原理就是在请求的头文件加Authorization。这样每次请求都需要验证一次。那么问题就来了,由于框架是通过request.getInputStream获取请求参数再做分析,而http发送的验证请求body是为空,导致后面的程序报错。就不得不再后面的解析中判断一下输入流是否为空,再做处理。

我就想能不能怎么控制HTTP只在发登入请求的时候才发验证请求,其他的请求就不要用了。

想办法删掉headers中的Authorization参数,查找资料只有
response.setHeader("WWW-Authenticate","NTLM&quot");却没有移除这个参数的方法。。
求大神们指点一二

猜你喜欢

转载自eclipower.iteye.com/blog/2359952