参考:http://jusescn.iteye.com/blog/757475,http://www.iteye.com/problems/61029
以及其他网上资料
1.概念
单点登录:http://baike.baidu.com/view/993620.htm,http://baike.baidu.com/view/190743.htm
JCIFS:官网 http://jcifs.samba.org/, 域验证,共享文件操作
2. IE 设置
无论在不在域中都会进行一次自动登录,不在域中则登录报错,catch住exception 后跳转到普通登录页面
3.web.xml
<filter> <filter-name>checkLogin</filter-name> <filter-class>com.XXX.xxx.filter.CheckLoginFilter</filter-class> <init-param> <param-name>excludeUrl</param-name> <param-value>login.jsp,login.do,loginService.do,change.do,upload.jsp</param-value> </init-param> <init-param> <param-name>loginPage</param-name> <param-value>login.jsp</param-value> </init-param> </filter>
3.Filter
public class CheckLoginFilter implements Filter {
private List<String> excludePages = new ArrayList<String>(0);
private String LOGIN_PAGE = "";
private final Logger logger = TraceLoggerFactory.getLogger(this.getClass());
private LoginService loginService = new LoginService();
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest)request;
HttpServletResponse httpServletResponse = (HttpServletResponse)response;
String servletPath = httpServletRequest.getServletPath();
NtlmPasswordAuthentication ntlm = null;
String[] paths = servletPath.split("/");
if(!excludePages.contains(paths[paths.length-1])){
Object userInfoObj = httpServletRequest.getSession().getAttribute("user");
String userName = request.getParameter("userName");
if(userInfoObj == null){
boolean loginFlag = false;
try {
//读取域配置 ,将配置放入配置文件中 读取
Config.setProperty( "jcifs.http.domainController","192.168.1.0"+","+ "192.168.1.1");
Config.setProperty( "jcifs.smb.client.domain", "testDomain" );
//进行域登录验证
loginFlag = (ntlm = loginService.negotiate( httpServletRequest, httpServletResponse, false )) !=null;
} catch (Exception e) {
//e.printStackTrace();
}
if (loginFlag) {
logger.info("域账户:" + ntlm.getUsername()+"已登录!");
DataObject[] userAccounts = userManager.queryByDomainAndName(ntlm.getUsername(),null);
if(userAccounts != null && userAccounts.length > 0){
//如果请求中包含用户名,则根据此用户名查找对应域账户是否已登录
if (!StringUtil.isBlank(userName)) {
for (DataObject object : userAccounts) {
if (userName.equals(object.getString("account"))) {
loginService.setUser2SessionByAccount(httpServletRequest, object);
}
}
}else{
if(userAccounts.length == 1){
loginService.setUser2SessionByAccount(httpServletRequest, userAccounts[0]);
}else if(userAccounts.length > 1){
//进入多账户选择页面
request.setAttribute("userInfos", userAccounts);
request.setAttribute("prePath", httpServletRequest.getContextPath()+ servletPath);
request.getRequestDispatcher("switch_user.jsp").forward(request,response);
return;
}
}
if(servletPath.endsWith("/login.jsp") ||servletPath.endsWith("index.jsp")){
httpServletResponse.sendRedirect("epf_index.jsp");
}else{
request.getRequestDispatcher(servletPath).forward(request,response);
}
return;
}
}
DataObject userInfo1 = (DataObject)httpServletRequest.getSession().getAttribute("user");
if(userInfo1 == null ){
httpServletResponse.sendRedirect(httpServletRequest.getContextPath()+"/"+LOGIN_PAGE);
return;
}
}
}
chain.doFilter( new NtlmHttpServletRequest( httpServletRequest, ntlm ), response );
}
public void init(FilterConfig config) throws ServletException {
LOGIN_PAGE = config.getInitParameter("loginPage");
String excludePage = config.getInitParameter("excludeUrl");
if(excludePage != null && !"".equals(excludePage)){
String[] excludePages = excludePage.split(",");
this.excludePages = Arrays.asList(excludePages);
}
//初始化 JCIFS的配置信息
loginService.initJcifsConfig();
}
/**从源码中弄过来的 不知道有啥用
*/
class NtlmHttpServletRequest extends HttpServletRequestWrapper {
Principal principal;
NtlmHttpServletRequest( HttpServletRequest req, Principal principal ) {
super( req );
this.principal = principal;
}
public String getRemoteUser() {
return principal.getName();
}
public Principal getUserPrincipal() {
return principal;
}
public String getAuthType() {
return "NTLM";
}
}
}
public class LoginService {
TraceLogger logger = new TraceLogger(LoginService.class);
UserManager userManager = new UserManager();
private static LogStream log = LogStream.getInstance();
private String defaultDomain;
private String domainController;
private boolean loadBalance;
private boolean enableBasic;
private boolean insecureBasic;
private String realm;
public boolean setUser2SessionByAccount(HttpServletRequest request,DataObject account){
String accountStatus = account.getString("accountStatus");
if(accountStatus.equals("Y")){
DataObject user = getUserInfoByUserId(account.getString("accountId"));
user.setString("loginIp", request.getRemoteAddr());
System.out.println("loginIp:"+request.getRemoteAddr());
request.getSession().setAttribute("user", user);
request.getSession().setAttribute(SynchroToken.TOKEN_NAME, SynchroToken.generateToken());
return true;
}
return false;
}
public boolean setUser2SessionByUserName(HttpServletRequest request, String userName){
DataObject account = userManager.queryByAccount(userName);
return setUser2SessionByAccount(request, account);
}
public void initJcifsConfig(){
int level;
// Config.setProperty( "jcifs.http.domainController", "192.168.0.14" );
// Config.setProperty( "jcifs.smb.client.domain", "epfnet" );
// Config.setProperty( "jcifs.smb.client.username", "administrator" );
// Config.setProperty( "jcifs.smb.client.password", "123456" );
Config.setProperty( "jcifs.smb.client.soTimeout", "6000" );
Config.setProperty( "jcifs.netbios.cachePolicy", "1200" );
Config.setProperty( "jcifs.smb.lmCompatibility", "0" );
Config.setProperty( "jcifs.smb.client.useExtendedSecurity", "false" );
Config.setProperty( "jcifs.util.loglevel", "1" );
enableBasic = Boolean.valueOf(
Config.getProperty("jcifs.http.enableBasic")).booleanValue();
insecureBasic = Boolean.valueOf(
Config.getProperty("jcifs.http.insecureBasic")).booleanValue();
realm = Config.getProperty("jcifs.http.basicRealm");
defaultDomain = Config.getProperty("jcifs.smb.client.domain");
domainController = Config.getProperty( "jcifs.http.domainController" );
if( domainController == null ) {
domainController = defaultDomain;
loadBalance = Config.getBoolean( "jcifs.http.loadBalance", true );
}
if (realm == null) realm = "jCIFS";
if(( level = Config.getInt( "jcifs.util.loglevel", -1 )) != -1 ) {
LogStream.setLevel( level );
}
if( LogStream.level > 2 ) {
try {
Config.store( log, "JCIFS PROPERTIES" );
} catch( IOException ioe ) {
}
}
}
/**
* Negotiate password hashes with MSIE clients using NTLM SSP
* @param req The servlet request
* @param resp The servlet response
* @param skipAuthentication If true the negotiation is only done if it is
* initiated by the client (MSIE post requests after successful NTLM SSP
* authentication). If false and the user has not been authenticated yet
* the client will be forced to send an authentication (server sends
* HttpServletResponse.SC_UNAUTHORIZED).
* @return True if the negotiation is complete, otherwise false
*/
public 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());
if( msg != null && (msg.startsWith( "NTLM " ) ||
(offerBasic && msg.startsWith("Basic ")))) {
if (msg.startsWith("NTLM ")) {
HttpSession ssn = req.getSession();
byte[] challenge;
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 {
SmbSession.logon( dc, ntlm );
//在catch 中做下修改 就不会弹出验证框了,直接当做验证失败跳到登录页面,我忘了有没有改了,反正是头信息,与源码对下吧
if( LogStream.level > 2 ) {
log.println( "NtlmHttpFilter: " + ntlm +
" successfully authenticated against " + dc );
}
} catch( SmbAuthException sae ) {
if( LogStream.level > 1 ) {
log.println( "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 + "\"");
}
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 ssn = req.getSession(false);
if (ssn == null || (ntlm = (NtlmPasswordAuthentication)
ssn.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;
}
}