package com.xjj.sso.client.filter;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import com.xjj.sso.client.pojo.RequestParameter;
import com.xjj.sso.client.rabbitmq.QueueConsumer;
import com.xjj.sso.client.session.SessionHandle;
import com.xjj.sso.client.user.SSOReceipt;
import com.xjj.sso.client.util.EncryptUtils;
import com.xjj.sso.client.SSOConstants;
import com.xjj.sso.client.util.SSOUtils;
public class SSOClientFilter implements Filter {
public static ConcurrentHashMap TICKET_SESSION_CACHE = new ConcurrentHashMap();
public static ConcurrentHashMap SESSION_TICKET_CACHE = new ConcurrentHashMap();
@Override
public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
String uri = request.getRequestURI();
String contextPath = request.getContextPath();
if(SSOUtils.isNotFilter(uri,contextPath))
{
chain.doFilter(request, response);
return;
}
String requestLogoutTicket = request.getParameter("requestLogout");
//如果是被动单点退出
if(SSOUtils.isNotBlank(requestLogoutTicket))
{
ssoLogout(requestLogoutTicket);
return;
}
//如果是客户端的单点登陆
if(uri.endsWith(SSOConstants.SSO_CLIENT_SSOLOGONURL))
{
ssoLogon(request,response);
return;
}
//如果已经登陆成功
Object receiptObj = request.getSession().getAttribute(SSOConstants.SSO_CLIENT_RECEIPT);
if(null != receiptObj)
{
chain.doFilter(request, response);
}else
{
//单点登陆验证
authentication(request, response, chain);
}
}
/**
* 单点登陆验证
* @param request
* @param response
* @throws IOException
* @throws ServletException
*/
private void authentication(HttpServletRequest request,HttpServletResponse response,FilterChain chain) throws IOException, ServletException
{
String ticket = request.getParameter("ticket");
//还没有ticket,说明还没有验证通过,去sso服务端去验证,并且记录当前请求的参数。
if(SSOUtils.isBlank(ticket))
{
Map pramMap = request.getParameterMap();
Map pramMapNew = new HashMap();
pramMapNew.putAll(pramMap);
String paramCode = null;
if(!pramMap.isEmpty())
{
String method = request.getMethod();
paramCode = RequestParameter.generateCode();
RequestParameter param = new RequestParameter();
param.setCode(paramCode);
param.setMethod(method);
param.setRequestPram(pramMapNew);
param.setAction(getService(request,null,false));
request.getSession().setAttribute("requestPram"+paramCode, param);
}
StringBuilder authUrl = new StringBuilder();
authUrl.append(SSOConstants.SSO_SERVER_AUTHENTICATION);
authUrl.append("?service=");
authUrl.append(getService(request,paramCode,true));
authUrl.append("&projectCode=");
authUrl.append(SSOConstants.SSO_CLIENT_PROJECTCODE);
System.out.println("=====================sso client authentication sendRedirect begin============================");
System.out.println("authUrl="+authUrl.toString());
System.out.println("=====================sso client authentication sendRedirect end==============================");
response.sendRedirect(authUrl.toString());
return;
}
else
{
//有ticket说明已经从服务端验证通过了,取得登陆信息,并且还原原来的请求场景
String ssoParamCode = request.getParameter("ssoParamCode");
String service = getService(request,ssoParamCode,false);
SSOReceipt receipt = SSOUtils.validateTicket(ticket, service);
System.out.println("---------------------sso client authentication validateTicket begin---------------------");
System.out.println("ticket="+ticket);
System.out.println("service="+service);
System.out.println("receipt="+receipt);
System.out.println("---------------------sso client authentication validateTicket end---------------------");
if(null == receipt)
{
StringBuilder authUrl = new StringBuilder();
authUrl.append(SSOConstants.SSO_SERVER_AUTHENTICATION);
authUrl.append("?service=");
authUrl.append(getService(request,null,true));
authUrl.append("&projectCode=");
authUrl.append(SSOConstants.SSO_CLIENT_PROJECTCODE);
//没有验证通过,再去重新验证。
response.sendRedirect(authUrl.toString());
return;
}
SessionHandle handle;
try {
handle = (SessionHandle) (Class.forName(SSOConstants.SSO_CLIENT_SESSIONHANDLE).newInstance());
handle.handle(request, receipt);
} catch (Exception e) {
e.printStackTrace();
}
TICKET_SESSION_CACHE.put(ticket, request.getSession());
SESSION_TICKET_CACHE.put(request.getSession().getId(), ticket);
//如果没有参数
if(SSOUtils.isBlank(ssoParamCode))
{
chain.doFilter(request, response);
}else
{
Object requestPramObj = request.getSession().getAttribute("requestPram"+ssoParamCode);
RequestParameter param = (RequestParameter)requestPramObj;
//还原原来的请求场景
//generateHtmlFormSubmit(param,request,response);
//生成跳转链接,直接调转,废弃模拟表单提交的方式,因为表单提交的方式会出现不友好的loading页面。
String ssoUrl = this.generateRedirectUrl(param);
request.getSession().removeAttribute("requestPram"+ssoParamCode);
response.sendRedirect(ssoUrl);
return;
}
}
}
/**
* 被动单点退出
* @param request
* @param response
*/
private void ssoLogout(String ticket){
if(TICKET_SESSION_CACHE.containsKey(ticket))
{
HttpSession sess = TICKET_SESSION_CACHE.get(ticket);
if(null != sess)
{
SESSION_TICKET_CACHE.remove(sess.getId());
sess.invalidate();
}
TICKET_SESSION_CACHE.remove(ticket);
}
}
/**
* 单点登陆(登陆窗口在客户端)
* @param request
* @param response
* @throws IOException
* @throws ServletException
*/
private void ssoLogon(HttpServletRequest request,HttpServletResponse response) throws IOException, ServletException{
String ticket = request.getParameter("ticket");
String ssoerror = request.getParameter(SSOConstants.SSO_SERVER_ERROR);
//ssoerror不为空,说明已经从sso服务端登陆失败返回来了。
if(SSOUtils.isNotBlank(ssoerror))
{
String ssoParamCode = request.getParameter("ssoParamCode");
Object requestPramObj = request.getSession().getAttribute("requestPram"+ssoParamCode);
RequestParameter param = (RequestParameter)requestPramObj;
if(null != SSOConstants.SSO_CLIENT_LOGIN_ISREDIRECT && "false".equals(SSOConstants.SSO_CLIENT_LOGIN_ISREDIRECT))
{
//request.getSession().removeAttribute("requestPram"+ssoParamCode);
String loginUrl = request.getContextPath()+SSOConstants.SSO_CLIENT_LOGINURL;
//如果请求参数为空
if(null == requestPramObj)
{
response.sendRedirect(loginUrl);
return;
}
request.setAttribute(SSOConstants.SSO_SERVER_ERROR, ssoerror);
request.setAttribute("ssoLoginName", param.getParameter("loginName"));
request.setAttribute("ssoPassword", param.getParameter("password"));
request.getRequestDispatcher(loginUrl).forward(request, response);
return;
}
else
{
StringBuilder loginSB = new StringBuilder(request.getContextPath());
loginSB.append(SSOConstants.SSO_CLIENT_LOGINURL);
loginSB.append("?");
loginSB.append(SSOConstants.SSO_SERVER_ERROR);
loginSB.append("=");
loginSB.append(ssoerror);
loginSB.append("&ssoParamCode=");
loginSB.append(ssoParamCode);
//request.getSession().removeAttribute("requestPram"+ssoParamCode);
response.sendRedirect(loginSB.toString());
return;
}
}
//如果还没有验证
if(SSOUtils.isBlank(ticket))
{
//接收相关参数(必须的参数)传统登陆方式
String identity = request.getParameter("identity");
String password = request.getParameter("password");
String projectCode = SSOConstants.SSO_CLIENT_PROJECTCODE;
String backURL = request.getParameter("backURL");
if(SSOUtils.isBlank(identity) || SSOUtils.isBlank(password))
{
//不符合以上登陆方式,登陆失败
sendRedirect(request,response,SSOConstants.SSO_CLIENT_LOGINURL);
return;
}
String paramCode = RequestParameter.generateCode();
RequestParameter param = new RequestParameter();
//拼装参数信息
Map pramMap = new HashMap();
//密码加密传输
password = EncryptUtils.MD5Encode(password);
if(!SSOUtils.isBlank(identity))
{
pramMap.put("identity", new String[]{identity});
}
if(!SSOUtils.isBlank(password))
{
pramMap.put("password", new String[]{password});
}
pramMap.put("projectCode", new String[]{projectCode});
pramMap.put("service", new String[]{getService(request,paramCode,false)});
pramMap.put("backURL", new String[]{backURL});
param.setCode(paramCode);
param.setMethod("post");
param.setRequestPram(pramMap);
param.setAction(SSOConstants.SSO_SERVER_SIGNIN);
request.getSession().setAttribute("requestPram"+paramCode, param);
//拼装表单提交
//generateHtmlFormSubmit(param,request,response);
//生成跳转链接,直接调转,废弃模拟表单提交的方式,因为表单提交的方式会出现不友好的loading页面。
String ssoUrl = this.generateRedirectUrl(param);
response.sendRedirect(ssoUrl);
return;
}
//经过上面二层的判断,ticket不为空,说明已经从服务端验证通过了
String ssoParamCode = request.getParameter("ssoParamCode");
String service = getService(request,ssoParamCode,false);
SSOReceipt receipt = SSOUtils.validateTicket(ticket, service);
Object requestPramObj = request.getSession().getAttribute("requestPram"+ssoParamCode);
request.getSession().removeAttribute("requestPram"+ssoParamCode);
//如果请求参数为空
if(null == requestPramObj)
{
sendRedirect(request,response,SSOConstants.SSO_CLIENT_LOGINURL);
return;
}
RequestParameter param = (RequestParameter)requestPramObj;
//验证失败
if(null == receipt)
{
String loginName = param.getParameter("loginName");
String password = param.getParameter("password");
request.setAttribute(SSOConstants.SSO_SERVER_ERROR,"ticketerror");
request.setAttribute("loginName",loginName);
request.setAttribute("password",password);
request.getRequestDispatcher(SSOConstants.SSO_CLIENT_LOGINURL).forward(request, response);
return;
}
SessionHandle handle;
try {
handle = (SessionHandle) (Class.forName(SSOConstants.SSO_CLIENT_SESSIONHANDLE).newInstance());
handle.handle(request, receipt);
} catch (Exception e) {
e.printStackTrace();
}
//缓存ticket 和 session
TICKET_SESSION_CACHE.put(ticket, request.getSession());
SESSION_TICKET_CACHE.put(request.getSession().getId(), ticket);
//转向成功地址
String backURL = param.getParameter("backURL");
if(SSOUtils.isNotBlank(backURL))
{
sendRedirect(request,response,backURL);
}else
{
sendRedirect(request,response,SSOConstants.SSO_CLIENT_LOGINURL);
}
}
/**
* 获得service
* @param request
* @param paramCode
* @param encode
* @return
* @throws UnsupportedEncodingException
*/
private String getService(HttpServletRequest request,String paramCode,boolean encode) throws UnsupportedEncodingException{
StringBuffer sb = new StringBuffer();
sb.append(request.getScheme()+"://");
if(null == SSOConstants.SSO_CLIENT_SERVERNAME || "".equals(SSOConstants.SSO_CLIENT_SERVERNAME))
{
sb.append(request.getServerName());
}
else
{
sb.append(SSOConstants.SSO_CLIENT_SERVERNAME);
}
if(!"80".equals(request.getServerPort()))
{
sb.append(":");
sb.append(request.getServerPort());
}
sb.append(request.getRequestURI());
if(SSOUtils.isNotBlank(paramCode))
{
sb.append("?ssoParamCode="+paramCode);
}
if(encode)
{
String encodedService = URLEncoder.encode(sb.toString(),"utf-8");
return encodedService;
}else
{
return sb.toString();
}
}
/**
* 获得service
* @param request
* @param paramCode
* @param encode
* @return
* @throws UnsupportedEncodingException
*/
private String getService_bak(HttpServletRequest request,String paramCode,boolean encode) throws UnsupportedEncodingException{
StringBuffer sb = new StringBuffer();
sb.append(SSOConstants.HTTP_PRE);
sb.append(SSOConstants.SSO_CLIENT_SERVERNAME);
sb.append(request.getRequestURI());
if(SSOUtils.isNotBlank(paramCode))
{
sb.append("?ssoParamCode="+paramCode);
}
if(encode)
{
String encodedService = URLEncoder.encode(sb.toString(),"utf-8");
return encodedService;
}else
{
return sb.toString();
}
}
/**生成重定向url链接
*
* @param param
* @return
*/
private String generateRedirectUrl(RequestParameter param)
{
StringBuilder urlBuff = new StringBuilder();
urlBuff.append(param.getAction());
Set paramSet = param.getRequestPram().keySet();
String paramName = null;
String[] paramValues = null;
int idx = 0;
for (Iterator iterator = paramSet.iterator(); iterator.hasNext();) {
paramName = iterator.next();
paramValues = param.getRequestPram().get(paramName);
for(int i=0;i
{
if(i == 0 && idx ==0 && param.getAction().indexOf("?")<0)
{
urlBuff.append("?");
}else
{
urlBuff.append("&");
}
urlBuff.append(paramName);
urlBuff.append("=");
if (paramValues[i].contains("http")
|| paramValues[i].contains("#")
|| paramValues[i].contains("=")
|| paramValues[i].contains("&")
|| paramValues[i].contains("+")
|| paramValues[i].contains(".")
|| paramValues[i].contains("%"))
{
try {
urlBuff.append(java.net.URLEncoder.encode(paramValues[i],"utf-8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}else
{
urlBuff.append(paramValues[i]);
}
}
idx ++;
}
return urlBuff.toString();
}
/**
* 根据相关参数生成表单提交html代码
* @param param
* @param request
* @param response
* @throws IOException
*/
private void generateHtmlFormSubmit(RequestParameter param,HttpServletRequest request,HttpServletResponse response) throws IOException
{
response.setContentType("text/html");
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
out.println(""-//W3C//DTD HTML 4.01 Transitional//EN\">");
out.println("");
out.println("
");out.println("");
out.println("
loading...");out.println("
out.println("var i = 0;");
out.println("var s = \"loading\";");
out.println("function addPoint(){ ");
out.println("if(i<6){");
out.println("s += \".\";");
out.println("document.getElementById(\"point\").innerHTML = s;");
out.println("i++; ");
out.println("}else{ s = \"loading\";");
out.println("document.getElementById(\"point\").innerHTML = s;");
out.println("i = 0; ");
out.println("}}");
out.println("function loadPoint(){ window.setInterval(\"addPoint()\",200);}");
out.println("");
out.println("");
out.println("
");out.println("
");Set paramSet = param.getRequestPram().keySet();
String paramName = null;
String[] paramValues = null;
for (Iterator iterator = paramSet.iterator(); iterator.hasNext();) {
paramName = iterator.next();
paramValues = param.getRequestPram().get(paramName);
for(int i=0;i
{
out.println(" ");
}
}
out.println("
");//添加等待loading begin
out.println("
out.println("
");
out.println("loading......");
out.println("
//添加等待loading end
out.println(" ");
out.println("");
out.println("
out.println("window.document.forms[0].submit();");
out.println("");
out.flush();
out.close();
}
/**
* 客户端跳转
* @param request
* @param response
* @param url
* @throws IOException
*/
private void sendRedirect(HttpServletRequest request,HttpServletResponse response,String url) throws IOException
{
if(SSOUtils.isBlank(url))
{
return;
}
if(url.startsWith(SSOConstants.HTTP_PRE) || url.startsWith(SSOConstants.HTTPS_PRE))
{
response.sendRedirect(url);
return;
}
response.sendRedirect(request.getContextPath()+url);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
//如果通知类型为rabbitmq
if(SSOConstants.SSO_NOTIFICATION_TYPE.equals("rabbitmq"))
{
try {
//启动mq 消费线程
QueueConsumer consumer = new QueueConsumer("sso.*");
Thread consumerThread = new Thread(consumer);
consumerThread.start();
} catch (Exception e) {
System.out.println("启动mq线程报错");
e.printStackTrace();
}
}
}
@Override
public void destroy() {
}
}
一键复制
编辑
Web IDE
原始数据
按行查看
历史