单点登录指,多个应用系统,统一在一个系统登录一次之后,在会话有效期内,可以访问任意一个系统而不需要重新登录。对应的有单点登出,在一处登出之后,用户在其他系统的会话都会下线。
几种实现的架构
架构1
公共的登录模块 + 会话中心这种方式不能算是单点登录,应该算是session共享。将登录和验证的逻辑放到一个公共模块(login)里面,在每个项目里面依赖这个(login)模块,每个项目验证或登录的时候都会使用同一个会话中心。
架构2
统一的认证中心,子项目验证会话的方式为将token传给认证中心,认证中心去会话中心查询是否存在会话,若存在表示会话有效。
xxl-sso大体就是这个思路
架构3
统一的认证中心,子项目验证会话的方式为将token传给认证中心,认证中心解密token,解密成功,表示会话有效。
CAS
CAS是耶鲁大学开源的一个企业级的单点登录框架,目前已由Apereo基金会管理。目前Github上面有三个仓库:
- 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切换文档的版本
点击计划 -> 架构,打开架构页面,了解cas的架构:
点击计划 -> 开始,打开开始导向中,有一个发布 Cas 标题,建议我们使用 war 覆盖的方式发布 cas:
点击链接,打开 war 覆盖方式初始化的说明:
点击右侧大纲的Cas overlay template标题,定位到cas覆盖模版说明:
点击链接跳转到github的cas-overlay-template仓库地址,下载源码。
cas-overlay-template
6.x版本依赖jdk11,使用的是 gradle 构建工具。我这里使用 Idea 开发,如下截图,选择该项使用的 jdk 和 gradle 使用的 jdk 都是 11:
默认配置
从打包后的 app.war 中解压出来的 cas-server-webapp-resources-6.3.5.jar 中的配置:
##
# 嵌入的 Web 容器的 SSL 配置
#
server.ssl.key-store=file:/etc/cas/thekeystore
server.ssl.key-store-password=changeit
server.ssl.key-password=changeit
# 是否开启 https
server.ssl.enabled=true
##
# 嵌入的 Web 容器的配置
#
server.port=8443
server.servlet.context-path=/cas
server.max-http-header-size=2097152
server.forward-headers-strategy=NATIVE
server.error.include-stacktrace=ALWAYS
server.compression.enabled=true
server.compression.mime-types=application/javascript,application/json,application/xml,text/html,text/xml,text/plain
##
# 嵌入 Tomcat 容器的配置
#
server.tomcat.max-http-form-post-size=2097152
server.tomcat.basedir=build/tomcat
server.tomcat.connection-timeout=PT20S
server.tomcat.accesslog.enabled=true
server.tomcat.accesslog.pattern=%t %a "%r" %s (%D ms)
server.tomcat.accesslog.suffix=.log
server.tomcat.background-processor-delay=0s
server.tomcat.threads.min-spare=10
server.tomcat.threads.max=200
server.tomcat.remoteip.port-header=X-Forwarded-Port
server.tomcat.remoteip.protocol-header=X-Forwarded-Proto
server.tomcat.remoteip.protocol-header-https-value=https
server.tomcat.remoteip.remote-ip-header=X-FORWARDED-FOR
server.tomcat.uri-encoding=UTF-8
server.tomcat.additional-tld-skip-patterns=*.jar
##
# CAS Web Application JMX/Spring Configuration
#
spring.jmx.enabled=false
##
# CAS Web Application Http Encoding Configuration
#
server.servlet.encoding.charset=UTF-8
server.servlet.encoding.enabled=true
server.servlet.encoding.force=true
##
# Allow configuration classes to override bean definitions from Spring Boot
#
spring.main.allow-bean-definition-overriding=true
spring.main.lazy-initialization=false
##
# CAS Cloud Bus Configuration
#
spring.cloud.bus.enabled=false
# Indicates that systemPropertiesOverride can be used. Set to false to prevent users from changing the default accidentally. Default true.
spring.cloud.config.allow-override=true
# External properties should override system properties.
spring.cloud.config.override-system-properties=false
# When allowOverride is true, external properties should take lowest priority, and not override any existing property sources (including local config files).
spring.cloud.config.override-none=false
# spring.cloud.bus.refresh.enabled=true
# spring.cloud.bus.env.enabled=true
# spring.cloud.bus.destination=CasCloudBus
# spring.cloud.bus.ack.enabled=true
##
# CAS Web Application Endpoints Security
#
management.endpoints.enabled-by-default=false
management.endpoint.shutdown.enabled=false
management.endpoint.restart.enabled=false
management.endpoints.web.base-path=/actuator
management.endpoints.web.exposure.include=info,health,status,configurationMetadata
management.endpoints.jmx.exposure.exclude=*
# management.endpoints.web.exposure.include=*
# management.endpoints.web.path-mapping.health=status
# management.endpoint.health.show-details=when_authorized
management.server.add-application-context-header=false
# Endpoint Security Basic Authentication
spring.security.user.name=casuser
# spring.security.user.password=
# spring.security.user.roles=
# Define a CAS-specific "WARN" status code and its order
management.endpoint.health.status.order=WARN,DOWN,OUT_OF_SERVICE,UNKNOWN,UP
# Define health indicator behavior (requires cas-server-core-monitor)
management.health.memoryHealthIndicator.enabled=true
# Define a default that doesn't require module /cas/actuator/health/ping serves as status
management.health.ping.enabled=true
# turn off health indicators by default
management.health.defaults.enabled=false
spring.cloud.discovery.client.composite-indicator.enabled=false
##
# CAS Web Application Session Configuration
#
server.servlet.session.timeout=PT30S
server.servlet.session.cookie.http-only=true
server.servlet.session.tracking-modes=COOKIE
##
# CAS Thymeleaf View Configuration
#
spring.thymeleaf.encoding=UTF-8
spring.thymeleaf.cache=true
spring.thymeleaf.mode=HTML
spring.thymeleaf.template-resolver-order=100
##
# CAS Log4j Configuration
#
# logging.config=file:/etc/cas/log4j2.xml
server.servlet.context-parameters.isLog4jAutoInitializationDisabled=true
##
# CAS Metrics Configuration
#
management.metrics.web.server.request.autotime.enabled=true
management.metrics.export.atlas.enabled=false
management.metrics.export.datadog.enabled=false
management.metrics.export.ganglia.enabled=false
management.metrics.export.graphite.enabled=false
management.metrics.export.influx.enabled=false
management.metrics.export.jmx.enabled=false
management.metrics.export.newrelic.enabled=false
management.metrics.export.prometheus.enabled=false
management.metrics.export.signalfx.enabled=false
management.metrics.export.statsd.enabled=false
management.metrics.export.wavefront.enabled=false
management.metrics.export.simple.enabled=true
management.metrics.enable.logback=true
management.metrics.enable.process.files=true
management.metrics.enable.system.cpu=true
management.metrics.enable.process.cpu=true
management.metrics.enable.process.uptime=true
management.metrics.enable.process.start.time=true
##
# CAS Swagger Configuration
#
springdoc.show-actuator=true
springdoc.model-and-view-allowed=true
springdoc.writer-with-default-pretty-printer=true
springdoc.swagger-ui.displayRequestDuration=true
##
# CAS AspectJ Configuration
#
spring.aop.auto=true
spring.aop.proxy-target-class=true
##
# CAS View Settings
#
cas.view.cas2.v3ForwardCompatible=true
##
# CAS Authentication Credentials
#
cas.authn.accept.enabled=true
cas.authn.accept.users=casuser::Mellon
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,修改静态认证的用户名密码:
cas:
server:
name: https://app.qingdao2world.com:8443
prefix: ${cas.server.name}/cas
authn:
# 静态认证
accept:
# 添加用户名密码
users: test::123456
# 静态认证的处理器的名称
name: Static Credentials
server:
port: 8443
servlet:
context-path: /cas
ssl:
# 关闭 https 协议
enabled: false
将 log4j.xml 放到 resources 下面覆盖原始的日志文件,修改 log4j.xml 里面的日志路径:
运行 gradle 的 build 分组下的 run 脚本:
输入日志如下:
...
各种脚本的执行
...
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=
, -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]
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=
-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
Successfully started process 'command '/Users/beigege/Library/Java/JavaVirtualMachines/corretto-11.0.12/Contents/Home/bin/java''
_ ____ _____ ____ _____ ___ ____ _ ____
/ \ | _ \| ____| _ \| ____/ _ \ / ___| / \ / ___|
/ _ \ | |_) | _| | |_) | _|| | | | | | / _ \ \___ \
/ ___ \| __/| |___| _ <| |__| |_| | | |___ / ___ \ ___) |
/_/ \_\_| |_____|_| \_\_____\___/ \____/_/ \_\____/
CAS Version: 6.3.5
CAS Branch: 6.3.x
CAS Commit Id: 771568662d4df0ba9825eb6bb1ae53b9cfff4d28
CAS Build Date/Time: 2021-06-17T16:49:38Z
Spring Boot Version: 2.3.7.RELEASE
Spring Version: 5.2.12.RELEASE
Java Home: /Users/beigege/Library/Java/JavaVirtualMachines/corretto-11.0.12/Contents/Home
Java Vendor: Amazon.com Inc.
Java Version: 11.0.12
JVM Free Memory: 218 MB
JVM Maximum Memory: 2 GB
JVM Total Memory: 348 MB
OS Architecture: x86_64
OS Name: Mac OS X
OS Version: 11.5
OS Date/Time: 2021-07-28T23:55:25.956840
OS Temp Directory: /var/folders/fj/tr3p9j693f17kbzrrzl3v5x80000gn/T/
------------------------------------------------------------
Apache Tomcat Version: Apache Tomcat/9.0.48
------------------------------------------------------------
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>
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]]>
2021-07-28 23:55:26,178 INFO [org.apereo.cas.web.CasWebApplication] - <The following profiles are active: standalone>
2021-07-28 23:55:29,112 INFO [org.apereo.cas.configuration.CasConfigurationPropertiesValidator] - <Validated CAS property sources and configuration successfully.>
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.>
2021-07-28 23:55:35,048 WARN [org.apereo.cas.config.support.authentication.AcceptUsersAuthenticationEventExecutionPlanConfiguration] - <>
2021-07-28 23:55:35,048 WARN [org.apereo.cas.config.support.authentication.AcceptUsersAuthenticationEventExecutionPlanConfiguration] - <
____ _____ ___ ____ _
/ ___|_ _/ _ \| _ \| |
\___ \ | || | | | |_) | |
___) || || |_| | __/|_|
|____/ |_| \___/|_| (_)
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.>
2021-07-28 23:55:35,048 WARN [org.apereo.cas.config.support.authentication.AcceptUsersAuthenticationEventExecutionPlanConfiguration] - <>
2021-07-28 23:55:36,265 INFO [org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration] - <
Using generated security password: 6d0ea306-6cf7-4f91-bdc9-83ba678c4c73
>
2021-07-28 23:55:36,389 INFO [org.springframework.security.web.DefaultSecurityFilterChain] - <Will secure Ant [pattern='/login/**'] with []>
2021-07-28 23:55:36,389 INFO [org.springframework.security.web.DefaultSecurityFilterChain] - <Will secure Ant [pattern='/logout/**'] with []>
2021-07-28 23:55:36,389 INFO [org.springframework.security.web.DefaultSecurityFilterChain] - <Will secure Ant [pattern='/validate/**'] with []>
2021-07-28 23:55:36,389 INFO [org.springframework.security.web.DefaultSecurityFilterChain] - <Will secure Ant [pattern='/serviceValidate/**'] with []>
2021-07-28 23:55:36,389 INFO [org.springframework.security.web.DefaultSecurityFilterChain] - <Will secure Ant [pattern='/p3/serviceValidate/**'] with []>
2021-07-28 23:55:36,389 INFO [org.springframework.security.web.DefaultSecurityFilterChain] - <Will secure Ant [pattern='/proxyValidate/**'] with []>
2021-07-28 23:55:36,389 INFO [org.springframework.security.web.DefaultSecurityFilterChain] - <Will secure Ant [pattern='/p3/proxyValidate/**'] with []>
2021-07-28 23:55:36,389 INFO [org.springframework.security.web.DefaultSecurityFilterChain] - <Will secure Ant [pattern='/proxy/**'] with []>
2021-07-28 23:55:36,435 INFO [org.springframework.security.web.access.channel.ChannelProcessingFilter] - <Validated configuration attributes>
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]>
2021-07-28 23:55:37,328 WARN [org.apereo.cas.config.support.authentication.AcceptUsersAuthenticationEventExecutionPlanConfiguration] - <>
2021-07-28 23:55:37,328 WARN [org.apereo.cas.config.support.authentication.AcceptUsersAuthenticationEventExecutionPlanConfiguration] - <
____ _____ ___ ____ _
/ ___|_ _/ _ \| _ \| |
\___ \ | || | | | |_) | |
___) || || |_| | __/|_|
|____/ |_| \___/|_| (_)
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.>
2021-07-28 23:55:37,328 WARN [org.apereo.cas.config.support.authentication.AcceptUsersAuthenticationEventExecutionPlanConfiguration] - <>
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.>
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.>
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.>
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>
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].>
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>
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].>
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>
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].>
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>
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].>
2021-07-28 23:55:38,093 INFO [org.apereo.cas.web.CasWebApplication] - <Started CasWebApplication in 14.838 seconds (JVM running for 17.312)>
2021-07-28 23:55:38,098 INFO [org.apereo.cas.web.CasWebApplication] - <>
2021-07-28 23:55:38,098 INFO [org.apereo.cas.web.CasWebApplication] - <
____ _____ _ ______ __
| _ \| ____| / \ | _ \ \ / /
| |_) | _| / _ \ | | | \ V /
| _ <| |___ / ___ \| |_| || |
|_| \_\_____/_/ \_\____/ |_|
>
2021-07-28 23:55:38,098 INFO [org.apereo.cas.web.CasWebApplication] - <>
2021-07-28 23:55:38,098 INFO [org.apereo.cas.web.CasWebApplication] - <Ready to process requests @ [2021-07-28T15:55:38.098Z]>
2021-07-28 23:55:38,111 INFO [org.apereo.cas.services.AbstractServicesManager] - <Loaded [0] service(s) from [InMemoryServiceRegistry].>
有一个stop输出,说是使用了静态的认证列表,生产环境需要关闭,他的默认用户名:
##
# CAS Authentication Credentials
#
cas.authn.accept.enabled=true
cas.authn.accept.users=casuser::Mellon
cas.authn.accept.name=Static Credentials
输入访问地址查看:http://localhost:8443/cas,用我们修改后的用户名test密码123456登录
登录界面如下:
没有什么东西。
数据库认证
添加依赖:
在 build.gradle 中添加依赖,点击刷新依赖,会看到项目的依赖列表中会出现 jdbc 相关的的依赖。
修改配置,密码
cas:
server:
name: https://app.qingdao2world.com:8443
prefix: ${cas.server.name}/cas
authn:
accept:
# 禁用静态认证
enabled: false
users: test::test
name: Static Credentials
### JDBC用户认证
jdbc:
query[0]:
user: root
password: bgg@1234
driver-class: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/platform_cas?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false
# 数据库方言,mysql8
dialect: org.hibernate.dialect.MySQL8Dialect
# 认证器的名称
name: jdbcAuthenticationHandler
# 认证器的顺序
order: 0
sql: SELECT * FROM cas_user WHERE username=?
# 数据库密码字段
field-password: password
field-expired:
field-disabled:
# 作为用户属性的字段
principal-attribute-list: realname,nickname,phone,email
## 转换
principal-transformation:
# 用户名转小写
case-conversion: LOWERCASE
## 密码加密规则
password-encoder:
characterEncoding: UTF-8
# 加密方式,可以先设置为 NONE,不加密进行测试,即数据库存储明文密码
type: BCRYPT
strength: 7
重启后登录效果和静态认证是相同的,不同的数据库方言可以在官方文档中看到:https://apereo.github.io/cas/6.3.x/installation/JDBC-Drivers.html
服务注册
每一个客户端都看作是一个服务,客户端要使用认证中心登录,就需要将自己注册到认证中心,开发阶段可以使用 json 配置文件方式注册服务。
客户端
新建一个客户端程序,这里官方写的 springboot + security 的 demo,关键依赖
<!-- springboot security + cas start -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-cas</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.jasig.cas.client</groupId>
<artifactId>cas-client-support-springboot</artifactId>
<version>3.6.2</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
</dependency>
<!-- springboot security + cas end -->
配置:
# 应用名称
spring.application.name=cas-client-demo
# 应用服务 WEB 访问端口
server.port=8080
# 认证中心服务地址
cas.server-url-prefix=http://127.0.0.1:8443/cas
# 认证中心登录地址
cas.server-login-url=${cas.server-url-prefix}/login
# 是否接收认证中心的单点登出
cas.single-logout.enabled=true
# 客户端地址
cas.client-host-url=http://127.0.0.1:8080
# 自定义的spring security登出后的跳转地址,到认证中心的退出
cas-logout-url=http://127.0.0.1:8443/cas/logout?service=http://127.0.0.1:8080
# 用户权限名称,用户登录后回调 security 的 loadUserDetails,从认证中心返回的 Principal 中获取 attribute-authorities 的值作为权限
# var 权限 = assertion.getPrincipal().getAttributes().get(attribute) attribute in attribute-authorities
cas.attribute-authorities=memberships
cas.use-session=true
spring.freemarker.suffix=.ftl
server.session.cookie.http-only: true
server.session.tracking-modes: COOKIE
spring.mvc.view.prefix:/WEB-INF/jsp/
spring.mvc.view.suffix:.jsp
logging.level.org.springframework.security: DEBUG
logging.level.org.jasig.cas: DEBUG
## The format used for the keystore. It could be set to JKS in case it is a JKS file
#server.ssl.key-store-type=JKS
## The path to the keystore containing the certificate
#server.ssl.key-store=classpath:keystore
## The password used to generate the certificate
#server.ssl.key-store-password=password
## The alias mapped to the certificate
#server.ssl.key-alias=tomcat
#server.error.whitelabel.enabled=false
#server.ssl.enabled=true
服务端
修改认证中心的服务注册,先用 json 方式,在 resources 下新建 services 目录,在目录中新建一个符合客户端规则的服务配置:
开启 json 初始化服务:
cas:
### 服务注册(客户端注册)
service-registry:
## json 文件方式注册服务
init-from-json: true
重启访问客户端,服务会被 EmbeddedResourceBasedServiceRegistry 加载,当前没有加 cas-server-support-json-service-registry 注册依赖,所以应该不是 json 方式存储服务:
JPA
将服务存储到关系型数据库,添加依赖:
修改配置,关闭 json 初始化,添加 jpa:
cas:
jdbc:
# 输出 sql
show-sql: true
# gen-ddl: true
# case-insensitive: false
### 服务注册(客户端注册)
service-registry:
## json 文件初始化服务,会把初始化的服务存储到 mysql 数据库
core:
init-from-json: true
## JPA 方式(Mysql)
jpa:
user: root
password: bgg@1234
driver-class: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/platform_cas?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false
dialect: org.hibernate.dialect.MySQL8Dialect
# 服务注册表不存在就创建,有则更新字段。
ddl-auto: update
重新启动认证中心程序,第一次会创建几张表:
6.4.x之前版本
6.4.x版本开始只有两张表
加载0个服务
关于四张表:
native表
CREATE TABLE `native` (
`next_val` bigint DEFAULT NULL COMMENT '记录下一个服务ID'
) COMMENT = 'Cas服务ID序列表';
Regex_Registered_Service表
CREATE TABLE `Regex_Registered_Service` (
`expression_type` varchar(50) NOT NULL DEFAULT 'regex' COMMENT '表达式类型',
`id` bigint NOT NULL COMMENT '服务ID,主键',
`acceptable_usage_policy` longblob,
`access_strategy` longblob,
`attribute_release` longblob,
`authn_policy` longblob,
`description` varchar(255) DEFAULT NULL COMMENT '服务描述(客户端应用描述),显示在登录页面',
`environments` longblob,
`evaluation_order` int NOT NULL COMMENT '服务匹配的优先级,用于两个服务表达式匹配到相同url的情况',
`expiration_policy` longblob,
`information_Url` varchar(255) DEFAULT NULL COMMENT '服务信息地址',
`logo` varchar(255) DEFAULT NULL COMMENT '服务的logo,显示在登录页面',
`logout_type` int DEFAULT NULL COMMENT '退出后如何处理当前客户端:0-不处理,1-向客户端发送退出请求,2-向客户端发送JSONP请求',
`logout_url` varchar(255) DEFAULT NULL COMMENT '客户端接收退出请求的地址',
`matching_strategy` longblob,
`mfa_policy` longblob,
`name` varchar(255) NOT NULL COMMENT '服务名称(客户端应用名称),显示在登录页面',
`privacy_Url` varchar(255) DEFAULT NULL COMMENT '服务隐私政策地址,应用的隐私政策地址,显示在登录页面',
`proxy_granting_ticket_expiration_policy` longblob,
`proxy_policy` longblob COMMENT '代理策略,服务是否可以代理认证登录',
`proxy_ticket_expiration_policy` longblob,
`public_key` longblob COMMENT '与此服务关联的公钥,用于通过加密 CAS 验证协议响应中的某些元素和属性(例如PGT或凭据)来授权请求',
`redirect_url` varchar(255) DEFAULT NULL COMMENT '身份认证默认跳转地址',
`response_Type` varchar(255) DEFAULT NULL COMMENT 'Cas响应客户端的类型',
`service_Id` varchar(255) NOT NULL COMMENT '服务(客户端)url的匹配规则',
`service_ticket_expiration_policy` longblob,
`sso_participation_policy` longblob,
`theme` varchar(255) DEFAULT NULL COMMENT '服务在登录页面显示的样式主题',
`ticket_granting_ticket_expiration_policy` longblob,
`username_attr` longblob,
PRIMARY KEY (`id`)
) COMMENT='Cas服务注册表';
Regex_Registered_Service_Regex_Registered_Service_Property 表
CREATE TABLE `Regex_Registered_Service_Regex_Registered_Service_Property` (
`Abstract_Registered_Service_id` bigint NOT NULL,
`property_values` longblob,
`Regex_Registered_Service_Property_name` varchar(255) NOT NULL,
PRIMARY KEY (`Abstract_Registered_Service_id`,`Regex_Registered_Service_Property_name`),
CONSTRAINT `FKn94p2l49u0pwrf7djnt9fmn9b` FOREIGN KEY (`Abstract_Registered_Service_id`) REFERENCES `Regex_Registered_Service` (`id`)
) comment='服务注册属性';
Regex_Registered_Service_Registered_Service_Impl_Contact 表
CREATE TABLE `Regex_Registered_Service_Registered_Service_Impl_Contact` (
`Abstract_Registered_Service_id` bigint NOT NULL,
`department` varchar(255) DEFAULT NULL,
`email` varchar(255) DEFAULT NULL,
`name` varchar(255) NOT NULL,
`phone` varchar(255) DEFAULT NULL,
`contacts_ORDER` int NOT NULL,
PRIMARY KEY (`Abstract_Registered_Service_id`,`contacts_ORDER`),
CONSTRAINT `FK7pmuqhejyaxpxptr5hpqd7pxc` FOREIGN KEY (`Abstract_Registered_Service_id`) REFERENCES `Regex_Registered_Service` (`id`)
) comment = '已注册服务的联系人';
service_sequence 表
CREATE TABLE `service_sequence` (
`next_val` bigint DEFAULT NULL
) comment = '服务序列表';
Registered_Services 表
CREATE TABLE `Registered_Services` (
`id` bigint NOT NULL,
`body` varchar(8000) NOT NULL COMMENT '服务配置信息',
`evaluation_Order` int NOT NULL,
`evaluation_Priority` int NOT NULL,
`name` varchar(255) NOT NULL COMMENT '服务名称',
`service_Id` varchar(255) NOT NULL COMMENT '服务url的匹配规则',
PRIMARY KEY (`id`)
) 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 的变量:
# Settings to generate keystore
# used by the build to assist with creating
# self-signed certificates for https endpoints
certDir=/Users/beigege/IdeaProjects/2021/cas-overlay-template/etc/cas
serverKeystore=cas.keystore
exportedServerCert=cas.crt
storeType=PKCS12
cas-management-overlay
需要启用 ssl 才能正常运行。需要安装证书到jdk中,证书的dns需要包含当前项目中配置的认证中心地址的域名或ip。-ext
-dname | CN | 姓名,一般填写域名 |
---|---|---|
OU | 单位,填企业 | |
O | 组织,填部门 | |
C | 国家 | |
-ext | SAN | 证书信任的域名或ip |
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