基于CAS实现单点登录

CAS

注:环境搭建相关资料:https://download.csdn.net/download/qq_31871785/11078868
在这里插入图片描述

一、概述

CAS是中央认证服务Central Authentication Service的简称。最初由耶鲁大学的Shawn Bayern 开发,后由Jasig社区维护,经过十多年发展,目前已成为影响最大、广泛使用的、基于Java实现的、开源SSO解决方案

2012年,Jasig和另一个有影响的组织Sakai Foundation合并,组成Apereo。Apereo是一个由高等学术教育机构发起组织的联盟,旨在为学术教育机构提供高质量软件,当然很多软件也被大量应用于商业环境,譬如CAS。目前CAS由Apereo社区维护。

CAS的官方网址是: https://www.apereo.org/projects/cas

Github地址:https://github.com/apereo/cas

二、术语解释

CAS的核心就是其Ticket,及其在Ticket之上的一系列处理操作。CAS的主要票据有TGT、ST、PGT、PGTIOU、PT,其中TGT、ST是CAS1.0(基础模式)协议中就有的票据,PGT、PGTIOU、PT是CAS2.0(代理模式)协议中有的票据。

  • TGT(Ticket Grangting Ticket)

    TGT是CAS为用户签发的登录票据,拥有了TGT,用户就可以证明自己在CAS成功登录过。TGT封装了Cookie值以及此Cookie值对应的用户信息。用户在CAS认证成功后,CAS生成cookie(叫TGC),写入浏览器,同时生成一个TGT对象,放入自己的缓存,TGT对象的ID就是cookie的值。当HTTP再次请求到来时,如果传过来的有CAS生成的cookie,则CAS以此cookie值为key查询缓存中有无TGT ,如果有的话,则说明用户之前登录过,如果没有,则用户需要重新登录。

  • TGC (Ticket-granting cookie)

    存放用户身份认证凭证的cookie,在浏览器和CAS Server间通讯时使用,并且只能基于安全通道传输(Https),是CAS Server用来明确用户身份的凭证。

  • ST(ServiceTicket)

    ST是CAS为用户签发的访问某一service的票据。用户访问service时,service发现用户没有ST,则要求用户去CAS获取ST。用户向CAS发出获取ST的请求,如果用户的请求中包含cookie,则CAS会以此cookie值为key查询缓存中有无TGT,如果存在TGT,则用此TGT签发一个ST,返回给用户。用户凭借ST去访问service,service拿ST去CAS验证,验证通过后,允许用户访问资源。

2. 实现原理

  • CAS Client 与受保护的客户端应用部署在一起,以 Filter 方式保护受保护的资源。对于访问受保护资源的每个 Web 请求, CAS Client 会分析该请求的 Http 请求中是否包含 Service Ticket ( ST )和 Ticket Granting Ticket(TGT) ,如果没有,则说明当前用户尚未登录,于是将请求重定向到指定好的 CAS Server 登录地址,并传递 Service (也就是要访问的目的资源地址),以便登录成功过后转回该地址。用户在第 3 步中输入认证信息,如果登录成功, CAS Server 随机产生一个相当长度、唯一、不可伪造的 Service Ticket ,并缓存以待将来验证,之后系统自动重定向到 Service 所在地址,并为客户端浏览器设置一个 Ticket Granted Cookie ( TGC ), CAS Client 在拿到 Service 和新产生的 Ticket 过后,在第 5 , 6 步中与 CAS Server 进行身份核实,以确保 Service Ticket 的合法性

  • 在该协议中,所有与 CAS 的交互均采用 SSL 协议确保 ST 和 TGC 的安全性。协议工作过程中会有 2 次重定向的过程,但是 CAS Client 与 CAS Server 之间进行 Ticket 验证的过程对于用户是透明的。

三、CAS环境搭建

创建证书

CAS 默认认证方式使用的是HTTPS协议,所以需要配置服务端的tomcat,使之支持SSL安全协议访问。

HTTPS(全称:Hyper Text Transfer Protocol over Secure Socket Layer),是以安全为目标的HTTP通道,简单讲是HTTP的安全版。

1)HTTPS协议需要到ca申请证书,一般免费证书很少,需要交费。

2)HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。

证书是单点登录认证系统中很重要的一把钥匙,客户端于服务器的交互安全靠的就是证书;

