NC集成CAS统一认证+单点登录原理
程序员文章站
2022-05-05 16:32:25
...
原理及步骤:
1、浏览器中输入应用地址http://IP:port/inedx.jsp。
进入NC服务器拦截器1处理:如果URI是/index.jsp且ticket==null,且Assertion==null,则跳转到CAS认证页面。
2、CAS登录成功,跳转回业务系统/index.jsp页面。
进入NC服务器拦截器1处理:此时ticket!=null,流转到拦截器2进行ticket校验。
3、拦截器2校验未通过则终止;通过则设置Assertion(包含用户名等信息),并跳转到/index.jsp;jsessionid=XX。注意此时的URI是/index.jsp;jsessionid=XX,而不是/inedx.jsp。
4、拦截器1进行处理,此时ticket==null但Assertion!=null,进行ssokey注册和跳转到单点登录地址,CAS单点登录成功。
流程图:
web.xml配置
<!--统一认证 start-->
<!--用于实现单点退出-->
<listener>
<listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
</listener>
<filter>
<filter-name>CAS Single Sign Out Filter</filter-name>
<filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CAS Single Sign Out Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--该过滤器负责用户的认证工作,判断用户是否登录(必须) start-->
<filter>
<filter-name>CASAuthenticationFilter</filter-name>
<filter-class>nc.bs.cas.login.AuthenticationFilter</filter-class>
<init-param>
<!--注意casServerLoginUrl指服务器的地址 -->
<param-name>casServerLoginUrl</param-name>
<param-value>http://XX:XX</param-value>
</init-param>
<init-param>
<!-- 当指定renew为true时,在请Cas Server时将带上参数“renew=true”,默认为false -->
<param-name>renew</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<!-- 指定gateway为true时,在请求Cas Server时将带上参数“gateway=true”,默认为false。 -->
<param-name>gateway</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<!--而serverName指的是应用的地址 -->
<param-name>serverName</param-name>
<param-value>http://XX:XX</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CASAuthenticationFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--该过滤器负责用户的认证工作 end-->
<!-- 该过滤器配置负责对Ticket的校验工作,对于client接收到的ticket进行验证(必须) start -->
<!--这个过滤器可以从ticket取出CAS的session赋值到应用系统-->
<filter>
<filter-name>CASValidationFilter</filter-name>
<filter-class>org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter</filter-class>
<init-param>
<!--注意casServerLoginUrl指服务器的地址 -->
<param-name>casServerUrlPrefix</param-name>
<param-value>http://XX:XX</param-value>
</init-param>
<init-param>
<!--而serverName指的是应用的地址 -->
<param-name>serverName</param-name>
<param-value>http://XX:XX</param-value>
</init-param>
<init-param>
<param-name>useSession</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>redirectAfterValidation</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CASValidationFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 该过滤器配置负责对Ticket的校验工作 end -->
<!--统一认证 end-->
拦截器1核心代码:
private boolean isExclude(HttpServletRequest request){
boolean isInWhiteList = true;
String uri=request.getRequestURI();
// /index.jsp
// 1. /index.jsp 跳转到CAS认证页面
// 2. /index.jsp 有ticket 认证页面第一次跳回系统时有ticket,让校验器处理
if("/index.jsp".equals(uri)){
isInWhiteList = false;
}
// /index.jsp;jsessionid=82547E908AAE29F76F5D598533818E6D.server
// 3. 校验器处理通过后重定向到系统,/index.jsp;jsessionid或者/;jsessionid
else if(uri!=null&&(uri.startsWith("/index.jsp;jsessionid")||uri.startsWith("/;jsessionid"))){
isInWhiteList = false;
}
return isInWhiteList;
}
@Override
public final void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException
{
HttpServletRequest request = (HttpServletRequest)servletRequest;
HttpServletResponse response = (HttpServletResponse)servletResponse;
if(isExclude(request)){
filterChain.doFilter(request, response);
return;
}
String ticket = CommonUtils.safeGetParameter(request, getArtifactParameterName());
// 只有从认证页面跳回系统那一次请求有ticket
if(CommonUtils.isNotBlank(ticket))
{
log.error("######check ticket, uri="+request.getRequestURI()+", ticket="+ticket);
filterChain.doFilter(request, response);
return;
}
// 存在session则返回,否则返回null
HttpSession session = request.getSession(false);
Assertion assertion = session == null ? null : (Assertion)session.getAttribute(AbstractCasFilter.CONST_CAS_ASSERTION);
if(assertion != null)
{
String user=InvocationInfoProxy.getInstance().getUserCode();
if(isNullStr(user)){
log.error("######register ssoKey, uri="+request.getRequestURI());
String loginName = assertion.getPrincipal().getName();
// 登录NC
String appServer=this.serverName;
if(appServer==null){
appServer=request.getScheme() + "://" + request.getLocalAddr()+":"+request.getLocalPort();
}else if(appServer.endsWith("/")){
appServer=appServer.substring(0, appServer.length()-1);
}
// 1.生成ssoKey
String randomKey = IDMaker.makeID(30);
// 拼接NCURL跳转URL ssoRegServlet?ssoKey=key&userCode=
String regUrl = appServer + "/service/ssoRegServlet?ssoKey=" + randomKey + "&userCode=" + loginName;
// 2.注册ssoKey
try {
registerConnect(regUrl);
} catch (Exception e) {
Logger.error("注册ssoKey时异常", e);
}
// 3.通过ssoKey登录
String newUrl=appServer + "/login.jsp?ssoKey=" + randomKey;
response.sendRedirect(newUrl);
return;
}
filterChain.doFilter(request, response);
return;
}else{
// 控制是否启用CAS统一认证,系统参数异常时不走CAS
try {
List<SysInitVO>list=(List<SysInitVO>) getDao().retrieveByClause(SysInitVO.class, "initcode ='" + SQLTransferMeaningUtil.tmsql(AuthenticationFilter.PARAM_CAS) + "'and pk_org='" + SQLTransferMeaningUtil.tmsql(IOrgConst.GLOBEORG) + "'");
if(list!=null&&list.size()>0){
UFBoolean cas=new UFBoolean(list.get(0).getValue());
if(cas!=null&&cas.booleanValue()==false){
filterChain.doFilter(request, response);
return;
}
}
} catch (Exception e1) {
Logger.error("获取系统参数错误", e1);
filterChain.doFilter(request, response);
return;
}
log.error("######sendRedirect to cas, uri="+request.getRequestURI());
Logger.debug("no ticket and no assertion found");
String serviceUrl = constructServiceUrl(request, response);
String modifiedServiceUrl;
if(gateway)
{
Logger.debug("setting gateway attribute in session");
modifiedServiceUrl = gatewayStorage.storeGatewayInformation(request, serviceUrl);
} else
{
modifiedServiceUrl = serviceUrl;
}
String urlToRedirectTo = CommonUtils.constructRedirectUrl(casServerLoginUrl, getServiceParameterName(), modifiedServiceUrl, renew, gateway);
// 重定向
response.sendRedirect(urlToRedirectTo);
return;
}
}