CAS实现SSO单点登录案例(整合SpringSecurity)

共 18266字,需浏览 37分钟

 ·

2021-03-15 09:25

点击上方蓝色字体,选择“标星公众号”

优质文章,第一时间送达

76套java从入门到精通实战课程分享

CAS介绍

CAS是一个单点登录框架,由耶鲁大学的一个组织开发。CAS是一个开源项目,代码目前是在github上管理。单点登录:Single Sign On,简称SSO,SSO使得在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。通俗理解为一个应用登录了,其他被授权的应用不用再登录。之前也写过一篇sso单点登录,用redis实现的,有兴趣可以翻翻

cas下载地址:https://github.com/apereo/cas/releases


cas服务搭建

我们案例下载使用的是CAS4.2,采用HTTPS协议处理用户请求。搭建HTTPS需要咱们生成对应的证书信息。当然也可以通过配置使其支持http协议,但毕竟http协议不安全,所以我们还是学一下如何搭建本地HTTPS服务.


1.生成秘钥库

keytool -genkey -alias shemuel -keyalg RSA -keystore E:/javaee/cas/keystory/shemeul
其中-alias后面的是密钥库别名,最后的shemeul是要生成的密钥库文件.

命令运行后密钥库就生成了,接着就是导出这个密钥的证书,运行如下命令:

keytool -export -trustcacerts -alias shemuel -file E:/javaee/cas/keystory/shemuel.cer -keystore E:/javaee/cas/keystory/shemuel
前面的路径是要导出证书的位置,后面的路径是之前密钥库的路径

将证书导入到JDK证书库

刚才的操作会根据我们的秘钥库生成一个证书,紧接着我们需要将该证书导入到JDK的证书库里才能使用。

keytool -import -trustcacerts -alias shemuel -file E:/javaee/cas/keystory/shemuel.cer -keystore "F:/Java/jdk1.8.0_131/jre/lib/security/cacerts"

要求输入密钥库口令:注意这个密钥库是jdk的密钥库,口令密码为:changeit


2.tomcat发布cas服务端项目

在githib上下载cas服务端项目 https://github.com/apereo/cas/releases


  • 解压一个tomcat,放到D:\workspace\cas\目录下,把刚才我们下载的cas解压打开target目录下有个cas.war 拷贝到tomcat的webapps目录并解压,删除war包。


  • 下载的cas解压目录下还有一个文件target\war\work\org.jasig.cas\cas-server-webapp\WEB-INF\cas.properties,把他拷贝到webapps\cas\WEB-INF目录下。


  • 修改spring-configuration\propertyFileConfigurer.xml,把location="file:/etc/cas/cas.properties"换成刚才cas.properties的绝对路径。

    <util:properties id="casProperties" location="file:D:/workspace/cas/apache-tomcat-8.5.16/webapps/cas/WEB-INF/cas.properties" />

修改tomcat的conf/server.xml,加入如下代码

<Connector port="443" protocol="org.apache.coyote.http11.Http11NioProtocol"
        maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
        clientAuth="false" sslProtocol="TLS"
        keystoreFile="E:\javaee\cas\keystory\shemuel" 
        keystorePass="123456" />

启动tomcat, bin目录下的 startup.bat


访问 https://shemuel:8443/cas/login

我这里的本地hosts配置了 127.0.0.1 对应 shemuel了,有兴趣也可以配置一下.

访问后可能出现浏览器安全提示,因为我们的证书是本地的,没交钱所以会出现警告,添加个例外继续访问,看到如下界面就说明成功了

登录名:casuser 密码:Mellon

这是cas自带的一个登录用户,我们可以配置数据库信息,使用我们自己的数据库表用户登录


3.配置cas数据库连接池

  • 打开webapps\cas\WEB-INF\deployerConfigContext.xml

  • 把32行的<alias name="acceptUsersAuthenticationHandler" alias="primaryAuthenticationHandler" /> 注释掉。

  • 将如下代码拷贝到deployerConfigContext.xml中

