# 前言
今天的笔记是介绍如何搭建一个简单的 CAS 服务认证中心。
相关链接
1. CAS 5.3 官网 | |
https://apereo.github.io/cas/5.3.x/index.html | |
2. CAS 5.3 开始指南 | |
https://apereo.github.io/cas/5.3.x/planning/Getting-Started.html | |
3. CAS 5.3 覆盖安装 | |
https://apereo.github.io/cas/5.3.x/installation/Maven-Overlay-Installation.html |
# 环境准备
选择 CAS 5.3 作为构建版本
- JDK 1.8
- Maven 3.5.3
- CAS 5.3
根据官方文档部署说明,推荐我们使用 WAR Overlay method 的方法,利用覆盖机制来组合 CAS 原始工件和本地自定义方法来达到自定义 CAS 的要求。官方给了两种编译方式,一种是 Maven 、另一种是 Gradle ,这里使用 Maven 安装部署。
项目 | 构建目录 | 源目录 |
---|---|---|
CAS Maven WAR Overlay | target/cas.war!WEB-INF/classes/ | src/main/resources |
CAS Gradle WAR Overlay | cas/build/libs/cas.war!WEB-INF/classes/ | src/main/resources |
建议使用 WAR Overlay 方法在本地构建和部署 CAS 。这种方法不需要采用者显式下载任何版本的 CAS,而是利用覆盖机制将 CAS 原始工件和本地定制结合起来,以进一步简化未来的升级和维护。
# 开始
要构建覆盖项目,您需要将构建目录中需要自定义的目录和文件复制到源目录。
注意:不要在上面提到的构建目录中进行更改。每次进行构建时,更改集都将被清除并设置回默认值。将覆盖的组件放在源目录或其他指示位置以避免意外。
# 搭建环境
1、访问 github 构建模板项目地址
2、构建模板项目选择 5.3 版本分支
3、下载该版本的 zip 压缩包
4、导入 IDE 编辑器并且初始化
初始目录名称 cas-overlay-template-5.3 修改为 platform-cas-server
5、创建项目 src、resource、test 等目录
6、拷贝依赖 ./overlays/org.apereo.cas.cas-server-webapp-tomcat-5.3.16/WEB-INF/classes 下的部分文件目录到项目中
目录清单
./resources
├── services
│ └── ...
├── static
│ └── ...
├── templates
│ └── ...
├── webflow
│ ├── login
│ │ └── login-webflow.xml
│ └── logout
│ └── logout-webflow.xml
├── apereo.properties
├── application.properties
├── application.yml
├── bootstrap.properties
├── cas-theme-default.properties
├── log4j2.xml
├── messages.properties...
├── truststore.jks
└── user-details.properties
7、修改 pom.xml 文件
CAS 依赖和其他相关依赖
完整 maven 依赖通过 pom.xml 获取。
<dependencies> | |
<dependency> | |
<groupId>org.apereo.cas</groupId> | |
<artifactId>cas-server-core</artifactId> | |
<version>${cas.version}</version> | |
<exclusions> | |
<exclusion> | |
<groupId>org.springframework.boot</groupId> | |
<artifactId>spring-boot-devtools</artifactId> | |
</exclusion> | |
<exclusion> | |
<groupId>org.apache.logging.log4j</groupId> | |
<artifactId>log4j-slf4j-impl</artifactId> | |
</exclusion> | |
</exclusions> | |
</dependency> | |
<!-- 省略... --> | |
</dependencies> |
# 执行启动
CAS 基础环境已经搭建完成,我们开始启动 CAS 。
1、Spring Boot 启动类
1.1、CAS Spring Boot 启动 banner 实现
org.apereo.cas.web.util 目录包下面新建 CasEmbeddedContainerUtils
public final class CasEmbeddedContainerUtils { | |
/** | |
* Property to dictate to the environment whether embedded container is running CAS. | |
*/ | |
public static final String EMBEDDED_CONTAINER_CONFIG_ACTIVE = "CasEmbeddedContainerConfigurationActive"; | |
private static final Logger LOGGER = LoggerFactory.getLogger(CasEmbeddedContainerUtils.class); | |
private CasEmbeddedContainerUtils() { | |
} | |
/** | |
* Gets runtime properties. | |
* | |
* @param embeddedContainerActive the embedded container active | |
* @return the runtime properties | |
*/ | |
public static Map<String, Object> getRuntimeProperties(final Boolean embeddedContainerActive) { | |
final Map<String, Object> properties = new LinkedHashMap<>(); | |
properties.put(EMBEDDED_CONTAINER_CONFIG_ACTIVE, embeddedContainerActive); | |
return properties; | |
} | |
/** | |
* Gets cas banner instance. | |
* | |
* @return the cas banner instance | |
*/ | |
public static Banner getCasBannerInstance() { | |
final String packageName = CasEmbeddedContainerUtils.class.getPackage().getName(); | |
final Reflections reflections = | |
new Reflections(new ConfigurationBuilder() | |
.filterInputsBy(new FilterBuilder().includePackage(packageName)) | |
.setUrls(ClasspathHelper.forPackage(packageName)) | |
.setScanners(new SubTypesScanner(true))); | |
final Set<Class<? extends AbstractCasBanner>> subTypes = reflections.getSubTypesOf(AbstractCasBanner.class); | |
subTypes.remove(DefaultCasBanner.class); | |
if (subTypes.isEmpty()) { | |
return new DefaultCasBanner(); | |
} | |
try { | |
final Class<? extends AbstractCasBanner> clz = subTypes.iterator().next(); | |
LOGGER.debug("Created banner [{}]", clz); | |
return clz.newInstance(); | |
} catch (final Exception e) { | |
LOGGER.error(e.getMessage(), e); | |
} | |
return new DefaultCasBanner(); | |
} | |
} |
1.2、Web 应用上下文
org.apereo.cas.web.web 目录下新建 CasWebApplicationContext
public class CasWebApplicationContext extends AnnotationConfigEmbeddedWebApplicationContext { | |
/** | |
* {@inheritDoc} | |
* Reset the value resolver on the inner {@link ScheduledAnnotationBeanPostProcessor} | |
* so that we can parse durations. This is due to how {@link org.springframework.scheduling.annotation.SchedulingConfiguration} | |
* creates the processor and does not provide a way for one to inject a value resolver. | |
*/ | |
@Override | |
protected void onRefresh() { | |
final ScheduledAnnotationBeanPostProcessor sch = (ScheduledAnnotationBeanPostProcessor) | |
getBeanFactory().getBean(TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME, BeanPostProcessor.class); | |
sch.setEmbeddedValueResolver(new CasEmbeddedValueResolver(this)); | |
super.onRefresh(); | |
} | |
@Override | |
public String toString() { | |
return getClass().getSimpleName(); | |
} | |
} |
1.3、Cas Web 应用程序入口方法
org.apereo.cas.web.web 目录下新建 CasWebApplication
/** | |
* This is {@link CasWebApplication}. | |
* | |
* @author Misagh Moayyed | |
* @since 5.0.0 | |
*/ | |
@EnableDiscoveryClient | |
@SpringBootApplication(exclude = { | |
HibernateJpaAutoConfiguration.class, | |
JerseyAutoConfiguration.class, | |
GroovyTemplateAutoConfiguration.class, | |
JmxAutoConfiguration.class, | |
DataSourceAutoConfiguration.class, | |
RedisAutoConfiguration.class, | |
MongoAutoConfiguration.class, | |
MongoDataAutoConfiguration.class, | |
CassandraAutoConfiguration.class, | |
DataSourceTransactionManagerAutoConfiguration.class, | |
// MetricsDropwizardAutoConfiguration.class, | |
RedisRepositoriesAutoConfiguration.class | |
}) | |
@EnableConfigurationProperties(CasConfigurationProperties.class) | |
@EnableAsync | |
@EnableTransactionManagement(proxyTargetClass = true) | |
@EnableScheduling | |
@NoArgsConstructor | |
@Slf4j | |
@ComponentScan(basePackages={"org.jasig.cas"}) | |
public class CasWebApplication { | |
/** | |
* Main entry point of the CAS web application. | |
* | |
* Cas Web 应用程序入口方法 | |
* @param args the args | |
*/ | |
public static void main(final String[] args) { | |
final Map<String, Object> properties = CasEmbeddedContainerUtils.getRuntimeProperties(Boolean.TRUE); | |
final Banner banner = CasEmbeddedContainerUtils.getCasBannerInstance(); | |
new SpringApplicationBuilder(CasWebApplication.class) | |
.banner(banner) | |
.web(true) | |
.properties(properties) | |
.logStartupInfo(true) | |
.contextClass(CasWebApplicationContext.class) | |
.run(args); | |
} | |
} |
2、8080 端口启动
修改配置文件 application.properties 中 cas 使用 8080 端口启动
# server.port=8443 | |
server.port=8080 |
注释 SSL 相关配置项
# server.ssl.key-store=file:/etc/cas/thekeystore | |
# server.ssl.key-store-password=changeit | |
# server.ssl.key-password=changeit |
直接运行 CasWebApplication 中的 main 方法进行启动
启动成功后可直接访问 http://localhost:8080/cas/login ,默认账号密码:casuser / Mellon
完成登录
这样我们就已经完成 CAS 基本服务搭建。
这里提示我们的登录不是安全的,由于没有使用 HTTPS 协议,下面我们开始配置 HTTPS 支持。
# 配置证书
开始配置 HTTPS 支持,制作证书。
# Windows 环境
Windows 环境下使用 JDK 自带的工具 keytool 生成证书
1、生成密钥库文件
管理员命令行切换进入 JDK bin 目录 C:\Program Files\Java\jdk1.8.0_121\bin 后执行以下命令
keytool -genkeypair -alias cas -keyalg RSA -keypass changeit -storepass changeit -keystore thekeystore -dname "CN=cas.example.org,OU=Example,OU=Org,C=AU" -ext SAN="dns:example.org,dns:localhost,ip:127.0.0.1" |
在当前目录生成密钥库文件 thekeystore
2、查看生成秘钥库的文件内容
输入密钥库口令: changeit
3、导出数字证书
继续执行以下命令根据密钥库文件导出证书
keytool -export -alias cas -file cas.cer -keystore thekeystore -validity 3650 |
输入先前的密钥库口令 changeit ,然后在当前目录下生成具体的 cas.cer 数字证书。
4、将数字证书导入到 JDK 中,其中证书密码为 changeit
keytool -import -alias cas -keystore "C:\Program Files\Java\jdk1.8.0_121\jre\lib\security\cacerts" -file cas.cer -trustcacerts -storepass changeit |
命令执行后输:是 信任证书
至此证书制作并且导入完成。
# Linux 环境
keytool 工具生成密钥文件
keytool -genkey -alias tomcat -keyalg RSA -keystore /etc/cas/thekeystore
输入口令
输入口令:changeit
查看生成秘钥库的文件内容
keytool -list -keystore /etc/cas/thekeystore
根据 keystore 生成 crt 文件
keytool -export -alias tomcat -file /etc/cas/tomcat.cer -keystore /etc/cas/thekeystore -validity 3650
将信任授权文件添加到 jdk 中
sudo keytool -import -keystore /usr/java/jdk1.8.0_121/jre/lib/security/cacerts -file /etc/cas/tomcat.cer -alias tomcat -storepass changeit
# 配置 DNS
# Windows 环境
CAS 服务端是部署在本地的,需要做一个本地映射,Windows 需要使用管理员进行修改。
C:\Windows\System32\drivers\etc\hosts
添加映射地址
127.0.0.1 cas.example.org
# Linux 环境
添加 cas.example.org 到 hosts 文件中
echo '127.0.0.1 cas.example.org' >> /etc/hosts |
# 配置 Tomcat
编辑 Tomcat 目录 conf 下的 server.xml 文件(如果部署 Tomcat 下的情况),我们使用 Spring Boot 部署则暂时不用。
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol" | |
maxThreads="150" SSLEnabled="true" scheme="https" secure="true" | |
clientAuth="false" sslProtocol="TLS" | |
keystoreFile="C:\Program Files\Java\jdk1.8.0_121\bin\thekeystore" | |
keystorePass="changeit" /> |
# 配置 SSL 启动项
1、配置 8443 端口启动
配置文件 application.properties 中 使用 8443 端口启动
server.port=8443 |
启用 SSL 相关配置项,注意 key-store 填写上文中具体生成路径
server.ssl.key-store=C:\\Program Files\\Java\\jdk1.8.0_121\\bin\\thekeystore | |
server.ssl.key-store-password=changeit | |
server.ssl.key-password=changeit |
或者将刚才上面生成的 thekeystore 复制到项目的 /etc/cas/ 目录下,那么使用如下配置
server.ssl.key-store=file:/etc/cas/thekeystore | |
server.ssl.key-store-password=changeit | |
server.ssl.key-password=changeit |
现在我们启动项目就可以直接使用 /etc/cas/ 下面的证书,除此之外,我们还可以将证书放在 ./resources 目录下面,每次打包就可以直接使用该证书。
server.ssl.key-store=classpath:thekeystore |
2、启动 CAS 运行
https://localhost:8443/cas/login
localhost 方法访问,此时已经没有 SSL 警告,可以查看证书状况。
# 配置认证方式
接着我们继续更改 CAS 的认证配置,在 application.properties 配置文件中找到 CAS 默认用户名和密码配置位置。
## | |
# CAS Authentication Credentials | |
# | |
cas.authn.accept.users=casuser::Mellon |
默认的认证方式为静态文件认证,现在我们更改为 JDBC 认证方式,同时添加相关数据库驱动。
<dependencies> | |
<!-- 新增支持 jdbc 验证 --> | |
<dependency> | |
<groupId>org.apereo.cas</groupId> | |
<artifactId>cas-server-support-jdbc</artifactId> | |
<version>${cas.version}</version> | |
</dependency> | |
<!-- 若不想找驱动可以直接写下面的依赖即可,其中包括 HSQLDB、Oracle、MYSQL、PostgreSQL、MariaDB、Microsoft SQL Server --> | |
<dependency> | |
<groupId>org.apereo.cas</groupId> | |
<artifactId>cas-server-support-jdbc-drivers</artifactId> | |
<version>${cas.version}</version> | |
</dependency> | |
</dependencies> |
如果指定使用 MySQL 数据库,这里不推荐这个用法,具体使用什么数据库引入具体的相关驱动即可,因为引入综合包的同时也引入了许多不必要的包。
<dependency> | |
<groupId>mysql</groupId> | |
<artifactId>mysql-connector-java</artifactId> | |
<version>8.0.11</version> | |
<scope>runtime</scope> | |
</dependency> |
我们继续更改 application.properties 配置文件,同时注释静态用户配置,具体更改如下:
## | |
# CAS Authentication Credentials | |
# 注释静态认证 | |
# cas.authn.accept.users=casuser::Mellon | |
# 查询账号密码 SQL,必须包含密码字段 | |
cas.authn.jdbc.query[0].sql=select * from user where username=? | |
# 指定上面的 SQL 查询字段名(必须) | |
cas.authn.jdbc.query[0].fieldPassword=password | |
# 指定过期字段,1 为过期,若过期不可用 | |
cas.authn.jdbc.query[0].fieldExpired=expired | |
# 为不可用字段段,1 为不可用,需要修改密码 | |
cas.authn.jdbc.query[0].fieldDisabled=disabled | |
# 数据库连接 | |
cas.authn.jdbc.query[0].url=jdbc:mysql://127.0.0.1:3306/cas?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false | |
# 数据库 dialect 配置 | |
cas.authn.jdbc.query[0].dialect=org.hibernate.dialect.MySQLDialect | |
# 数据库用户名 | |
cas.authn.jdbc.query[0].user=root | |
# 数据库用户密码 | |
cas.authn.jdbc.query[0].password=123 | |
# 数据库事务自动提交 | |
cas.authn.jdbc.query[0].autocommit=false | |
# 数据库驱动 | |
cas.authn.jdbc.query[0].driverClass=com.mysql.jdbc.Driver | |
# 超时配置 | |
cas.authn.jdbc.query[0].idleTimeout=5000 | |
# 默认加密策略,通过 encodingAlgorithm 来指定算法,默认 NONE 不加密 | |
cas.authn.jdbc.query[0].passwordEncoder.type=NONE | |
# cas.authn.jdbc.query[0].passwordEncoder.characterEncoding=UTF-8 | |
# cas.authn.jdbc.query[0].passwordEncoder.encodingAlgorithm=MD5 |
由于使用 JDBC 认证方式,测试需要准备一个 MySQL 数据库。本地新建了一个数据库 cas ,然后新建用户表 user ,添加 id、username、password、expired、disabled 字段,同时添加用户名和密码,并给 expired、disabled 字段赋值为 0。
CREATE DATABASE IF NOT EXISTS cas DEFAULT CHARACTER SET utf8; | |
CREATE TABLE `user` ( | |
`id` bigint(20) NOT NULL COMMENT '主键', | |
`username` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, | |
`password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, | |
`expired` tinyint(4) NULL DEFAULT NULL, | |
`disabled` tinyint(4) NULL DEFAULT NULL, | |
PRIMARY KEY (`id`) USING BTREE | |
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; | |
INSERT INTO `user` VALUES (1, 'pitt1997', '123456', 0, 0); | |
INSERT INTO `user` VALUES (2, 'valieva', '12345678', 0, 0); | |
SET FOREIGN_KEY_CHECKS = 1; |
数据库初始化完成后重启 CAS 再次登录。
到此,CAS 基础服务搭建就介绍完毕。