单点登录指,多个应用系统,统一在一个系统登录一次之后,在会话有效期内,可以访问任意一个系统而不需要重新登录。对应的有单点登出,在一处登出之后,用户在其他系统的会话都会下线。

几种实现的架构

架构1

公共的登录模块 + 会话中心这种方式不能算是单点登录,应该算是session共享。将登录和验证的逻辑放到一个公共模块(login)里面,在每个项目里面依赖这个(login)模块,每个项目验证或登录的时候都会使用同一个会话中心。
SSO - 图1

架构2

统一的认证中心,子项目验证会话的方式为将token传给认证中心,认证中心去会话中心查询是否存在会话,若存在表示会话有效。
SSO - 图2
xxl-sso大体就是这个思路

架构3

统一的认证中心,子项目验证会话的方式为将token传给认证中心,认证中心解密token,解密成功,表示会话有效。

CAS

CAS是耶鲁大学开源的一个企业级的单点登录框架,目前已由Apereo基金会管理。目前Github上面有三个仓库:
image.png

  • cas:单点登录认证中心的源码,一些默认页面等都可以在这里查看 https://github.com/apereo/cas
  • cas-overlay-template:服务端覆盖模版,用于定制与扩展cas服务端程序,官方建议使用此仓库来构建项目,用来创建一个自定义的认证中心。
  • cas-management-overlay:服务管理系统覆盖模版,用来管理客户端和用户,源码在这里:https://github.com/apereo/cas-management

官方文档:https://apereo.github.io/cas/6.3.x/
可以点击Version切换文档的版本
image.png

点击计划 -> 架构,打开架构页面,了解cas的架构:

点击计划 -> 开始,打开开始导向中,有一个发布 Cas 标题,建议我们使用 war 覆盖的方式发布 cas:
image.png
点击链接,打开 war 覆盖方式初始化的说明:
image.png
点击右侧大纲的Cas overlay template标题,定位到cas覆盖模版说明:
image.png
点击链接跳转到github的cas-overlay-template仓库地址,下载源码。

cas-overlay-template

6.x版本依赖jdk11,使用的是 gradle 构建工具。我这里使用 Idea 开发,如下截图,选择该项使用的 jdk 和 gradle 使用的 jdk 都是 11:
image.png
image.png

默认配置

从打包后的 app.war 中解压出来的 cas-server-webapp-resources-6.3.5.jar 中的配置:

  1. ##
  2. # 嵌入的 Web 容器的 SSL 配置
  3. #
  4. server.ssl.key-store=file:/etc/cas/thekeystore
  5. server.ssl.key-store-password=changeit
  6. server.ssl.key-password=changeit
  7. # 是否开启 https
  8. server.ssl.enabled=true
  9. ##
  10. # 嵌入的 Web 容器的配置
  11. #
  12. server.port=8443
  13. server.servlet.context-path=/cas
  14. server.max-http-header-size=2097152
  15. server.forward-headers-strategy=NATIVE
  16. server.error.include-stacktrace=ALWAYS
  17. server.compression.enabled=true
  18. server.compression.mime-types=application/javascript,application/json,application/xml,text/html,text/xml,text/plain
  19. ##
  20. # 嵌入 Tomcat 容器的配置
  21. #
  22. server.tomcat.max-http-form-post-size=2097152
  23. server.tomcat.basedir=build/tomcat
  24. server.tomcat.connection-timeout=PT20S
  25. server.tomcat.accesslog.enabled=true
  26. server.tomcat.accesslog.pattern=%t %a "%r" %s (%D ms)
  27. server.tomcat.accesslog.suffix=.log
  28. server.tomcat.background-processor-delay=0s
  29. server.tomcat.threads.min-spare=10
  30. server.tomcat.threads.max=200
  31. server.tomcat.remoteip.port-header=X-Forwarded-Port
  32. server.tomcat.remoteip.protocol-header=X-Forwarded-Proto
  33. server.tomcat.remoteip.protocol-header-https-value=https
  34. server.tomcat.remoteip.remote-ip-header=X-FORWARDED-FOR
  35. server.tomcat.uri-encoding=UTF-8
  36. server.tomcat.additional-tld-skip-patterns=*.jar
  37. ##
  38. # CAS Web Application JMX/Spring Configuration
  39. #
  40. spring.jmx.enabled=false
  41. ##
  42. # CAS Web Application Http Encoding Configuration
  43. #
  44. server.servlet.encoding.charset=UTF-8
  45. server.servlet.encoding.enabled=true
  46. server.servlet.encoding.force=true
  47. ##
  48. # Allow configuration classes to override bean definitions from Spring Boot
  49. #
  50. spring.main.allow-bean-definition-overriding=true
  51. spring.main.lazy-initialization=false
  52. ##
  53. # CAS Cloud Bus Configuration
  54. #
  55. spring.cloud.bus.enabled=false
  56. # Indicates that systemPropertiesOverride can be used. Set to false to prevent users from changing the default accidentally. Default true.
  57. spring.cloud.config.allow-override=true
  58. # External properties should override system properties.
  59. spring.cloud.config.override-system-properties=false
  60. # When allowOverride is true, external properties should take lowest priority, and not override any existing property sources (including local config files).
  61. spring.cloud.config.override-none=false
  62. # spring.cloud.bus.refresh.enabled=true
  63. # spring.cloud.bus.env.enabled=true
  64. # spring.cloud.bus.destination=CasCloudBus
  65. # spring.cloud.bus.ack.enabled=true
  66. ##
  67. # CAS Web Application Endpoints Security
  68. #
  69. management.endpoints.enabled-by-default=false
  70. management.endpoint.shutdown.enabled=false
  71. management.endpoint.restart.enabled=false
  72. management.endpoints.web.base-path=/actuator
  73. management.endpoints.web.exposure.include=info,health,status,configurationMetadata
  74. management.endpoints.jmx.exposure.exclude=*
  75. # management.endpoints.web.exposure.include=*
  76. # management.endpoints.web.path-mapping.health=status
  77. # management.endpoint.health.show-details=when_authorized
  78. management.server.add-application-context-header=false
  79. # Endpoint Security Basic Authentication
  80. spring.security.user.name=casuser
  81. # spring.security.user.password=
  82. # spring.security.user.roles=
  83. # Define a CAS-specific "WARN" status code and its order
  84. management.endpoint.health.status.order=WARN,DOWN,OUT_OF_SERVICE,UNKNOWN,UP
  85. # Define health indicator behavior (requires cas-server-core-monitor)
  86. management.health.memoryHealthIndicator.enabled=true
  87. # Define a default that doesn't require module /cas/actuator/health/ping serves as status
  88. management.health.ping.enabled=true
  89. # turn off health indicators by default
  90. management.health.defaults.enabled=false
  91. spring.cloud.discovery.client.composite-indicator.enabled=false
  92. ##
  93. # CAS Web Application Session Configuration
  94. #
  95. server.servlet.session.timeout=PT30S
  96. server.servlet.session.cookie.http-only=true
  97. server.servlet.session.tracking-modes=COOKIE
  98. ##
  99. # CAS Thymeleaf View Configuration
  100. #
  101. spring.thymeleaf.encoding=UTF-8
  102. spring.thymeleaf.cache=true
  103. spring.thymeleaf.mode=HTML
  104. spring.thymeleaf.template-resolver-order=100
  105. ##
  106. # CAS Log4j Configuration
  107. #
  108. # logging.config=file:/etc/cas/log4j2.xml
  109. server.servlet.context-parameters.isLog4jAutoInitializationDisabled=true
  110. ##
  111. # CAS Metrics Configuration
  112. #
  113. management.metrics.web.server.request.autotime.enabled=true
  114. management.metrics.export.atlas.enabled=false
  115. management.metrics.export.datadog.enabled=false
  116. management.metrics.export.ganglia.enabled=false
  117. management.metrics.export.graphite.enabled=false
  118. management.metrics.export.influx.enabled=false
  119. management.metrics.export.jmx.enabled=false
  120. management.metrics.export.newrelic.enabled=false
  121. management.metrics.export.prometheus.enabled=false
  122. management.metrics.export.signalfx.enabled=false
  123. management.metrics.export.statsd.enabled=false
  124. management.metrics.export.wavefront.enabled=false
  125. management.metrics.export.simple.enabled=true
  126. management.metrics.enable.logback=true
  127. management.metrics.enable.process.files=true
  128. management.metrics.enable.system.cpu=true
  129. management.metrics.enable.process.cpu=true
  130. management.metrics.enable.process.uptime=true
  131. management.metrics.enable.process.start.time=true
  132. ##
  133. # CAS Swagger Configuration
  134. #
  135. springdoc.show-actuator=true
  136. springdoc.model-and-view-allowed=true
  137. springdoc.writer-with-default-pretty-printer=true
  138. springdoc.swagger-ui.displayRequestDuration=true
  139. ##
  140. # CAS AspectJ Configuration
  141. #
  142. spring.aop.auto=true
  143. spring.aop.proxy-target-class=true
  144. ##
  145. # CAS View Settings
  146. #
  147. cas.view.cas2.v3ForwardCompatible=true
  148. ##
  149. # CAS Authentication Credentials
  150. #
  151. cas.authn.accept.enabled=true
  152. cas.authn.accept.users=casuser::Mellon
  153. cas.authn.accept.name=Static Credentials

