CAS6.3 SSO单点服务搭建

一、环境准备

这里使用的是CAS Server 6.3版本,环境要求:

  • jdk11:6.x需要jdk11, 而5.x系列使用的jdk8
  • gradle:7.0以上,cas自从5.3以后就改成gradle构建了
  • tomcat:9.0以上

github下载CAS服务模板,解压该包重命名为cas-server

CAS官网

二、配置gradle

1、下载gradle并解压

2、在环境变量中增加GRADLE_HOME变量,并指向gradle解压目录。

3、增加GRADLE_USER_HOME环境变量,随便给一个保存jar包的地址,如:D:\gradle-repository

4、在Path环境变量中增加bin目录指向,如:%GRADLE_HOME%\bin

5、gradle支持阿里云:在gradle解压目录的init.d目录下新建一个名称为init.gradle的文件,内容如下

allprojects{
 repositories {
 def ALIYUN_REPOSITORY_URL = 'http://maven.aliyun.com/nexus/content/groups/public'
 def ALIYUN_JCENTER_URL = 'http://maven.aliyun.com/nexus/content/repositories/jcenter'
 all { ArtifactRepository repo ->
 if(repo instanceof MavenArtifactRepository){
 def url = repo.url.toString()
 if (url.startsWith('https://repo1.maven.org/maven2')) {
 project.logger.lifecycle "Repository ${repo.url} replaced by $ALIYUN_REPOSITORY_URL."
 remove repo
 }
 if (url.startsWith('https://jcenter.bintray.com/')) {
 project.logger.lifecycle "Repository ${repo.url} replaced by $ALIYUN_JCENTER_URL."
 remove repo
 }
 }
 }
 maven {
 url ALIYUN_REPOSITORY_URL
 url ALIYUN_JCENTER_URL
 }
 }
}

用idea 打开项目, 设置gradle jvm使用的jvm

gradle设置.png

修改build.gradle文件, 添加aliyun依赖地址

repositories {
 if (project.privateRepoUrl) {
 maven {
 url project.privateRepoUrl
 credentials {
 username = project.privateRepoUsername
 password = System.env.PRIVATE_REPO_TOKEN
 }
 }
 }
 mavenLocal()
//    mavenCentral()

 maven { url 'https://maven.aliyun.com/nexus/content/repositories/google' }
 maven { url 'https://maven.aliyun.com/nexus/content/groups/public/' }
 maven { url 'https://maven.aliyun.com/nexus/content/repositories/jcenter'}

 maven { url 'https://oss.sonatype.org/content/repositories/releases' }
 maven {
 url 'https://oss.sonatype.org/content/repositories/snapshots'
 mavenContent { snapshotsOnly() }
 }
 maven { url 'https://build.shibboleth.net/nexus/content/repositories/releases/' }
 maven {
 url "https://repo.spring.io/milestone"
 mavenContent { releasesOnly() }
 }
}

三、构建cas项目

仔细阅读README.md文件, 大多数操作官方都给了提示

gradlew文件是gradle构建项目的入口, 可以通过如下命令了解gradlew的用法

./gradlew help
./gradlew tasks

如果IDEA正常设置,默认会自动进行开始预加载jar包,这个过程要慢一些。我们可以手动进行,执行如下命令

./gradlew.bat clean build

执行完成后,对其进行解压war包,执行如下命令

./gradlew.bat explodeWar

在build中会生成cas-resources目录,将其复制到src/main目录下并命名为resources

CAS默认使用https服务, 需要配置https证书,我们也可以启用http,修改/src/main/resoucres/services/HTTPSandIMAPS-10000001.json文件

{
 "@class": "org.apereo.cas.services.RegexRegisteredService",
 "serviceId": "^(https|http|imaps)://.*",
 "name": "HTTPS and IMAPS",
 "id": 10000001,
 "description": "This service definition authorizes all application urls that support HTTPS and IMAPS protocols.",
 "evaluationOrder": 10000
}

将"serviceId": "^(https|http|imaps)://.*",中增加了http,这样就可以了。

重新编译生成新的war包

./gradlew.bat build

