局方所有人的电脑都在一个域中管理,员工通过域账号和密码登录他的计算机之后,在登录应用系统之后不再需要做登入操作,直接进入系统;
实现方法
通过查询资料,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"");却没有移除这个参数的方法。。
求大神们指点一二