6.3.x的更多配置文档:https://github.com/apereo/cas/blob/6.3.x/docs/cas-server-documentation/configuration/Configuration-Properties.md

启动

修改配置,禁用ssl,修改静态认证的用户名密码:

  1. cas:
  2. server:
  3. name: https://app.qingdao2world.com:8443
  4. prefix: ${cas.server.name}/cas
  5. authn:
  6. # 静态认证
  7. accept:
  8. # 添加用户名密码
  9. users: test::123456
  10. # 静态认证的处理器的名称
  11. name: Static Credentials
  12. server:
  13. port: 8443
  14. servlet:
  15. context-path: /cas
  16. ssl:
  17. # 关闭 https 协议
  18. enabled: false

将 log4j.xml 放到 resources 下面覆盖原始的日志文件,修改 log4j.xml 里面的日志路径:
image.png
运行 gradle 的 build 分组下的 run 脚本:
image.png
输入日志如下:

  1. ...
  2. 各种脚本的执行
  3. ...
  4. Started [/Users/beigege/Library/Java/JavaVirtualMachines/corretto-11.0.12/Contents/Home/bin/java, -DCVS_PASSFILE=~/.cvspass, -Dapple.laf.useScreenMenuBar=true, -Dawt.toolkit=sun.lwawt.macosx.LWCToolkit, -Dcom.apple.mrj.application.live-resize=false, -Dcom.jetbrains.suppressWindowRaise=false, -Dfile.separator=/, -DgopherProxySet=false, -Didea.active=true, -Didea.cycle.buffer.size=1024, -Didea.dynamic.classpath=false, -Didea.executable=idea, -Didea.fatal.error.notification=disabled, -Didea.home.path=/Applications/IntelliJ IDEA.app/Contents, -Didea.jre.check=true, -Didea.max.content.load.filesize=20000, -Didea.max.intellisense.filesize=2500, -Didea.no.launcher=false, -Didea.paths.selector=IntelliJIdea2020.3, -Didea.popup.weight=heavy, -Didea.smooth.progress=false, -Didea.vendor.name=JetBrains, -Didea.version=2020.3.1, -Didea.xdebug.key=-Xdebug, -Dio.netty.allocator.cacheTrimIntervalMillis=600000, -Dio.netty.allocator.numDirectArenas=1, -Dio.netty.allocator.numHeapArenas=1, -Dio.netty.allocator.useCacheForAllThreads=false, -Dio.netty.machineId=28:f0:76:ff:fe:16:65:0e, -Dio.netty.processId=9825, -Dio.netty.serviceThreadPrefix=Netty , -Djava.awt.graphicsenv=sun.awt.CGraphicsEnvironment, -Djava.awt.printerjob=sun.lwawt.macosx.CPrinterJob, -Djava.class.path=/Users/beigege/.gradle/wrapper/dists/gradle-7.1.1-all/1wqbeia0d49252rmlcr6o8lbl/gradle-7.1.1/lib/gradle-launcher-7.1.1.jar, -Djava.class.version=55.0, -Djava.endorsed.dirs, -Djava.home=/Users/beigege/Library/Java/JavaVirtualMachines/corretto-11.0.12/Contents/Home, -Djava.library.path=/Users/beigege/Library/Java/Extensions:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java:., -Djava.rmi.server.disableHttp=true, -Djava.rmi.server.hostname=127.0.0.1, -Djava.runtime.name=OpenJDK Runtime Environment, -Djava.runtime.version=11.0.12+7-LTS, -Djava.specification.name=Java Platform API Specification, -Djava.specification.vendor=Oracle Corporation, -Djava.specification.version=11, -Djava.util.concurrent.ForkJoinPool.common.threadFactory=com.intellij.concurrency.IdeaForkJoinWorkerThreadFactory, -Djava.vendor=Amazon.com Inc., -Djava.vendor.url=https://aws.amazon.com/corretto/, -Djava.vendor.url.bug=https://bugreport.java.com/bugreport/, -Djava.vendor.version=JBR-11.0.9.1.11-1145.63-jcef, -Djava.version=11.0.12, -Djava.version.date=2020-11-04, -Djava.vm.compressedOopsMode=Zero based, -Djava.vm.info=mixed mode, -Djava.vm.name=OpenJDK 64-Bit Server VM, -Djava.vm.specification.name=Java Virtual Machine Specification, -Djava.vm.specification.vendor=Oracle Corporation, -Djava.vm.specification.version=11, -Djava.vm.vendor=Amazon.com Inc., -Djava.vm.version=11.0.12+7-LTS, -Djavax.swing.rebaseCssSizeMap=true, -Djb.vmOptionsFile=/Users/beigege/Library/Application Support/JetBrains/IntelliJIdea2020.3/idea.vmoptions, -Djdk.attach.allowAttachSelf=true, -Djdk.debug=release, -Djdk.http.auth.tunneling.disabledSchemes="", -Djdk.module.illegalAccess.silent=true, -Djna.loaded=true, -Djna.nosys=true, -Djna.platform.library.path=/usr/lib:/usr/lib, -Djna.tmpdir=/Users/beigege/Library/Caches/JetBrains/IntelliJIdea2020.3/tmp, -Djnidispatch.path=/Users/beigege/Library/Caches/JetBrains/IntelliJIdea2020.3/tmp/jna7571730455114393065.tmp, -Dkotlin.daemon.jvm.options=--illegal-access=permit, -Dkotlinx.coroutines.debug=off, -Dlibrary.jansi.path=/Users/beigege/.gradle/native/jansi/null/osx, -Dline.separator=
  5. , -Dlog4j.defaultInitOverride=true, -Dorg.sqlite.tmpdir=/Users/beigege/Library/Caches/JetBrains/IntelliJIdea2020.3/tmp, -Dos.arch=x86_64, -Dos.name=Mac OS X, -Dos.version=11.5, -Dpath.separator=:, -Dpty4j.preferred.native.folder=/Applications/IntelliJ IDEA.app/Contents/lib/pty4j-native, -Dpty4j.tmpdir=/Users/beigege/Library/Caches/JetBrains/IntelliJIdea2020.3/tmp, -Dsun.arch.data.model=64, -Dsun.boot.library.path=/Users/beigege/Library/Java/JavaVirtualMachines/corretto-11.0.12/Contents/Home/lib, -Dsun.cpu.endian=little, -Dsun.cpu.isalist, -Dsun.io.unicode.encoding=UnicodeBig, -Dsun.java.command=org.gradle.launcher.daemon.bootstrap.GradleDaemon 7.1.1, -Dsun.java.launcher=SUN_STANDARD, -Dsun.jnu.encoding=UTF-8, -Dsun.management.compiler=HotSpot 64-Bit Tiered Compilers, -Dsun.os.patch.level=unknown, -Dswing.bufferPerWindow=true, -Duser.dir=/Users/beigege/IdeaProjects/2021/cas-overlay-template, -Duser.home=/Users/beigege, -Duser.name=beigege, -Duser.script=Hans, -Duser.timezone=Asia/Shanghai, -server, -noverify, -XX:+TieredCompilation, -XX:TieredStopAtLevel=1, -Xmx2048M, -Dfile.encoding=UTF-8, -Djava.io.tmpdir=/var/folders/fj/tr3p9j693f17kbzrrzl3v5x80000gn/T/, -Duser.country=CN, -Duser.language=zh, -Duser.variant, -jar, build/libs/app.war]
  6. Starting process 'command '/Users/beigege/Library/Java/JavaVirtualMachines/corretto-11.0.12/Contents/Home/bin/java''. Working directory: /Users/beigege/IdeaProjects/2021/cas-overlay-template Command: /Users/beigege/Library/Java/JavaVirtualMachines/corretto-11.0.12/Contents/Home/bin/java -DCVS_PASSFILE=~/.cvspass -Dapple.laf.useScreenMenuBar=true -Dawt.toolkit=sun.lwawt.macosx.LWCToolkit -Dcom.apple.mrj.application.live-resize=false -Dcom.jetbrains.suppressWindowRaise=false -Dfile.separator=/ -DgopherProxySet=false -Didea.active=true -Didea.cycle.buffer.size=1024 -Didea.dynamic.classpath=false -Didea.executable=idea -Didea.fatal.error.notification=disabled -Didea.home.path=/Applications/IntelliJ IDEA.app/Contents -Didea.jre.check=true -Didea.max.content.load.filesize=20000 -Didea.max.intellisense.filesize=2500 -Didea.no.launcher=false -Didea.paths.selector=IntelliJIdea2020.3 -Didea.popup.weight=heavy -Didea.smooth.progress=false -Didea.vendor.name=JetBrains -Didea.version=2020.3.1 -Didea.xdebug.key=-Xdebug -Dio.netty.allocator.cacheTrimIntervalMillis=600000 -Dio.netty.allocator.numDirectArenas=1 -Dio.netty.allocator.numHeapArenas=1 -Dio.netty.allocator.useCacheForAllThreads=false -Dio.netty.machineId=28:f0:76:ff:fe:16:65:0e -Dio.netty.processId=9825 -Dio.netty.serviceThreadPrefix=Netty -Djava.awt.graphicsenv=sun.awt.CGraphicsEnvironment -Djava.awt.printerjob=sun.lwawt.macosx.CPrinterJob -Djava.class.path=/Users/beigege/.gradle/wrapper/dists/gradle-7.1.1-all/1wqbeia0d49252rmlcr6o8lbl/gradle-7.1.1/lib/gradle-launcher-7.1.1.jar -Djava.class.version=55.0 -Djava.endorsed.dirs -Djava.home=/Users/beigege/Library/Java/JavaVirtualMachines/corretto-11.0.12/Contents/Home -Djava.library.path=/Users/beigege/Library/Java/Extensions:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java:. -Djava.rmi.server.disableHttp=true -Djava.rmi.server.hostname=127.0.0.1 -Djava.runtime.name=OpenJDK Runtime Environment -Djava.runtime.version=11.0.12+7-LTS -Djava.specification.name=Java Platform API Specification -Djava.specification.vendor=Oracle Corporation -Djava.specification.version=11 -Djava.util.concurrent.ForkJoinPool.common.threadFactory=com.intellij.concurrency.IdeaForkJoinWorkerThreadFactory -Djava.vendor=Amazon.com Inc. -Djava.vendor.url=https://aws.amazon.com/corretto/ -Djava.vendor.url.bug=https://bugreport.java.com/bugreport/ -Djava.vendor.version=JBR-11.0.9.1.11-1145.63-jcef -Djava.version=11.0.12 -Djava.version.date=2020-11-04 -Djava.vm.compressedOopsMode=Zero based -Djava.vm.info=mixed mode -Djava.vm.name=OpenJDK 64-Bit Server VM -Djava.vm.specification.name=Java Virtual Machine Specification -Djava.vm.specification.vendor=Oracle Corporation -Djava.vm.specification.version=11 -Djava.vm.vendor=Amazon.com Inc. -Djava.vm.version=11.0.12+7-LTS -Djavax.swing.rebaseCssSizeMap=true -Djb.vmOptionsFile=/Users/beigege/Library/Application Support/JetBrains/IntelliJIdea2020.3/idea.vmoptions -Djdk.attach.allowAttachSelf=true -Djdk.debug=release -Djdk.http.auth.tunneling.disabledSchemes="" -Djdk.module.illegalAccess.silent=true -Djna.loaded=true -Djna.nosys=true -Djna.platform.library.path=/usr/lib:/usr/lib -Djna.tmpdir=/Users/beigege/Library/Caches/JetBrains/IntelliJIdea2020.3/tmp -Djnidispatch.path=/Users/beigege/Library/Caches/JetBrains/IntelliJIdea2020.3/tmp/jna7571730455114393065.tmp -Dkotlin.daemon.jvm.options=--illegal-access=permit -Dkotlinx.coroutines.debug=off -Dlibrary.jansi.path=/Users/beigege/.gradle/native/jansi/null/osx -Dline.separator=
  7. -Dlog4j.defaultInitOverride=true -Dorg.sqlite.tmpdir=/Users/beigege/Library/Caches/JetBrains/IntelliJIdea2020.3/tmp -Dos.arch=x86_64 -Dos.name=Mac OS X -Dos.version=11.5 -Dpath.separator=: -Dpty4j.preferred.native.folder=/Applications/IntelliJ IDEA.app/Contents/lib/pty4j-native -Dpty4j.tmpdir=/Users/beigege/Library/Caches/JetBrains/IntelliJIdea2020.3/tmp -Dsun.arch.data.model=64 -Dsun.boot.library.path=/Users/beigege/Library/Java/JavaVirtualMachines/corretto-11.0.12/Contents/Home/lib -Dsun.cpu.endian=little -Dsun.cpu.isalist -Dsun.io.unicode.encoding=UnicodeBig -Dsun.java.command=org.gradle.launcher.daemon.bootstrap.GradleDaemon 7.1.1 -Dsun.java.launcher=SUN_STANDARD -Dsun.jnu.encoding=UTF-8 -Dsun.management.compiler=HotSpot 64-Bit Tiered Compilers -Dsun.os.patch.level=unknown -Dswing.bufferPerWindow=true -Duser.dir=/Users/beigege/IdeaProjects/2021/cas-overlay-template -Duser.home=/Users/beigege -Duser.name=beigege -Duser.script=Hans -Duser.timezone=Asia/Shanghai -server -noverify -XX:+TieredCompilation -XX:TieredStopAtLevel=1 -Xmx2048M -Dfile.encoding=UTF-8 -Djava.io.tmpdir=/var/folders/fj/tr3p9j693f17kbzrrzl3v5x80000gn/T/ -Duser.country=CN -Duser.language=zh -Duser.variant -jar build/libs/app.war
  8. Successfully started process 'command '/Users/beigege/Library/Java/JavaVirtualMachines/corretto-11.0.12/Contents/Home/bin/java''
  9. _ ____ _____ ____ _____ ___ ____ _ ____
  10. / \ | _ \| ____| _ \| ____/ _ \ / ___| / \ / ___|
  11. / _ \ | |_) | _| | |_) | _|| | | | | | / _ \ \___ \
  12. / ___ \| __/| |___| _ <| |__| |_| | | |___ / ___ \ ___) |
  13. /_/ \_\_| |_____|_| \_\_____\___/ \____/_/ \_\____/
  14. CAS Version: 6.3.5
  15. CAS Branch: 6.3.x
  16. CAS Commit Id: 771568662d4df0ba9825eb6bb1ae53b9cfff4d28
  17. CAS Build Date/Time: 2021-06-17T16:49:38Z
  18. Spring Boot Version: 2.3.7.RELEASE
  19. Spring Version: 5.2.12.RELEASE
  20. Java Home: /Users/beigege/Library/Java/JavaVirtualMachines/corretto-11.0.12/Contents/Home
  21. Java Vendor: Amazon.com Inc.
  22. Java Version: 11.0.12
  23. JVM Free Memory: 218 MB
  24. JVM Maximum Memory: 2 GB
  25. JVM Total Memory: 348 MB
  26. OS Architecture: x86_64
  27. OS Name: Mac OS X
  28. OS Version: 11.5
  29. OS Date/Time: 2021-07-28T23:55:25.956840
  30. OS Temp Directory: /var/folders/fj/tr3p9j693f17kbzrrzl3v5x80000gn/T/
  31. ------------------------------------------------------------
  32. Apache Tomcat Version: Apache Tomcat/9.0.48
  33. ------------------------------------------------------------
  34. 2021-07-28 23:55:25,989 INFO [org.apereo.cas.configuration.DefaultCasConfigurationPropertiesSourceLocator] - <Configuration directory [null] is not a directory or cannot be found at the specific path>
  35. 2021-07-28 23:55:25,998 INFO [org.apereo.cas.configuration.loader.YamlConfigurationPropertiesLoader] - <Found settings [[cas.server.name, cas.server.prefix, logging.config, server.port, server.servlet.context-path, server.ssl.enabled, server.ssl.key-password, server.ssl.key-store, server.ssl.key-store-password]] in YAML file [class path resource [application.yml]]>
  36. 2021-07-28 23:55:26,178 INFO [org.apereo.cas.web.CasWebApplication] - <The following profiles are active: standalone>
  37. 2021-07-28 23:55:29,112 INFO [org.apereo.cas.configuration.CasConfigurationPropertiesValidator] - <Validated CAS property sources and configuration successfully.>
  38. 2021-07-28 23:55:32,285 WARN [org.hibernate.validator.internal.properties.javabean.JavaBeanExecutable] - <HV000254: Missing parameter metadata for (int, MeterFilter, String, String), which declares implicit or synthetic parameters. Automatic resolution of generic type information for method parameters may yield incorrect results if multiple parameters have the same erasure. To solve this, compile your code with the '-parameters' flag.>
  39. 2021-07-28 23:55:35,048 WARN [org.apereo.cas.config.support.authentication.AcceptUsersAuthenticationEventExecutionPlanConfiguration] - <>
  40. 2021-07-28 23:55:35,048 WARN [org.apereo.cas.config.support.authentication.AcceptUsersAuthenticationEventExecutionPlanConfiguration] - <
  41. ____ _____ ___ ____ _
  42. / ___|_ _/ _ \| _ \| |
  43. \___ \ | || | | | |_) | |
  44. ___) || || |_| | __/|_|
  45. |____/ |_| \___/|_| (_)
  46. CAS is configured to accept a static list of credentials for authentication. While this is generally useful for demo purposes, it is STRONGLY recommended that you DISABLE this authentication method by setting 'cas.authn.accept.enabled=false' and switch to a mode that is more suitable for production.>
  47. 2021-07-28 23:55:35,048 WARN [org.apereo.cas.config.support.authentication.AcceptUsersAuthenticationEventExecutionPlanConfiguration] - <>
  48. 2021-07-28 23:55:36,265 INFO [org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration] - <
  49. Using generated security password: 6d0ea306-6cf7-4f91-bdc9-83ba678c4c73
  50. >
  51. 2021-07-28 23:55:36,389 INFO [org.springframework.security.web.DefaultSecurityFilterChain] - <Will secure Ant [pattern='/login/**'] with []>
  52. 2021-07-28 23:55:36,389 INFO [org.springframework.security.web.DefaultSecurityFilterChain] - <Will secure Ant [pattern='/logout/**'] with []>
  53. 2021-07-28 23:55:36,389 INFO [org.springframework.security.web.DefaultSecurityFilterChain] - <Will secure Ant [pattern='/validate/**'] with []>
  54. 2021-07-28 23:55:36,389 INFO [org.springframework.security.web.DefaultSecurityFilterChain] - <Will secure Ant [pattern='/serviceValidate/**'] with []>
  55. 2021-07-28 23:55:36,389 INFO [org.springframework.security.web.DefaultSecurityFilterChain] - <Will secure Ant [pattern='/p3/serviceValidate/**'] with []>
  56. 2021-07-28 23:55:36,389 INFO [org.springframework.security.web.DefaultSecurityFilterChain] - <Will secure Ant [pattern='/proxyValidate/**'] with []>
  57. 2021-07-28 23:55:36,389 INFO [org.springframework.security.web.DefaultSecurityFilterChain] - <Will secure Ant [pattern='/p3/proxyValidate/**'] with []>
  58. 2021-07-28 23:55:36,389 INFO [org.springframework.security.web.DefaultSecurityFilterChain] - <Will secure Ant [pattern='/proxy/**'] with []>
  59. 2021-07-28 23:55:36,435 INFO [org.springframework.security.web.access.channel.ChannelProcessingFilter] - <Validated configuration attributes>
  60. 2021-07-28 23:55:36,450 INFO [org.springframework.security.web.DefaultSecurityFilterChain] - <Will secure any request with [org.springframework.security.web.access.channel.ChannelProcessingFilter@e5c5e6, org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@77ea960f, org.springframework.security.web.context.SecurityContextPersistenceFilter@2c1a8529, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@4ac19bc6, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@436a563f, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@5f166f2e, org.springframework.security.web.session.SessionManagementFilter@638977e0, org.springframework.security.web.access.ExceptionTranslationFilter@73dbe25, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@528f5b7f]>
  61. 2021-07-28 23:55:37,328 WARN [org.apereo.cas.config.support.authentication.AcceptUsersAuthenticationEventExecutionPlanConfiguration] - <>
  62. 2021-07-28 23:55:37,328 WARN [org.apereo.cas.config.support.authentication.AcceptUsersAuthenticationEventExecutionPlanConfiguration] - <
  63. ____ _____ ___ ____ _
  64. / ___|_ _/ _ \| _ \| |
  65. \___ \ | || | | | |_) | |
  66. ___) || || |_| | __/|_|
  67. |____/ |_| \___/|_| (_)
  68. CAS is configured to accept a static list of credentials for authentication. While this is generally useful for demo purposes, it is STRONGLY recommended that you DISABLE this authentication method by setting 'cas.authn.accept.enabled=false' and switch to a mode that is more suitable for production.>
  69. 2021-07-28 23:55:37,328 WARN [org.apereo.cas.config.support.authentication.AcceptUsersAuthenticationEventExecutionPlanConfiguration] - <>
  70. 2021-07-28 23:55:37,395 WARN [org.apereo.cas.config.CasCoreServicesConfiguration] - <Runtime memory is used as the persistence storage for retrieving and persisting service definitions. Changes that are made to service definitions during runtime WILL be LOST when the CAS server is restarted. Ideally for production, you should choose a storage option (JSON, JDBC, MongoDb, etc) to track service definitions.>
  71. 2021-07-28 23:55:37,533 WARN [org.apereo.cas.config.CasCoreTicketsConfiguration] - <Runtime memory is used as the persistence storage for retrieving and managing tickets. Tickets that are issued during runtime will be LOST when the web server is restarted. This MAY impact SSO functionality.>
  72. 2021-07-28 23:55:37,535 INFO [org.apereo.cas.util.CoreTicketUtils] - <Ticket registry encryption/signing is turned off. This MAY NOT be safe in a clustered production environment. Consider using other choices to handle encryption, signing and verification of ticket registry tickets, and verify the chosen ticket registry does support this behavior.>
  73. 2021-07-28 23:55:37,750 WARN [org.apereo.cas.util.cipher.BaseStringCipherExecutor] - <Secret key for encryption is not defined for [Ticket-granting Cookie]; CAS will attempt to auto-generate the encryption key>
  74. 2021-07-28 23:55:37,776 WARN [org.apereo.cas.util.cipher.BaseStringCipherExecutor] - <Generated encryption key [vPm9C2_lj5AyRJpo-N9_Q2zrEzlBSko5V-Ye-dMNm7M] of size [256] for [Ticket-granting Cookie]. The generated key MUST be added to CAS settings under setting [cas.tgc.crypto.encryption.key].>
  75. 2021-07-28 23:55:37,777 WARN [org.apereo.cas.util.cipher.BaseStringCipherExecutor] - <Secret key for signing is not defined for [Ticket-granting Cookie]. CAS will attempt to auto-generate the signing key>
  76. 2021-07-28 23:55:37,777 WARN [org.apereo.cas.util.cipher.BaseStringCipherExecutor] - <Generated signing key [qN2BGFKoJcyRfRjRB3YzteZv0-1DVprkOuQpzfusgcGocxWhNJLoPCSBVYif2r90Wnf-ToR9CBN68Q716ZhupQ] of size [512] for [Ticket-granting Cookie]. The generated key MUST be added to CAS settings under setting [cas.tgc.crypto.signing.key].>
  77. 2021-07-28 23:55:37,906 WARN [org.apereo.cas.util.cipher.BaseBinaryCipherExecutor] - <Secret key for signing is not defined under [cas.webflow.crypto.signing.key]. CAS will attempt to auto-generate the signing key>
  78. 2021-07-28 23:55:37,906 WARN [org.apereo.cas.util.cipher.BaseBinaryCipherExecutor] - <Generated signing key [QB2In1LhWr1WrySkh3qwo8rMEZtIz3jda6H3pLnIQ2VO3HNlSfBaoku23vQyWaa71JrHod4z8SVcTP3eNB10bQ] of size [512]. The generated key MUST be added to CAS settings under setting [cas.webflow.crypto.signing.key].>
  79. 2021-07-28 23:55:37,906 WARN [org.apereo.cas.util.cipher.BaseBinaryCipherExecutor] - <Secret key for encryption is not defined under [cas.webflow.crypto.encryption.key]. CAS will attempt to auto-generate the encryption key>
  80. 2021-07-28 23:55:37,907 WARN [org.apereo.cas.util.cipher.BaseBinaryCipherExecutor] - <Generated encryption key [8ZXIXRQxf_uFmycTLFmbxg] of size [16]. The generated key MUST be added to CAS settings under setting [cas.webflow.crypto.encryption.key].>
  81. 2021-07-28 23:55:38,093 INFO [org.apereo.cas.web.CasWebApplication] - <Started CasWebApplication in 14.838 seconds (JVM running for 17.312)>
  82. 2021-07-28 23:55:38,098 INFO [org.apereo.cas.web.CasWebApplication] - <>
  83. 2021-07-28 23:55:38,098 INFO [org.apereo.cas.web.CasWebApplication] - <
  84. ____ _____ _ ______ __
  85. | _ \| ____| / \ | _ \ \ / /
  86. | |_) | _| / _ \ | | | \ V /
  87. | _ <| |___ / ___ \| |_| || |
  88. |_| \_\_____/_/ \_\____/ |_|
  89. >
  90. 2021-07-28 23:55:38,098 INFO [org.apereo.cas.web.CasWebApplication] - <>
  91. 2021-07-28 23:55:38,098 INFO [org.apereo.cas.web.CasWebApplication] - <Ready to process requests @ [2021-07-28T15:55:38.098Z]>
  92. 2021-07-28 23:55:38,111 INFO [org.apereo.cas.services.AbstractServicesManager] - <Loaded [0] service(s) from [InMemoryServiceRegistry].>