<!--配置加密算法-->
  <bean id="MD5PasswordEncoder" class="org.jasig.cas.authentication.handler.DefaultPasswordEncoder" autowire="byName">
   <constructor-arg  value="MD5"/>
  </bean>
  
  <!--查询数据所采用什么加密方式-->
  <bean id="queryDatabaseAuthenticationHandler" name="primaryAuthenticationHandler" class="org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler">
   <property name="passwordEncoder" ref="MD5PasswordEncoder"/>
  </bean>
  
  <!--名字叫dataSource的Bean取别名叫queryDatabaseDataSource-->
  <alias name="dataSource" alias="queryDatabaseDataSource"/>
  
  <!--配置数据源-->
  <bean id="dataSource"
    class="com.mchange.v2.c3p0.ComboPooledDataSource"
    p:driverClass="com.mysql.jdbc.Driver"
    p:jdbcUrl="jdbc:mysql://127.0.0.1:3306/springsecurity?useUnicode=true&amp;characterEncoding=UTF-8&amp;zeroDateTimeBehavior=convertToNull"
    p:user="root"
    p:password="123456"
    p:initialPoolSize="6"
    p:minPoolSize="6"
    p:maxPoolSize="18"
    p:maxIdleTimeExcessConnections="120"
    p:checkoutTimeout="10000"
    p:acquireIncrement="6"
    p:acquireRetryAttempts="5"
    p:acquireRetryDelay="2000"
    p:idleConnectionTestPeriod="30"
    p:preferredTestQuery="select 1"/>
  <!--end  从数据库中的用户表中读取 -->


  • 把如下jar包拷贝到lib下

  • 配置查询语句

修改cas.properties 220行,去掉注释,修改如下:

修改cas.properties 220行,去掉注释,修改如下:

    cas.jdbc.authn.query.sql=select password from users where username=?

由于此时我们指定的加密算法为md5了,所以我们需要重新增加一条md5加密的数据到数据库去。

INSERT INTO users(username,password,enabled)VALUES('itheima',(SELECT MD5('123456')),'true');


重启tomcat,用itheima登录成功。


CSA实现单点登录功能

新建一个maven工程,配置一下CAS相关过滤器,然后访问首页。

pom依赖

    <dependency>
      <groupId>org.jasig.cas.client</groupId>
      <artifactId>cas-client-core</artifactId>
      <version>3.3.3</version>
    </dependency>
    <dependency>
   <groupId>javax.servlet</groupId>
   <artifactId>servlet-api</artifactId>
   <version>2.5</version>
   <scope>provided</scope>
 </dependency>
 <build>
  <plugins>
   <!-- 配置Tomcat插件 -->
   <plugin>
    <groupId>org.apache.tomcat.maven</groupId>
    <artifactId>tomcat7-maven-plugin</artifactId>
    <configuration>
     <port>70</port>
     <!-- http://127.0.0.1:{port}/{path} -->
     <path>/</path>
    </configuration>
   </plugin>

   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.1</version>
    <configuration>
     <source>1.8</source>
     <target>1.8</target>
    </configuration>
   </plugin>
  </plugins>
 </build>

web.xml

<!-- 用于单点退出,该过滤器用于实现单点登出功能,可选配置 -->
  <listener>
    <listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
  </listener>
  <!-- 该过滤器用于实现单点登出功能,可选配置。 -->
  <filter>
    <filter-name>CAS Single Sign Out Filter</filter-name>
    <filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>CAS Single Sign Out Filter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

  <!-- 该过滤器负责用户的认证工作,必须启用它 -->
  <filter>
    <filter-name>CASFilter</filter-name>
    <filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>
    <init-param>
      <param-name>casServerLoginUrl</param-name>
       <!--这是cas 服務端登陸認證地址 -->
      <param-value>https://shemuel:8443/cas/login</param-value>
     
    </init-param>
    <init-param>
      <param-name>serverName</param-name>
      <param-value>http://shemuel:70</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>CASFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
  
  
  <!--登陸成功后cas server會重定向到之前要訪問的頁面並携帶一個ticket,該ticket需要重新進行校驗認證。 以下过滤器负责对Ticket的校验工作,必须启用它 -->
  <filter>
    <filter-name>CAS Validation Filter</filter-name>
    <filter-class>org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter</filter-class>
    <init-param>
      <param-name>casServerUrlPrefix</param-name>
      <param-value>https://shemuel:8443/cas</param-value>
    </init-param>
    <init-param>
      <param-name>serverName</param-name>
      <param-value>http://shemuel:70</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>CAS Validation Filter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
  <!-- 该过滤器负责实现HttpServletRequest请求的包裹, 比如允许开发者通过HttpServletRequest的getRemoteUser()方法获得SSO登录用户的登录名,可选配置。 -->
  <filter>
    <filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
    <filter-class>
      org.jasig.cas.client.util.HttpServletRequestWrapperFilter
    </filter-class>
  </filter>
  <filter-mapping>
    <filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

  <!-- 该过滤器使得开发者可以通过org.jasig.cas.client.util.AssertionHolder来获取用户的登录名。 比如AssertionHolder.getAssertion().getPrincipal().getName()。 -->
  <filter>
    <filter-name>CAS Assertion Thread Local Filter</filter-name>
    <filter-class>org.jasig.cas.client.util.AssertionThreadLocalFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>CAS Assertion Thread Local Filter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>


tomcat运行,端口70,出现如下报错

上面错误的原因是因为CAS默认值接受HTTPS有IMAPS协议请求的认证,我们需要把HTTP也给加上去。