通过tomcat启动项目, 其中Deployment配置项选择war包。

cas启动成功页面.png

显示该页面表示已正常启动可访问,我们可以使用src/main/resources/application.properties配置文件最底部配置的

cas.authn.accept.users=casuser::Mellon

casuser::Mellon账号进行测试。casuser是账号, Mellon是密码

四、使用数据库账号数据验证

打开build.gradle文件, 在其中进行添加jdbc包的引用和相应数据库的包引用。

// 寻找文件中该部分位置,在其内部最下方增加下面最后3行
dependencies {
 ...
 // CAS dependencies/modules may be listed here statically...
 implementation "org.apereo.cas:cas-server-core-api-configuration-model"
 implementation "org.apereo.cas:cas-server-webapp-init"

 // 数据库连接所需依赖
 implementation 'org.apereo.cas:cas-server-support-jdbc:6.3.7.2'
 implementation 'mysql:mysql-connector-java:8.0.30'
}

在yml配置文件添加数据库配置, 其中query[0]配置的是固定加密算法, encode[0]配置的是盐加密算法, 可以并存

cas:
 view:
 cas2:
 v3ForwardCompatible: true
 authn:
#    accept:
#      enabled: false
#      users: casuser::Mellon
#      name: Static Credentials
 jdbc:
 query[0]:
 url: jdbc:mysql://localhost:3306/crm_single?characterEncoding=utf8&useSSL=false&zeroDateTimeBehavior=convertToNull&tinyInt1isBit=false&serverTimezone=Asia/Shanghai&useAffectedRows=true
 user: root
 password: 12345678
 sql: SELECT password FROM admin_user WHERE username=?
 field-password: password
 driver-class: com.mysql.cj.jdbc.Driver
 dialect: org.hibernate.dialect.MySQLDialect
 password-encoder:
# 加密类型为NONE|DEFAULT|STANDARD|BCRYPT|SCRYPT|PBKDF2这几种, 或指定java类型 org.apereo.cas.config.MyPasswordEncoder
 type: BCRYPT
#          character-encoding: UTF-8
#      加密算法可从中选: org.apache.commons.codec.digest.DigestUtils, 如:MD5
#          encoding-algorithm: MD5
#          strength: 32
#  cas推荐的加盐算法
 encode[0]:
 url: jdbc:mysql://localhost:3306/crm_single?characterEncoding=utf8&useSSL=false&zeroDateTimeBehavior=convertToNull&tinyInt1isBit=false&serverTimezone=Asia/Shanghai&useAffectedRows=true
 user: root
 password: 12345678
 driver-class: com.mysql.cj.jdbc.Driver
 dialect: org.hibernate.dialect.MySQLDialect
 sql: SELECT password,salt FROM admin_user WHERE username=?
 # 密码字段
 password-field-name: password
 # 哈希次数
 number-of-iterations: 2
 # 固定静态盐, 使用静态盐加密配置此项
 static-salt: .
 # 盐值字段, 使用动态盐加密才需要配置此项
 salt-field-name: salt
 algorithm-name: MD5
 # 过期字段
 expired-field-name: expired
 # 禁用字段
 disabled-field-name: disabled
 tgc:
 secure: false

cas推荐的盐加密算法, java实现如下

import cn.hutool.core.util.IdUtil;
import cn.hutool.crypto.SecureUtil;
import com.google.common.collect.Lists;
import org.apache.shiro.crypto.hash.ConfigurableHashService;
import org.apache.shiro.crypto.hash.DefaultHashService;
import org.apache.shiro.crypto.hash.HashRequest;
import org.apache.shiro.util.ByteSource;
import org.junit.Test;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

import java.util.List;


public class PasswordSaltTest {
 private String staticSalt = ".";
 private String algorithmName = "MD5";
 private String encodedPassword = "123456";
//    private static String dynamicSalt = "d3aff9f360a54e0a8f7ab40c24af4e1e";