有一个stop输出,说是使用了静态的认证列表,生产环境需要关闭,他的默认用户名:

  1. ##
  2. # CAS Authentication Credentials
  3. #
  4. cas.authn.accept.enabled=true
  5. cas.authn.accept.users=casuser::Mellon
  6. cas.authn.accept.name=Static Credentials

输入访问地址查看:http://localhost:8443/cas,用我们修改后的用户名test密码123456登录
image.png
登录界面如下:
image.png
没有什么东西。

数据库认证

添加依赖:
image.png
在 build.gradle 中添加依赖,点击刷新依赖,会看到项目的依赖列表中会出现 jdbc 相关的的依赖。
image.png
修改配置,密码

  1. cas:
  2. server:
  3. name: https://app.qingdao2world.com:8443
  4. prefix: ${cas.server.name}/cas
  5. authn:
  6. accept:
  7. # 禁用静态认证
  8. enabled: false
  9. users: test::test
  10. name: Static Credentials
  11. ### JDBC用户认证
  12. jdbc:
  13. query[0]:
  14. user: root
  15. password: bgg@1234
  16. driver-class: com.mysql.cj.jdbc.Driver
  17. url: jdbc:mysql://127.0.0.1:3306/platform_cas?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false
  18. # 数据库方言,mysql8
  19. dialect: org.hibernate.dialect.MySQL8Dialect
  20. # 认证器的名称
  21. name: jdbcAuthenticationHandler
  22. # 认证器的顺序
  23. order: 0
  24. sql: SELECT * FROM cas_user WHERE username=?
  25. # 数据库密码字段
  26. field-password: password
  27. field-expired:
  28. field-disabled:
  29. # 作为用户属性的字段
  30. principal-attribute-list: realname,nickname,phone,email
  31. ## 转换
  32. principal-transformation:
  33. # 用户名转小写
  34. case-conversion: LOWERCASE
  35. ## 密码加密规则
  36. password-encoder:
  37. characterEncoding: UTF-8
  38. # 加密方式,可以先设置为 NONE,不加密进行测试,即数据库存储明文密码
  39. type: BCRYPT
  40. strength: 7