本教程由于是演示所以就自己用JDK自带的keytool工具生成证书;如果以后真正在产品环境中使用肯定要去证书提供商去购买,证书认证一般都是由VeriSign认证(中文官方网站:http://www.verisign.com/cn/)

  1. 用JDK自带的keytool工具生成证书:

    keytool -genkey -alias tomcat -keyalg RSA -keystore d:/keys/tomcat.keystore
    

    在这里插入图片描述

  2. 导出证书

    keytool -export -file d:/keys/tomcat.crt -alias tomcat -keystore d:/keys/tomcat.keystore
    

    在这里插入图片描述

  3. 为客户端的JVM导入证书

    keytool -import -keystore D:/softWare/Java/jdk1.8.0_91/jre/lib/security/cacerts -file D:/keys/tomcat.crt -alias tomcat
    

    有可能会碰到报错请参考:
      keytool 错误: java.io.IOException: Keystore was tampered with, or password was incorrect
      这里需要输入的密码不是证书的密码执行keytool -import -keystore - file 这个命令提示需要输入密码。输入 changeit,信任证书,OK

  4. 应用证书到Web服务器-Tomcat

    打开tomcat目录的conf/server.xml文件,开启87和92行的注释代码,并设置keystoreFile、keystorePass修改结果如下

    <Connector port="8443" protocol="org.apache.coyote.http11.Http11Protocol"
                   maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
                   clientAuth="false" sslProtocol="TLS" 
                   keystoreFile="D:/keys/tomcat.keystore"  
                   keystorePass="123456"  
                   />
    
  5. 配置HOSTS映射

    为CAS单点登录系统是基于JAVA安全证书的 https 访问, 要使用CAS单点登录必须要配置域名, CAS是不能通过ip访问的),编辑文件 C:\Windows\System32\drivers\etc\hosts 在文件末端添加下面三条信息:

    127.0.0.1   www.ssoserver.com
    127.0.0.1   www.ssoclient1.com
    127.0.0.1   www.ssoclient2.com
    
  6. 启动Tomcat并验证HTTPS配置

    输入网址: https://www.ssoserver.com:8443/
    在这里插入图片描述
    在这里插入图片描述

安装CAS-Server

  1. cas.war放置到tomcat/webapps/目录下,并启动tomcat

    在浏览器地址栏输入: https://www.ssoserver.com:8443/cas,出现CAS服务端的登录验证首页
    在这里插入图片描述

    使用账号密码(casuser/Mellon)登录CAS-Server
    在这里插入图片描述

  2. 导入lib

    tomcat-7.0.57\webapps\cas\lib导入以下2个jar包(自定义数据源相关)
    在这里插入图片描述

    无需导入c3p0

安装CAS-Client

  1. 新建应用cas_client1,并导入CAS Client依赖

    <dependencies>
        <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>
    </dependencies>
    
  2. 修改web.xml

    <web-app>
        <display-name>Archetype Created Web Application</display-name>
        <!-- 单点登出配置-->
        <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>CAS Authentication Filter</filter-name>
            <filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>
            <init-param>
                <param-name>casServerLoginUrl</param-name>
                <param-value>https://www.ssoserver.com:8443/cas/login</param-value>
            </init-param>
            <init-param>
                <param-name>serverName</param-name>
                <param-value>http://www.ssoclient1.com:9090</param-value>
            </init-param>
        </filter>
        <filter-mapping>
            <filter-name>CAS Authentication Filter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    
        <!-- 票据配置 -->
        <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://www.ssoserver.com:8443/cas</param-value>
            </init-param>
            <init-param>
                <param-name>serverName</param-name>
                <param-value>http://www.ssoclient1.com:9090</param-value>
            </init-param>
        </filter>
    
        <filter-mapping>
            <filter-name>CAS Validation Filter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    
    
        <!-- 封装标准的HttpRequest,使得request.getRemoteUser()和request.getUserPrincipal()这两个方法可用 -->
        <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>
        
        <!--定义的Servlet-->
        <servlet>
            <servlet-name>user</servlet-name>
            <servlet-class>com.baizhi.UserServlet</servlet-class>
        </servlet>
        <servlet-mapping>
            <servlet-name>user</servlet-name>
            <url-pattern>/user</url-pattern>
        </servlet-mapping>
    </web-app>
    
    
  3. 准备自定义Servlet

    package com.baizhi;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.security.Principal;
    
    public class UserServlet extends HttpServlet {
    
        @Override
        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            Principal principal = req.getUserPrincipal();
            req.getSession().setAttribute("user",principal.getName());
            req.getRequestDispatcher("/index.jsp").forward(req,resp);
        }
    }
    
    
  4. 准备受限资源 index.jsp

    <html>
    <body>
    <h2>Hello World!</h2>
    Hello: ${user} 
    </body>
    </html>
    
  5. 修改CAS-Server配置文件

    修改cas-server/cas/webapps/classes/services/HTTPSandIMAPS-10000001.json,以支持CAS-Client Http请求形式访问CAS-Server

    在这里插入图片描述

  6. 启动CAS-Client测试

    在浏览器地址栏输入: http://www.ssoclient1.com:9090/c1/user 回车,跳转到CAS-Server认证中心
    在这里插入图片描述

    输入用户名密码,跳转到SSO-Client
    在这里插入图片描述

三、自定义数据源

