公司产品需要对接一个CAS认证服务的单点登录,拿到手上的时候有点懵逼,但是问题还是需要解决的,到网上查了一下,全是基于tomcat服务的,使用过滤器来实现的,但是我们系统用的是内嵌的Jetty服务器,怎么办呢?
在此之前你得了解一下Jetty服务器的结构,怎样集成过滤器,可以参考以下:
https://www.cnblogs.com/kxdblog/p/6368836.html?utm_source=itdadao&utm_medium=referral
我这里用的是cas-client-core.jar的第三方包,大家如果想更加了解可以去看一下里面的源码。
添加了过滤器之后,然后就是servlet了,自己业务的登录逻辑。
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
AttributePrincipal principal = (AttributePrincipal) req.getUserPrincipal();
if (principal == null) {
logger.err("principal is null.");
return;
}
String userName = principal.getName();
if (userName == null) {
try {
throw new LogicalException("USER_NAME_IS_NULL", "USER_NAME_IS_NULL");
} catch (LogicalException e) {
e.printStackTrace();
}
}
if (userName == null) {
logger.err("userName is null.");
return;
}
try {
UserInfo userInfo = null;
try {
userInfo = this.beans.getUserCore().getModel().findUser(userName, null, null);
} catch (SQLException e) {
e.printStackTrace();
}
if (null != userInfo) {
// 根据用户信息获取网盘token
// 创建token添加到cookie
Env env = new Env(req, resp, "");
LoginInfo loginInfo = this.beans.getAuthApi().createToken(env, userInfo, SyncConfig.TOKENAGE);
Cookie panCookie = new Cookie("token", loginInfo.tokenInfo.token);
panCookie.setPath("/");
// 设置cookie时间
panCookie.setMaxAge(-1);
resp.addCookie(panCookie);
req.getSession().setAttribute("runTimeUser", userInfo);
// 重定向到xserver页面
resp.sendRedirect(SyncConfig.PANURL);
}
} catch (Exception e) {
logger.err("something error. userName:" + userName, e);
}
}
Jetty不像Tomcat一样初始化的时候web.xml就行,这个得自己添加到初始化里面去,才能起到作用。
Class clazz = httpServer.getClass();
Field field = clazz.getDeclaredField("handlers");
field.setAccessible(true);
List<Handler> handlers = (List<Handler>) field.get(httpServer);
// 移除web init中注册的"/*"路径
Iterator<Handler> iterator = handlers.iterator();
while (iterator.hasNext()) {
Handler handler = iterator.next();
if (handler instanceof ServletContextHandler) {
ServletContextHandler h = (ServletContextHandler) handler;
if (h.getContextPath().equals("/")) {
iterator.remove();
break;
}
}
}
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/");
ServletHandler handler = new ServletHandler();
String filterHodlerPath = "/*";
String filterPath = "/*";
// 单点退出
context.addEventListener(new SingleSignOutHttpSessionListener());
//添加单点退出的过滤器
FilterHolder singleSignOutFilterHolder = handler.addFilterWithMapping(SingleSignOutFilter.class, filterHodlerPath,
EnumSet.of(DispatcherType.REQUEST));
context.addFilter(singleSignOutFilterHolder, filterPath, EnumSet.of(DispatcherType.REQUEST));
// 单点登录
Map<String, String> params = new HashMap<>();
SyncConfig.serverName = properties.getProperty("serverName");
params.put("serverName", SyncConfig.serverName);
SyncConfig.loginUrlsJson = JSONObject.parseObject(properties.getProperty("casServerLoginUrls"));
SyncConfig.prefixJson = JSONObject.parseObject(properties.getProperty("casServerUrlPrefixs"));
if (SyncConfig.loginUrlsJson.size() != SyncConfig.prefixJson.size()) {
throw new LogicalException("CAS_CONFIG_ERROR", "CAS_CONFIG_ERROR");
}
params.put("casServerLoginUrls", properties.getProperty("casServerLoginUrls"));
params.put("casServerUrlPrefixs", properties.getProperty("casServerUrlPrefixs"));
for (String key : SyncConfig.prefixJson.keySet()) {
params.put("casServerUrlPrefix", SyncConfig.prefixJson.getString(key));
FilterHolder cas20ProxyReceivingTicketValidationFilterHolder = handler.addFilterWithMapping(
Cas20ProxyReceivingTicketValidationFilterWrapper.class, filterHodlerPath, EnumSet.of(DispatcherType.REQUEST));
cas20ProxyReceivingTicketValidationFilterHolder.setInitParameters(params);
context.addFilter(cas20ProxyReceivingTicketValidationFilterHolder, filterPath, EnumSet.of(DispatcherType.REQUEST));
}
for (String key : SyncConfig.loginUrlsJson.keySet()) {
params.put("casServerLoginUrl", SyncConfig.loginUrlsJson.getString(key));
FilterHolder authenticationFilterHolder = handler.addFilterWithMapping(AuthenticationFilterWrapper.class, filterHodlerPath,
EnumSet.of(DispatcherType.REQUEST));
authenticationFilterHolder.setInitParameters(params);
context.addFilter(authenticationFilterHolder, filterPath, EnumSet.of(DispatcherType.REQUEST));
}
FilterHolder httpServletRequestWrapperFilterHolder = handler.addFilterWithMapping(HttpServletRequestWrapperFilter.class,
filterHodlerPath, EnumSet.of(DispatcherType.REQUEST));
context.addFilter(httpServletRequestWrapperFilterHolder, filterPath, EnumSet.of(DispatcherType.REQUEST));
FilterHolder assertionThreadLocalFilterHolder = handler.addFilterWithMapping(AssertionThreadLocalFilter.class, filterHodlerPath,
EnumSet.of(DispatcherType.REQUEST));
context.addFilter(assertionThreadLocalFilterHolder, filterPath, EnumSet.of(DispatcherType.REQUEST));
context.setHandler(handler);
ServletHolder sh = new ServletHolder(new SsoServlet(beans, logger));
context.addServlet(sh, "/*");
handlers.add(context);
注意:注销的Filter必须放在最前面。
多网段配置采用json配置文件来制作,在初始化的时候将Fiter重写(jar包内的是final,无法重写,需要自己修改一下jar包内容,重写的init需要将初始化存入json的各网断地址拿出来,doFilter需要用到,doFilter里面就需要对多网段和客户端地址进行判断对比匹配。)
public class Cas20ProxyReceivingTicketValidationFilterWrapper extends Cas20ProxyReceivingTicketValidationFilter {
private JSONObject prefixJson;
private String currentServerName;
private String currentPrefixUrl;
@Override
protected void initInternal(FilterConfig filterConfig) throws ServletException {
String casServerUrlPrefixs = filterConfig.getInitParameter("casServerUrlPrefixs");
prefixJson = JSONObject.parseObject(casServerUrlPrefixs);
currentPrefixUrl = filterConfig.getInitParameter("casServerUrlPrefix");
for (String key : prefixJson.keySet()) {
String value = prefixJson.getString(key);
if (value.equalsIgnoreCase(currentPrefixUrl)) {
currentServerName = key;
break;
}
}
super.initInternal(filterConfig);
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
final HttpServletRequest request = (HttpServletRequest) servletRequest;
final String host = request.getHeader("Host");
final String xHost = request.getHeader("X-Forwarded-For");
final String comparisonHost;
if (xHost != null && host == "localhost") {
comparisonHost = xHost;
} else {
comparisonHost = host;
}
if (currentServerName.equalsIgnoreCase(comparisonHost)) {
request.setAttribute("casServerUrlPrefix", currentPrefixUrl);
super.doFilter(servletRequest, servletResponse, filterChain);
} else {
filterChain.doFilter(servletRequest, servletResponse);
}
}
}
最后就是退出了。退出坑还是挺多的。给个链接参考一下,里面说的比较详细,我这里就不一一细说了。
https://www.cnblogs.com/codestory/p/5512104.html