重启后登录效果和静态认证是相同的,不同的数据库方言可以在官方文档中看到:https://apereo.github.io/cas/6.3.x/installation/JDBC-Drivers.html

服务注册

每一个客户端都看作是一个服务,客户端要使用认证中心登录,就需要将自己注册到认证中心,开发阶段可以使用 json 配置文件方式注册服务。

客户端

新建一个客户端程序,这里官方写的 springboot + security 的 demo,关键依赖

  1. <!-- springboot security + cas start -->
  2. <dependency>
  3. <groupId>org.springframework.boot</groupId>
  4. <artifactId>spring-boot-starter-security</artifactId>
  5. </dependency>
  6. <dependency>
  7. <groupId>org.springframework.security</groupId>
  8. <artifactId>spring-security-cas</artifactId>
  9. <scope>runtime</scope>
  10. </dependency>
  11. <dependency>
  12. <groupId>org.jasig.cas.client</groupId>
  13. <artifactId>cas-client-support-springboot</artifactId>
  14. <version>3.6.2</version>
  15. </dependency>
  16. <dependency>
  17. <groupId>org.projectlombok</groupId>
  18. <artifactId>lombok</artifactId>
  19. <version>1.18.20</version>
  20. </dependency>
  21. <!-- springboot security + cas end -->