 @Test
 public void dynamicSalt() throws Exception {

 String dynamicSalt = IdUtil.simpleUUID();
//        String dynamicSalt = "0a9c11b7942148eeac743a114d757ed8";
 System.out.println("dynamicSalt = " + dynamicSalt);

 ConfigurableHashService hashService = new DefaultHashService();
 hashService.setPrivateSalt(ByteSource.Util.bytes(this.staticSalt));
 hashService.setHashAlgorithmName(this.algorithmName);
 hashService.setHashIterations(2);
 HashRequest request = new HashRequest.Builder()
 .setSalt(dynamicSalt)
 .setSource(encodedPassword)
 .build();
 String res =  hashService.computeHash(request).toHex();
 System.out.println("res = " + res);
 }
}

五、 服务注册管理

简介

cas客户端接入称之为service,必须经过cas的允许才能进行登录,当然不同的客户端可以做不同的事情,其中包括:

  • 自定义主题(各客户端登录页自定义)
  • 自定义属性(服务属性(固定)与用户属性(动态))
  • 自定义协议
  • 自定义登录后跳转方式,跳转路径
  • 授权策略(拒绝属性、可登录时间范围限制、等等)
  • 拒绝授权模式

持久化策略

  • InMemory XML(通过spring bean进行内存存储)
  • JSON(通过json文件存储) 推荐 ❤❤❤
  • YAML(通过yml文件存储)
  • Mongo(文档数据库持久化)推荐 ❤❤❤❤❤
  • JPA(关系型数据库持久化)
  • DynameDb
  • LDAP
  • Cochbase

在sso初步上线时推荐采用json文件存储,后面逐步多服务注入时推荐采用Mongo进行存储,采用cas-management进行采用UI进行管理我们的数据,目前阶段,持久化策略必须和cas进行配置一致才能生效

JSON 配置示例

需求:对所有http://localhost开头请求的service进行允许认证

resources/services下新建文件Localhost-10000002.json

{
 "@class": "org.apereo.cas.services.RegexRegisteredService",
 "serviceId": "^(http)://localhost.*",
 "name": "本地服务",
 "id": 10000002,
 "description": "这是一个本地允许的服务,通过localhost访问都允许通过",
 "evaluationOrder": 1
}

注意:json文件名字规则为${name}-${id}.json, id必须为json文件内容id一致

json文件解释:

  1. @class:必须为org.apereo.cas.services.RegisteredService的实现类,对其他属性进行一个json反射对象,常用的有RegexRegisteredService,匹配策略为id的正则表达式
  2. serviceId:唯一的服务id
  3. name: 服务名称,会显示在默认登录页
  4. id:全局唯一标志
  5. description:服务描述,会显示在默认登录页
  6. evaluationOrder: 匹配争取时的执行循序

除了以上说的还有很多配置策略以及节点,具体看官方文档, 配置不同的RegisteredService也会有稍微不一样

打开build.gradle文件, 添加需要的依赖

// 寻找文件中该部分位置,在其内部最下方增加下面最后3行
dependencies {
 ...
 // 服务注册所需依赖
 implementation "org.apereo.cas:cas-server-support-json-service-registry"
 implementation "org.apereo.cas:cas-server-support-jpa-service-registry"
}

在yml文件添加如下配置

cas:
 # Service Registry(服务注册)
 service-registry:
 # 开启识别Json文件,默认false
 init-from-json: true
 #自动扫描服务配置,默认开启
 watcher-enabled: true
 schedule:
 # 默认2分钟扫描一遍
 repeat-interval: PT2M
 # 默认延迟15秒开启
 start-delay: PT15S
 json:
 location: classpath:/services
 # jpa方式
 jpa:
 url: jdbc:mysql://localhost:3306/sso?characterEncoding=utf8&useSSL=false&zeroDateTimeBehavior=convertToNull&tinyInt1isBit=false&serverTimezone=Asia/Shanghai&useAffectedRows=true
 user: root
 password: 12345678
 driver-class: com.mysql.cj.jdbc.Driver
 dialect: org.hibernate.dialect.MySQL5Dialect
 ddl-auto: update
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,591评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,448评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,823评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,204评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,228评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,190评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,078评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,923评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,334评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,550评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,727评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,428评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,022评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,672评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,826评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,734评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,619评论 2 354

推荐阅读更多精彩内容