让CAS支持客户端自定义登陆页面——服务器新篇让CAS支持客户端自定义登陆页面——服务器新篇
让CAS支持客户端自定义登陆页面——服务器新篇
最近公司研发产品,将基于CAS的SSO列为了研究方向之一,统一登录统一认证还是比较简单的,因为领导指示,还要适应分散登录统一认证,所以还是要努力去实现。
在网上搜了搜,有一篇“让CAS支持客户端自定义登陆页面”的文章,分服务器篇和客户端篇两个部分,思路符合的,也提供了挺详细的代码,但问题是该文章是基于spring web flow 1.X的,现在的CAS服务是3.4.10版本,其内部流程用的是spring web flow 2...
让CAS支持客户端自定义登陆页面——服务器新篇
让CAS支持客户端自定义登陆页面——服务器新篇
最近公司研发产品,将基于CAS的SSO列为了研究方向之一,统一登录统一认证还是比较简单的,因为领导指示,还要适应分散登录统一认证,所以还是要努力去实现。
在网上搜了搜,有一篇“让CAS支持客户端自定义登陆页面”的文章,分服务器篇和客户端篇两个部分,思路符合的,也提供了挺详细的代码,但问题是该文章是基于spring web flow 1.X的,现在的CAS服务是3.4.10版本,其内部流程用的是spring web flow 2.X版本。
spring web flow 2.X和spring web flow 1.X不是向下兼容的,基本上流程代码是不能用了。我做了大量的修改,目前远程登录和远程退出都实现了,现在将符合spring web flow 2.X的做法记录下来,和需要的朋友们共享。
接下来我们讲解服务器端修改的详细过程:
1、修改/WEB-INF/web.xml,为cas增加一个/remoteLogin和//remoteLogout的映射,否则总是会转到login那个请求去了:
cas
/remoteLogin
cas
/remoteLogout
2、然后修改cas-servlet.xml文件,增加对/remoteLogin和/remoteLogout映射的处理,需要增加两个新流程:
remoteLoginController
remoteLogoutController
3、流程定义的xml文件:可以看到上面将请求指向了webflow配置文件
/WEB-INF/remoteLogin-webflow.xml和/WEB-INF/remoteLogout-webflow.xml,我们需要创
建此文件并配置其成为我们所需的流程。
以下是remoteLogin-webflow.xml全文:
以下是remoteLogout-webflow.xml全文:
4、流程首先由Action类进行处理,成功或失败都将转回 remoteCallbackView,这样就返回
了远程的登录页面。
4.1、登录处理Action类:
package com.cas.web.flow;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import org.jasig.cas.authentication.principal.Service; import org.jasig.cas.web.support.ArgumentExtractor; import org.jasig.cas.web.support.CookieRetrievingCookieGenerator; import org.jasig.cas.web.support.WebUtils;
import org.springframework.util.StringUtils;
import org.springframework.webflow.action.AbstractAction; import org.springframework.webflow.execution.Event; import org.springframework.webflow.execution.RequestContext;
/**
* 远程登陆票据提供Action.
* 根据InitialFlowSetupAction修改.
* 由于InitialFlowSetupAction为final类,因此只能将代码复制过来再进行修改.
*/
public class RemoteLoginAction extends AbstractAction {
/** CookieGenerator for the Warnings. */
@NotNull
private CookieRetrievingCookieGenerator warnCookieGenerator;
/** CookieGenerator for the TicketGrantingTickets. */
@NotNull
private CookieRetrievingCookieGenerator ticketGrantingTicketCookieGenerator;
/** Extractors for finding the service. */
@NotNull
@Size(min=1)
private List
argumentExtractors;
/** Boolean to note whether we've set the values on the generators or not. */
private boolean pathPopulated = false;
protected Event doExecute(final RequestContext context) throws Exception {
final HttpServletRequest request =
WebUtils.getHttpServletRequest(context);
if (!this.pathPopulated) {
final String contextPath =
context.getExternalContext().getContextPath();
final String cookiePath = StringUtils.hasText(contextPath) ? contextPath : "/";
logger.info("Setting path for cookies to: " + cookiePath);
this.warnCookieGenerator.setCookiePath(cookiePath);
this.ticketGrantingTicketCookieGenerator.setCookiePath(cookiePath);
this.pathPopulated = true;
}
context.getFlowScope().put("ticketGrantingTicketId", this.ticketGrantingTicketCookieGenerator.retrieveCookieValue(request));
context.getFlowScope().put("warnCookieValue",
Boolean.valueOf(this.warnCookieGenerator.retrieveCookieValue(request)));
final Service service = WebUtils.getService(this.argumentExtractors, context);
if (service != null && logger.isDebugEnabled()) {
logger.debug("Placing service in FlowScope: " + service.getId());
}
context.getFlowScope().put("service", service);
// 客户端必须传递loginUrl参数过来,否则无法确定登陆目标页面
if (StringUtils.hasText(request.getParameter("loginUrl"))) {
context.getFlowScope().put("remoteLoginUrl",
request.getParameter("loginUrl"));
} else {
request.setAttribute("remoteLoginMessage", "loginUrl parameter must be supported.");
return error();
}
// 若参数包含submit则进行提交,否则进行验证
if (StringUtils.hasText(request.getParameter("submit"))) {
return result("submit");
} else {
return result("checkTicketGrantingTicket");
}
}
public void setTicketGrantingTicketCookieGenerator(
final CookieRetrievingCookieGenerator ticketGrantingTicketCookieGenerator)
{
this.ticketGrantingTicketCookieGenerator = ticketGrantingTicketCookieGenerator;
}
public void setWarnCookieGenerator(final CookieRetrievingCookieGenerator
warnCookieGenerator) {
this.warnCookieGenerator = warnCookieGenerator;
}
public void setArgumentExtractors(final List argumentExtractors) {
this.argumentExtractors = argumentExtractors;
}
}
4.2、退出处理Action类:
package com.cas.web.flow;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import org.jasig.cas.CentralAuthenticationService; import org.jasig.cas.authentication.principal.Service; import org.jasig.cas.web.support.ArgumentExtractor; import org.jasig.cas.web.support.CookieRetrievingCookieGenerator; import org.jasig.cas.web.support.WebUtils;
import org.springframework.util.StringUtils;
import org.springframework.webflow.action.AbstractAction; import org.springframework.webflow.execution.Event; import org.springframework.webflow.execution.RequestContext;
public class RemoteLogoutAction extends AbstractAction {
@NotNull
private CookieRetrievingCookieGenerator ticketGrantingTicketCookieGenerator;
@NotNull
private CookieRetrievingCookieGenerator warnCookieGenerator;
@NotNull
private CentralAuthenticationService centralAuthenticationService;
@NotNull
@Size(min=1)
private List argumentExtractors;
private boolean pathPopulated = false;
@Override
protected Event doExecute(final RequestContext context) throws Exception {
final HttpServletRequest request =
WebUtils.getHttpServletRequest(context);
final HttpServletResponse response =
WebUtils.getHttpServletResponse(context);
if (!this.pathPopulated) {
final String contextPath =
context.getExternalContext().getContextPath();
final String cookiePath = StringUtils.hasText(contextPath) ? contextPath : "/";
logger.info("Setting path for cookies to: " + cookiePath);
this.warnCookieGenerator.setCookiePath(cookiePath);
this.ticketGrantingTicketCookieGenerator.setCookiePath(cookiePath);
this.pathPopulated = true;
}
context.getFlowScope().put("ticketGrantingTicketId", this.ticketGrantingTicketCookieGenerator.retrieveCookieValue(request));
context.getFlowScope().put("warnCookieValue",
Boolean.valueOf(this.warnCookieGenerator.retrieveCookieValue(request)));
final Service service = WebUtils.getService(this.argumentExtractors, context);
if (service != null && logger.isDebugEnabled()) {
logger.debug("Placing service in FlowScope: " + service.getId());
}
context.getFlowScope().put("service", service);
context.getFlowScope().put("remoteLoginUrl",
request.getParameter("service"));
final String ticketGrantingTicketId =
this.ticketGrantingTicketCookieGenerator.retrieveCookieValue(request);
if (ticketGrantingTicketId != null) {
this.centralAuthenticationService.destroyTicketGrantingTicket(ticketGrantingTicketId);
this.ticketGrantingTicketCookieGenerator.removeCookie(response);
this.warnCookieGenerator.removeCookie(response);
}
return result("success");
}
public void setTicketGrantingTicketCookieGenerator(final CookieRetrievingCookieGenerator ticketGrantingTicketCookieGenerator) {
this.ticketGrantingTicketCookieGenerator =
ticketGrantingTicketCookieGenerator;
}
public void setWarnCookieGenerator(final CookieRetrievingCookieGenerator warnCookieGenerator) {
this.warnCookieGenerator = warnCookieGenerator;
}
public void setArgumentExtractors(final List argumentExtractors) {
this.argumentExtractors = argumentExtractors;
}
public void setCentralAuthenticationService(final CentralAuthenticationService centralAuthenticationService){
this.centralAuthenticationService = centralAuthenticationService;
}
}
4.3、cas的登录页面,username和password是传递给
这个变量的,判断用户登录信息也以这个变量传递给
org.jasig.cas.web.flow.AuthenticationViaFormAction的submit方法来进行,很遗憾,
这个变量没法中间赋值(反正我不会),所以我重构了一个方法:
public final String submit(final RequestContext context, final MessageContext messageContext) throws Exception {
// Validate login ticket
final String authoritativeLoginTicket =
WebUtils.getLoginTicketFromFlowScope(context);
final String providedLoginTicket =
WebUtils.getLoginTicketFromRequest(context);
if (!authoritativeLoginTicket.equals(providedLoginTicket)) {
this.logger.warn("Invalid login ticket " + providedLoginTicket);
final String code = "INVALID_TICKET";
messageContext.addMessage(new
MessageBuilder().error().code(code).arg(providedLoginTicket).defaultText(code).build());
return "error";
}
final String ticketGrantingTicketId =
WebUtils.getTicketGrantingTicketId(context);
final Service service = WebUtils.getService(context);
final HttpServletRequest request =
WebUtils.getHttpServletRequest(context);
org.jasig.cas.authentication.principal.UsernamePasswordCredentials credentials = new
org.jasig.cas.authentication.principal.UsernamePasswordCredentials();
credentials.setPassword(request.getParameter("password"));
credentials.setUsername(request.getParameter("username"));
if (StringUtils.hasText(context.getRequestParameters().get("renew")) && ticketGrantingTicketId != null && service != null) {
try {
final String serviceTicketId =
this.centralAuthenticationService.grantServiceTicket(ticketGrantingTicketId, service, credentials);
WebUtils.putServiceTicketInRequestScope(context, serviceTicketId);
putWarnCookieIfRequestParameterPresent(context);
return "warn";
} catch (final TicketException e) {
if (e.getCause() != null &&
AuthenticationException.class.isAssignableFrom(e.getCause().getClass())) {
populateErrorsInstance(e, messageContext);
return "error";
}
this.centralAuthenticationService.destroyTicketGrantingTicket(ticketGrantingTicketId);
if (logger.isDebugEnabled()) {
logger.debug("Attempted to generate a ServiceTicket using renew=true with different credentials", e);
}
}
}
try {
WebUtils.putTicketGrantingTicketInRequestScope(context, this.centralAuthenticationService.createTicketGrantingTicket(credentials));
putWarnCookieIfRequestParameterPresent(context);
return "success";
} catch (final TicketException e) {
populateErrorsInstance(e, messageContext);
return "error";
}
}
这个方法直接从request里获得username和password,然后验证。
5、配置remoteCallbackView显示节点,修改src/default_views.properties文件,增加
remoteCallbackView配置:
### 配置远程回调页面
remoteCallbackView.(class)=org.springframework.web.servlet.view.JstlView remoteCallbackView.url=/WEB-INF/view/jsp/default/ui/remoteCallbackView.jsp
6、创建/WEB-INF/view/jsp/default/ui/remoteCallbackView.jsp文件:
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
<%@ taglib prefix="c" uri=";%> <%@ taglib prefix="spring" uri=";%>
${remoteLoginMessage}
到此,服务器端修改完成,下一篇介绍客户端如何构建
本文档为【让CAS支持客户端自定义登陆页面——服务器新篇】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑,
图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。