配置:

  1. # 应用名称
  2. spring.application.name=cas-client-demo
  3. # 应用服务 WEB 访问端口
  4. server.port=8080
  5. # 认证中心服务地址
  6. cas.server-url-prefix=http://127.0.0.1:8443/cas
  7. # 认证中心登录地址
  8. cas.server-login-url=${cas.server-url-prefix}/login
  9. # 是否接收认证中心的单点登出
  10. cas.single-logout.enabled=true
  11. # 客户端地址
  12. cas.client-host-url=http://127.0.0.1:8080
  13. # 自定义的spring security登出后的跳转地址,到认证中心的退出
  14. cas-logout-url=http://127.0.0.1:8443/cas/logout?service=http://127.0.0.1:8080
  15. # 用户权限名称,用户登录后回调 security 的 loadUserDetails,从认证中心返回的 Principal 中获取 attribute-authorities 的值作为权限
  16. # var 权限 = assertion.getPrincipal().getAttributes().get(attribute) attribute in attribute-authorities
  17. cas.attribute-authorities=memberships
  18. cas.use-session=true
  19. spring.freemarker.suffix=.ftl
  20. server.session.cookie.http-only: true
  21. server.session.tracking-modes: COOKIE
  22. spring.mvc.view.prefix:/WEB-INF/jsp/
  23. spring.mvc.view.suffix:.jsp
  24. logging.level.org.springframework.security: DEBUG
  25. logging.level.org.jasig.cas: DEBUG
  26. ## The format used for the keystore. It could be set to JKS in case it is a JKS file
  27. #server.ssl.key-store-type=JKS
  28. ## The path to the keystore containing the certificate
  29. #server.ssl.key-store=classpath:keystore
  30. ## The password used to generate the certificate
  31. #server.ssl.key-store-password=password
  32. ## The alias mapped to the certificate
  33. #server.ssl.key-alias=tomcat
  34. #server.error.whitelabel.enabled=false
  35. #server.ssl.enabled=true