打开下载的cas项目: cas\WEB-INF\classes\services\HTTPSandIMAPS-10000001.json,修改第3行

"serviceId" : "^(https|imaps)://.*",


改成

"serviceId" : "^(https|imaps|http)://.*",


保存,并重新启动即可。


拷贝casclient-demo1 模拟两个客户端

拷贝casclien-demo1 改名casclient-demo2 部署,tomcat端口18083,进行单点测试。一个站点登录后另外一个站点就不需要登录了。

如果运营一旦出现如下错误,请调整tomcat的JDK,和生成秘钥的JDK保持一致,不要用SDK即可。

java.lang.RuntimeException: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
 org.jasig.cas.client.util.CommonUtils.getResponseFromServer(CommonUtils.java:407)
 org.jasig.cas.client.validation.AbstractCasProtocolUrlBasedTicketValidator.retrieveResponseFromServer(AbstractCasProtocolUrlBasedTicketValidator.java:45)
 org.jasig.cas.client.validation.AbstractUrlBasedTicketValidator.validate(AbstractUrlBasedTicketValidator.java:200)
 org.jasig.cas.client.validation.AbstractTicketValidationFilter.doFilter(AbstractTicketValidationFilter.java:206)
 org.jasig.cas.client.authentication.AuthenticationFilter.doFilter(AuthenticationFilter.java:161)
 org.jasig.cas.client.session.SingleSignOutFilter.doFilter(SingleSignOutFilter.java:100)

 Root Cause
 
 javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
  sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
  sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1949)
  sun.security.ssl.Handshaker.fatalSE(Handshaker.java:302)
  sun.security.ssl.Handshaker.fatalSE(Handshaker.java:296)
  sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1509)
  sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:216)
  sun.security.ssl.Handshaker.processLoop(Handshaker.java:979)
  sun.security.ssl.Handshaker.process_record(Handshaker.java:914)
  sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1062)
  sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375)
  sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1403)
  sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1387)
  sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:559)
  sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
  sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1513)
  sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1441)
  sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:254)
  org.jasig.cas.client.util.CommonUtils.getResponseFromServer(CommonUtils.java:393)
  org.jasig.cas.client.validation.AbstractCasProtocolUrlBasedTicketValidator.retrieveResponseFromServer(AbstractCasProtocolUrlBasedTicketValidator.java:45)
  org.jasig.cas.client.validation.AbstractUrlBasedTicketValidator.validate(AbstractUrlBasedTicketValidator.java:200)
  org.jasig.cas.client.validation.AbstractTicketValidationFilter.doFilter(AbstractTicketValidationFilter.java:206)
  org.jasig.cas.client.authentication.AuthenticationFilter.doFilter(AuthenticationFilter.java:161)
  org.jasig.cas.client.session.SingleSignOutFilter.doFilter(SingleSignOutFilter.java:100)
 
 Root Cause
 
 sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
  sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:387)
  sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:292)
  sun.security.validator.Validator.validate(Validator.java:260)
  sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:324)
  sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:229)
  sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:124)
  sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1491)
  sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:216)
  sun.security.ssl.Handshaker.processLoop(Handshaker.java:979)
  sun.security.ssl.Handshaker.process_record(Handshaker.java:914)
  sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1062)
  sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375)
  sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1403)
  sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1387)
  sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:559)
  sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
  sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1513)
  sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1441)
  sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:254)
  org.jasig.cas.client.util.CommonUtils.getResponseFromServer(CommonUtils.java:393)
  org.jasig.cas.client.validation.AbstractCasProtocolUrlBasedTicketValidator.retrieveResponseFromServer(AbstractCasProtocolUrlBasedTicketValidator.java:45)
  org.jasig.cas.client.validation.AbstractUrlBasedTicketValidator.validate(AbstractUrlBasedTicketValidator.java:200)
  org.jasig.cas.client.validation.AbstractTicketValidationFilter.doFilter(AbstractTicketValidationFilter.java:206)
  org.jasig.cas.client.authentication.AuthenticationFilter.doFilter(AuthenticationFilter.java:161)
  org.jasig.cas.client.session.SingleSignOutFilter.doFilter(SingleSignOutFilter.java:100)


cas服务端和两个客户端都启动后,我们访问其中一个客户端登录后,另一个客户端就不需要登录了说明成功!

至此简易的单点登录系统就完成了,后面会介绍springsecurity 如何整合cas

————————————————

版权声明:本文为CSDN博主「Shemuel_Deng」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:

https://blog.csdn.net/qq_35249342/article/details/86488393





粉丝福利:Java从入门到入土学习路线图

👇👇👇

👆长按上方微信二维码 2 秒


感谢点赞支持下哈 

浏览 44
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报