前后端分离的项目集成CAS
java1234
共 15318字,需浏览 31分钟
·
2021-06-13 18:16
点击上方蓝色字体,选择“标星公众号”
优质文章,第一时间送达
作者 | 一头磕在键盘上
来源 | urlify.cn/UV7Vvu
问题一、前后端分离项目如何集成CAS
1. 修改web.xml
增加对cas.jsp
的拦截
<filter-mapping>
<filter-name>CAS Filter</filter-name>
<url-pattern>/cas.jsp</url-pattern>
</filter-mapping>
2.未登录时,前端重定向后端cas.jsp
// 没有登录,跳转后端cas.jsp
if(notLogin){
window.location.href='192.168.0.100:8080/api-server/cas.jsp';
}
//和上面代码结果一样,但是节省一次重定向开销.参考代码如下
if(notLogin){
window.location.href=`192.168.0.90:8080/cas/login?service=192.168.0.100:8080/api-server/cas.jsp`;
}
3. cas.jsp
重定向到前端
// 重定向到前端地址.
String url = "192.168.0.120";
response.sendRedirect(url);
4. 保证将JSESSIONID
写入前端cookie
中
//获取sessionid
String jsessionid = session.getId();
// 前端地址.
String url = "192.168.0.120";
response.sendRedirect(url + "?jsessionid=" + jsessionid);
// getJsessionIdFromUrl() 从地址栏里获取jseesionid参数的值,具体逻辑自行实现
var jsessionid = getJsessionIdFromUrl();
// setCookie() 写入cookie,具体逻辑自行实现
setCookie('jsessionid',jsessionid);
方案流程
问题二、CAS
如何和原有的登录认证做对接
// cas.jsp 内容
// cas会将用户信息写入session中. request.getAttribute("_const_cas_assertion_") 也可以拿到.
Object object = request.getSession().getAttribute("_const_cas_assertion_");
// org.jasig.cas.client.validation.Assertion
Assertion assertion = (Assertion) object;
// 获取到用户名
String userName = assertion.getPrincipal().getName()
/*
假设原有登录是调用的 loginService.login(userName,password);方法
那我们增加一个免密登录方法 loginService.loginWithOutPWD(userName),
里面的处理逻辑和返回值 同loginService.login(userName,password)基本一致,唯独不再需要密码.
*/
Object obj = loginService.loginWithOutPWD(userName);
// isLogin判断是否二次登录成功
if(isLogin(obj)){
// 二次登录成功,调整前端. 如果原有登录有其它参数需要给前端,也可以附带在url后面.
//获取sessionid
String jsessionid = session.getId();
// 前端地址.
String url = "192.168.0.120";
response.sendRedirect(url + "?jsessionid=" + jsessionid);
}else{
// 二次登录失败
//...
}
CAS认证原理
CAS
基本概念
1.体系结构
2. 核心票据
TGT(Ticket Grangting Ticket)
TGC(Ticket-granting cookie)
ST(ServiceTicket)
3. 核心过滤器
CAS
认证原理
CAS客户端核心过滤器
AuthenticationFilter
<filter>
<filter-name>CAS Filter</filter-name>
<filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>
<init-param>
<param-name>casServerLoginUrl</param-name>
<param-value>${cas.serverUrl}/login</param-value>
</init-param>
<init-param>
<param-name>serverName</param-name>
<param-value>${cas.clientUrl}</param-value>
</init-param>
<init-param>
<param-name>ignorePattern</param-name>
<param-value>.*/login|.*/unsafe|.*/api/app/token/*|.*\.ico|.*\.js(?!p)|.*\.css|</param-value>
</init-param>
<init-param>
<param-name>ignoreUrlPatternType</param-name>
<param-value>REGEX</param-value>
</init-param>
...
</filter>
<filter-mapping>
<filter-name>CAS Filter</filter-name>
<url-pattern>/cas.jsp</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>CAS Filter</filter-name>
<url-pattern>/api/*</url-pattern>
</filter-mapping>
public final void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse,
final FilterChain filterChain) throws IOException, ServletException {
final HttpServletRequest request = (HttpServletRequest) servletRequest;
final HttpServletResponse response = (HttpServletResponse) servletResponse;
// 判断请求是否不需要过滤
if (isRequestUrlExcluded(request)) {
logger.debug("Request is ignored.");
filterChain.doFilter(request, response);
return;
}
final HttpSession session = request.getSession(false);
// CONST_CAS_ASSERTION = "_const_cas_assertion_"
final Assertion assertion = session != null ? (Assertion) session.getAttribute(CONST_CAS_ASSERTION) : null;
// 存在assertion,即认为这是一个已通过认证的请求.予以放行
if (assertion != null) {
filterChain.doFilter(request, response);
return;
}
// 不存在 assertion,那么就来判断这个请求是否是用来校验ST的(校验通过后会将信息写入assertion)
final String serviceUrl = constructServiceUrl(request, response);
final String ticket = retrieveTicketFromRequest(request);
final boolean wasGatewayed = this.gateway && this.gatewayStorage.hasGatewayedAlready(request, serviceUrl);
// 是校验ST的请求,予以放行
if (CommonUtils.isNotBlank(ticket) || wasGatewayed) {
filterChain.doFilter(request, response);
return;
}
final String modifiedServiceUrl;
logger.debug("no ticket and no assertion found");
if (this.gateway) {
logger.debug("setting gateway attribute in session");
modifiedServiceUrl = this.gatewayStorage.storeGatewayInformation(request, serviceUrl);
} else {
modifiedServiceUrl = serviceUrl;
}
logger.debug("Constructed service url: {}", modifiedServiceUrl);
// 要重定向界面地址(cas服务端登录界面).
final String urlToRedirectTo = CommonUtils.constructRedirectUrl(this.casServerLoginUrl,
getProtocol().getServiceParameterName(), modifiedServiceUrl, this.renew, this.gateway);
logger.debug("redirecting to \"{}\"", urlToRedirectTo);
this.authenticationRedirectStrategy.redirect(request, response, urlToRedirectTo);
}
TicketValidationFilter
<filter>
<filter-name>CAS Validation Filter</filter-name>
<filter-class>
org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter
</filter-class>
</filter>
final Assertion assertion = this.ticketValidator.validate(ticket,
constructServiceUrl(request, response));
logger.debug("Successfully authenticated user: {}", assertion.getPrincipal().getName());
// CONST_CAS_ASSERTION = "_const_cas_assertion_"
request.setAttribute(CONST_CAS_ASSERTION, assertion);
// useSession 对应配置项中的useSession参数,缺省值为true.但这个配置在3.4版本之后是弃用的,后续随时可能会被移除.
if (this.useSession) {
request.getSession().setAttribute(CONST_CAS_ASSERTION, assertion);
}
关于session
、cookie
及JSESSIONID
在其中起到的作用
评论