环境搭建

  1. 创建用户表
    在这里插入图片描述

    Note:password进行了MD5加密

  2. 修改配置文件deployerConfigContext.xml

    <!--     
        <bean id="primaryAuthenticationHandler"
              class="org.jasig.cas.authentication.AcceptUsersAuthenticationHandler">
            <property name="users">
                <map>
                    <entry key="casuser" value="Mellon"/>
                </map>
            </property>
        </bean>
      -->
    <!-- 配置数据源-->
    <bean id="dataSource" 
          class="com.mchange.v2.c3p0.ComboPooledDataSource"
          p:driverClass="com.mysql.jdbc.Driver" 
          p:jdbcUrl="jdbc:mysql://localhost:3306/test?useUnicode=true&amp;characterEncoding=UTF-8&amp;zeroDateTimeBehavior=convertToNull"
          p:user="root" 
          p:password="root" />
    
    <!-- 密码加密方式-->
    <bean id="passwordEncoder"      
          class="org.jasig.cas.authentication.handler.DefaultPasswordEncoder" autowire="byName">          
        <constructor-arg value="MD5"/>   
        <property name="characterEncoding">   
            <value>UTF-8</value>   
        </property>
    </bean>
    
    <!--查询匹配的字段-->
    <bean id="primaryAuthenticationHandler"
          class="org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler"
          p:dataSource-ref="dataSource"
          p:sql="select password from t_user where name = ?" 
          p:passwordEncoder-ref="passwordEncoder" />
    
  3. 重启CAS-Server测试,使用自定义数据源访问

四、自定义登录页

环境搭建

  1. CAS页面采用主题模板方式,定制一套自己的主题模板

    # 拷贝default目录,并命名为custom
    cas_server⁩/⁨webapps/cas⁩/⁨WEB-INF⁩/view⁩/jsp⁩/default
    

    在这里插入图片描述

  2. 修改使用的主题模板

    # 修改配置文件
    cas_server⁩/⁨webapps/cas⁩/WEB-INF/cas.properties
    

    在这里插入图片描述

  3. 指定自定义页面的静态资源文件

    # classes/cas-theme-default.properties 创建cas-theme-custom.properties文件,其内容是定义了css文件和js文件的位置。
    

    在这里插入图片描述

  4. 在/css目录下创建custom.css文件,内容如下:

    .form-bg{
        background: #00b4ef;
    }
    .form-horizontal{
        background: #fff;
        padding-bottom: 40px;
        border-radius: 15px;
        text-align: center;
    }
    .form-horizontal .heading{
        display: block;
        font-size: 35px;
        font-weight: 700;
        padding: 35px 0;
        border-bottom: 1px solid #f0f0f0;
        margin-bottom: 30px;
    }
    .form-horizontal .form-group{
        padding: 0 40px;
        margin: 0 0 25px 0;
        position: relative;
    }
    .form-horizontal .form-control{
        background: #f0f0f0;
        border: none;
        border-radius: 20px;
        box-shadow: none;
        padding: 0 20px 0 45px;
        height: 40px;
        transition: all 0.3s ease 0s;
    }
    .form-horizontal .form-control:focus{
        background: #e0e0e0;
        box-shadow: none;
        outline: 0 none;
    }
    .form-horizontal .form-group i{
        position: absolute;
        top: 12px;
        left: 60px;
        font-size: 17px;
        color: #c8c8c8;
        transition : all 0.5s ease 0s;
    }
    .form-horizontal .form-control:focus + i{
        color: #00b4ef;
    }
    .form-horizontal .fa-question-circle{
        display: inline-block;
        position: absolute;
        top: 12px;
        right: 60px;
        font-size: 20px;
        color: #808080;
        transition: all 0.5s ease 0s;
    }
    .form-horizontal .fa-question-circle:hover{
        color: #000;
    }
    .form-horizontal .main-checkbox{
        float: left;
        width: 20px;
        height: 20px;
        background: #11a3fc;
        border-radius: 50%;
        position: relative;
        margin: 5px 0 0 5px;
        border: 1px solid #11a3fc;
    }
    .form-horizontal .main-checkbox label{
        width: 20px;
        height: 20px;
        position: absolute;
        top: 0;
        left: 0;
        cursor: pointer;
    }
    .form-horizontal .main-checkbox label:after{
        content: "";
        width: 10px;
        height: 5px;
        position: absolute;
        top: 5px;
        left: 4px;
        border: 3px solid #fff;
        border-top: none;
        border-right: none;
        background: transparent;
        opacity: 0;
        -webkit-transform: rotate(-45deg);
        transform: rotate(-45deg);
    }
    .form-horizontal .main-checkbox input[type=checkbox]{
        visibility: hidden;
    }
    .form-horizontal .main-checkbox input[type=checkbox]:checked + label:after{
        opacity: 1;
    }
    .form-horizontal .text{
        float: left;
        margin-left: 7px;
        line-height: 20px;
        padding-top: 5px;
        text-transform: capitalize;
    }
    .form-horizontal .btn{
        float: right;
        font-size: 14px;
        color: #fff;
        background: #00b4ef;
        border-radius: 30px;
        padding: 10px 25px;
        border: none;
        text-transform: capitalize;
        transition: all 0.5s ease 0s;
    }
    @media only screen and (max-width: 479px){
        .form-horizontal .form-group{
            padding: 0 25px;
        }
        .form-horizontal .form-group i{
            left: 45px;
        }
        .form-horizontal .btn{
            padding: 10px 20px;
        }
    }
    
  5. 使用自定义页面覆盖默认页面
    cas_server⁩/⁨webapps/cas⁩/⁨WEB-INF⁩/view⁩/jsp⁩/custom

  • 5
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值