启动客户端程序和认证中心访问客户端程序:
image.png

服务端

修改认证中心的服务注册,先用 json 方式,在 resources 下新建 services 目录,在目录中新建一个符合客户端规则的服务配置:
image.png
开启 json 初始化服务:

  1. cas:
  2. ### 服务注册(客户端注册)
  3. service-registry:
  4. ## json 文件方式注册服务
  5. init-from-json: true

重启访问客户端,服务会被 EmbeddedResourceBasedServiceRegistry 加载,当前没有加 cas-server-support-json-service-registry 注册依赖,所以应该不是 json 方式存储服务:
image.png

JPA

将服务存储到关系型数据库,添加依赖:
image.png
修改配置,关闭 json 初始化,添加 jpa:

  1. cas:
  2. jdbc:
  3. # 输出 sql
  4. show-sql: true
  5. # gen-ddl: true
  6. # case-insensitive: false
  7. ### 服务注册(客户端注册)
  8. service-registry:
  9. ## json 文件初始化服务,会把初始化的服务存储到 mysql 数据库
  10. core:
  11. init-from-json: true
  12. ## JPA 方式(Mysql)
  13. jpa:
  14. user: root
  15. password: bgg@1234
  16. driver-class: com.mysql.cj.jdbc.Driver
  17. url: jdbc:mysql://127.0.0.1:3306/platform_cas?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false
  18. dialect: org.hibernate.dialect.MySQL8Dialect
  19. # 服务注册表不存在就创建,有则更新字段。
  20. ddl-auto: update

