3 搭建过程
3.1 搭建环境
本文搭建过程以cas-server-4.2.7,cas-client-3.4.1为例。构建环境为Idea 2017.1, Gradle3.5。
3.2 服务端搭建
3.2.1 安装配置Gradle
3.2.1.1 下载安装gradle
cas-server-4.2.7所使用构建工具为Gradle,所以需要先安装好Gradle。
3.2.1.2 配置gradle本地仓库
配置环境变量GRADLE_USER_HOME,并指向你的一个本地目录,用来保存Gradle下载的依赖包。
3.2.1.3 远程仓库配置
一般Gradle、maven从中央仓库mavenCentral下载依赖包,但是在国内下载速度巨慢,我们只能使用国内的镜像。 我们可以在cas-server项目的根目录下,对build.gradle做如下配置:
repositories {
maven {
url 'http://maven.aliyun.com/nexus/content/groups/public/'
}
mavenCentral()
}
3.2.2构建项目
将下载好的cas-4.2.7解压到cas-server目录,在Idea中打开项目。
选择使用本地Gradle版本,接下来就是漫长的等待项目加载过程。
3.2.3 实现自定义用户登录
cas原始登陆验证十分简单,只需在cas.properties中配置accept.authn.users字段即可,初始登录名密码为casuser,Mellon。为了实现真正的登陆验证,我们需要实现自己的登录验证流程。
3.2.3.1 建立自定义账号密码处理类:
在cas-server-core-authentication模块,org.jasig.cas.authentication包下新建自定义账号密码处理类。以建立sunlandsAuthenticationHandler为例:
@Component("sunlandsAuthenticationHandler")public class SunlandsAuthenticationHandler extends AbstractUsernamePasswordAuthenticationHandler {
/** The default separator in the file. */
private static final String DEFAULT_SEPARATOR = "::";
private static final Pattern USERS_PASSWORDS_SPLITTER_PATTERN = Pattern.compile(DEFAULT_SEPARATOR);
/** The list of users we will accept. */
private Map users;
@Value("${accept.authn.users:}")
private String acceptedUsers;
@Autowired
private SdfPasswordValidatorImpl sdfPasswordValidatorImpl; //验证账号密码的实现类
@Override
protected HandlerResult authenticateUsernamePasswordInternal(final UsernamePasswordCredential credential) throws GeneralSecurityException, PreventedException {
if (users == null || users.isEmpty()) {
throw new FailedLoginException("No user can be accepted because none is defined");
}
final String username = credential.getUsername();
final String password = credential.getPassword();
try {
boolean isValidUser = sdfPasswordValidatorImpl.authenticate(username,
password); //返回true则验证通过
if (!isValidUser) {
throw new FailedLoginException("Password does not match value on record.");
}
} catch (Exception e) {
throw new FailedLoginException("login failed.");
}
return createHandlerResult(credential, this.principalFactory.createPrincipal(username), null);
}
/**
* @param users The users to set.
*/
public final void setUsers(@NotNull final Map users) {
this.users = Collections.unmodifiableMap(users);
}
@PostConstruct
public void init() {
if (StringUtils.isNotBlank(this.acceptedUsers) && this.users == null) {
final Set usersPasswords = org.springframework.util.StringUtils.commaDelimitedListToSet(this.acceptedUsers);
final Map parsedUsers = new HashMap<>();
for (final String usersPassword : usersPasswords) {
final String[] splitArray = USERS_PASSWORDS_SPLITTER_PATTERN.split(usersPassword);
parsedUsers.put(splitArray[0], splitArray[1]);
}
setUsers(parsedUsers);
}
}
}
在authenticateUsernamePasswordInternal()方法中实现账号和密码的验证逻辑, 我这里是引入并调用了公司原有系统的密码账号验证类SdfPasswordValidatorImpl。
在类SdfPasswordValidatorImpl 的authenticate()方法中,用户自定义账号密码验证逻辑, 返回true则验证通过。
3.2.3.2配置自定义验证处理类:
在deployerConfigContext中将
···
···
替换为
···
···
3.2.4 自定义登录页面
3.2.5 实现ST与TGC存入redis
3.2.6 实现单点登录跳转地址限制
从应用系统跳转到cas登录页面时,会在登录地址后附带应用系统的地址,如
http://www.casserver.com/serviceValidate?service=http://www.client1.com/index,登陆之后就会跳转回应用系统页面http://www.client1.com/index。
Service地址在cas服务器后端并没有进行验证, service为任意网址均能跳转。在遭遇网络劫持或其他情况下,可能会从cas登录页面跳转到非公司网址,造成安全隐患,因此需要对service后的跳转地址进行验证。在service地址不符合要求的情况下,跳转到登陆成功的主页,而不是service地址。
3.2.6.1 修改cas.properties
在cas.properties文件中新增允许跳转的service地址变量,用 “| ”符号分隔,支持正则形式。
···
//# 允许跳转的service地址
service.allowed=xxx.cn|yyy.com
···
3.2.6.2 修改GenerateServiceTicketAction
修改GenerateServiceTicketAction类:
添加私有属性 serviceAllowed以及是否可以跳转标记常量
private static final Integer REGISTERED_SERVICE_FLAG = 1;
private static final Integer UNREGISTERED_SERVICE_FLAG = 0;
@Value("${service.allowed}")
private String serviceAllowed;
修改doExecute方法
final ServiceTicket serviceTicketId = this.centralAuthenticationService
.grantServiceTicket(ticketGrantingTicket, service, authenticationContext);
WebUtils.putServiceTicketInRequestScope(context, serviceTicketId);
// 新增开始
//判断service是否注册
Integer serviceFlag = UNREGISTERED_SERVICE_FLAG;
if(serviceAllowed !=null && !serviceAllowed.isEmpty()){
try {
String url = new URL(service.toString()).getHost();
String[] services = serviceAllowed.split("\\|");
for(String ser : services){
Pattern pattern = Pattern.compile(ser);
if (!pattern.matcher(url).matches()) continue;
serviceFlag = REGISTERED_SERVICE_FLAG;
}
if(serviceFlag==0) return new Event(this,"unregisteredService");
} catch (Exception e) {
logger.error("识别service是否注册失败",e);
return new Event(this,"unregisteredService");
}
}
//新增结束
return success();
3.6.2.3修改log-webflow.xml
3.3 应用系统端搭建
3.3.1 应用系统接入单点登录配置
若对应用系统端没有个性化需求, 应用系统直接引用cas-client jar包。并进行配置即可实现单点登录。
3.3.1.1 引入cas-client统一登录jar包
maven项目引入:
在pom文件中添加以下代码
org.jasig.cas.client
cas-client-core
3.4.1
org.slf4j
slf4j-api
1.7.10
3.3.1.2 配置文件
修改web.xml
在项目web.xml 中引入以下代码。引入内容应在系统原有字符串过滤filter之后,以免造成系统原有字符串过滤filter不能使用。
org.springframework.web.context.ContextLoaderListener
contextConfigLocation
classpath:casFilter.xml
org.jasig.cas.client.session.SingleSignOutHttpSessionListener
CAS Single Sign Out Filter
org.springframework.web.filter.DelegatingFilterProxy
targetFilterLifecycle
true
targetBeanName
singleSignOutFilter
CAS Single Sign Out Filter
/*
CAS Authentication Filter
org.springframework.web.filter.DelegatingFilterProxy
targetFilterLifecycle
true
targetBeanName
authenticationFilter
CAS Authentication Filter
/*
CAS Validation Filter
org.springframework.web.filter.DelegatingFilterProxy
targetFilterLifecycle
true
targetBeanName
ticketValidationFilter
CAS Validation Filter
/*
CAS HttpServletRequest Wrapper Filter
org.jasig.cas.client.util.HttpServletRequestWrapperFilter
CAS HttpServletRequest Wrapper Filter
/*
CAS Assertion Thread Local Filter
org.jasig.cas.client.util.AssertionThreadLocalFilter
CAS Assertion Thread Local Filter
/*
添加文件
在项目/src/main/resources/下添加cas-client.properties及casFilter.xml文件.
cas-client.properties
#线上cas服务器
#casServer=http://login.xxx.com
#测试cas服务器, 不验证263密码, 任何密码可登陆
casServer=[http://172.16.116.136:9091/cas](http://172.16.116.136:9091/cas/login)
#本应用的服务地址,需修改 serverName=http://172.16.103.226:9000
#设置不被不需要被拦截的地址,支持正则 ignoreAddress=/a.do|/*.html
casFilter.xml