重新启动认证中心程序,第一次会创建几张表:
6.4.x之前版本
image.png
6.4.x版本开始只有两张表
image.png
加载0个服务
image.png
关于四张表:
native表

  1. CREATE TABLE `native` (
  2. `next_val` bigint DEFAULT NULL COMMENT '记录下一个服务ID'
  3. ) COMMENT = 'Cas服务ID序列表';

Regex_Registered_Service表

  1. CREATE TABLE `Regex_Registered_Service` (
  2. `expression_type` varchar(50) NOT NULL DEFAULT 'regex' COMMENT '表达式类型',
  3. `id` bigint NOT NULL COMMENT '服务ID,主键',
  4. `acceptable_usage_policy` longblob,
  5. `access_strategy` longblob,
  6. `attribute_release` longblob,
  7. `authn_policy` longblob,
  8. `description` varchar(255) DEFAULT NULL COMMENT '服务描述(客户端应用描述),显示在登录页面',
  9. `environments` longblob,
  10. `evaluation_order` int NOT NULL COMMENT '服务匹配的优先级,用于两个服务表达式匹配到相同url的情况',
  11. `expiration_policy` longblob,
  12. `information_Url` varchar(255) DEFAULT NULL COMMENT '服务信息地址',
  13. `logo` varchar(255) DEFAULT NULL COMMENT '服务的logo,显示在登录页面',
  14. `logout_type` int DEFAULT NULL COMMENT '退出后如何处理当前客户端:0-不处理,1-向客户端发送退出请求,2-向客户端发送JSONP请求',
  15. `logout_url` varchar(255) DEFAULT NULL COMMENT '客户端接收退出请求的地址',
  16. `matching_strategy` longblob,
  17. `mfa_policy` longblob,
  18. `name` varchar(255) NOT NULL COMMENT '服务名称(客户端应用名称),显示在登录页面',
  19. `privacy_Url` varchar(255) DEFAULT NULL COMMENT '服务隐私政策地址,应用的隐私政策地址,显示在登录页面',
  20. `proxy_granting_ticket_expiration_policy` longblob,
  21. `proxy_policy` longblob COMMENT '代理策略,服务是否可以代理认证登录',
  22. `proxy_ticket_expiration_policy` longblob,
  23. `public_key` longblob COMMENT '与此服务关联的公钥,用于通过加密 CAS 验证协议响应中的某些元素和属性(例如PGT或凭据)来授权请求',
  24. `redirect_url` varchar(255) DEFAULT NULL COMMENT '身份认证默认跳转地址',
  25. `response_Type` varchar(255) DEFAULT NULL COMMENT 'Cas响应客户端的类型',
  26. `service_Id` varchar(255) NOT NULL COMMENT '服务(客户端)url的匹配规则',
  27. `service_ticket_expiration_policy` longblob,
  28. `sso_participation_policy` longblob,
  29. `theme` varchar(255) DEFAULT NULL COMMENT '服务在登录页面显示的样式主题',
  30. `ticket_granting_ticket_expiration_policy` longblob,
  31. `username_attr` longblob,
  32. PRIMARY KEY (`id`)
  33. ) COMMENT='Cas服务注册表';

Regex_Registered_Service_Regex_Registered_Service_Property 表

  1. CREATE TABLE `Regex_Registered_Service_Regex_Registered_Service_Property` (
  2. `Abstract_Registered_Service_id` bigint NOT NULL,
  3. `property_values` longblob,
  4. `Regex_Registered_Service_Property_name` varchar(255) NOT NULL,
  5. PRIMARY KEY (`Abstract_Registered_Service_id`,`Regex_Registered_Service_Property_name`),
  6. CONSTRAINT `FKn94p2l49u0pwrf7djnt9fmn9b` FOREIGN KEY (`Abstract_Registered_Service_id`) REFERENCES `Regex_Registered_Service` (`id`)
  7. ) comment='服务注册属性';

Regex_Registered_Service_Registered_Service_Impl_Contact 表

  1. CREATE TABLE `Regex_Registered_Service_Registered_Service_Impl_Contact` (
  2. `Abstract_Registered_Service_id` bigint NOT NULL,
  3. `department` varchar(255) DEFAULT NULL,
  4. `email` varchar(255) DEFAULT NULL,
  5. `name` varchar(255) NOT NULL,
  6. `phone` varchar(255) DEFAULT NULL,
  7. `contacts_ORDER` int NOT NULL,
  8. PRIMARY KEY (`Abstract_Registered_Service_id`,`contacts_ORDER`),
  9. CONSTRAINT `FK7pmuqhejyaxpxptr5hpqd7pxc` FOREIGN KEY (`Abstract_Registered_Service_id`) REFERENCES `Regex_Registered_Service` (`id`)
  10. ) comment = '已注册服务的联系人';

service_sequence 表

  1. CREATE TABLE `service_sequence` (
  2. `next_val` bigint DEFAULT NULL
  3. ) comment = '服务序列表';

Registered_Services 表

  1. CREATE TABLE `Registered_Services` (
  2. `id` bigint NOT NULL,
  3. `body` varchar(8000) NOT NULL COMMENT '服务配置信息',
  4. `evaluation_Order` int NOT NULL,
  5. `evaluation_Priority` int NOT NULL,
  6. `name` varchar(255) NOT NULL COMMENT '服务名称',
  7. `service_Id` varchar(255) NOT NULL COMMENT '服务url的匹配规则',
  8. PRIMARY KEY (`id`)
  9. ) comment = '服务注册表';

打开 cas-managment-overlay 程序

修改页面

我们可以根据源码中的页面所在路径和名称,在我们覆盖模版中的相应位置重写,会自动替换源码中的页面,这里不同的版本,源码的页面路径不同,页面资源文件在不同版本的位置如下(5.x之前的未查看):

版本 静态资源位置
5.0.x cas-server-webapp
5.1.x webapp
6.1.x cas-server-webapp-resources
6.2.x cas-server-support-thymeleaf

配置本地的证书

因为 cas 的会话票据是在网络中传输授权的,为了增加票据的安全性,他建议我们使用 https 协议,就需要我们生成一份 https 协议的证书,在 build.gradle 中有生成证书的脚本 createKeystore,使用了 gradle.properties 的变量:

  1. # Settings to generate keystore
  2. # used by the build to assist with creating
  3. # self-signed certificates for https endpoints
  4. certDir=/Users/beigege/IdeaProjects/2021/cas-overlay-template/etc/cas
  5. serverKeystore=cas.keystore
  6. exportedServerCert=cas.crt
  7. storeType=PKCS12

cas-management-overlay

需要启用 ssl 才能正常运行。需要安装证书到jdk中,证书的dns需要包含当前项目中配置的认证中心地址的域名或ip。-ext

-dname CN 姓名,一般填写域名
OU 单位,填企业
O 组织,填部门
C 国家
-ext SAN 证书信任的域名或ip
  1. keytool -genkeypair -alias cas -keyalg RSA -keypass changeit -storepass changeit -keystore ~/certs/keystore -dname CN=cas.qingdao2world.com,OU=青岛西海岸保税物流中心,O=IT部,C=CN -ext SAN=dns:cas.qingdao2world.com,dns:localhost,ip:127.0.0.1

6.3.x版本架构为:springboot+angular
在 cas-mgmt-core 中的 ForwardingController 中,将页面请求拦截全部重定向到 cas-mgmt-webapp-workspace 中的 management/src 目录中的 index.html
查看 angular 的路由我不会好像都在目录下的 *-routing.module.ts