cas单点登录服务端部署以及客户端配置详解

本文内容目录


  1. cas介绍

  2. tomcat配置https支持(包括证书生成步骤)

  3. cas服务端搭建

  4. cas客户端搭建


1. cas介绍

简介:

CAS是Central Authentication Service的缩写,中央认证服务,一种独立开放指令协议。CAS 是 耶鲁大学(Yale University)发起的一个开源项目,旨在为 Web 应用系统提供一种可靠的单点登录方法,CAS 在 2004 年 12 月正式成为 JA-SIG 的一个项目。

特点:

1、开源的企业级单点登录解决方案。

2、CAS Server 为需要独立部署的 Web 应用。

3、CAS Client 支持非常多的客户端(这里指单点登录系统中的各个 Web 应用),包括 Java, .Net, PHP, Perl, Apache, uPortal, Ruby 等。

4、CAS属于Apache 2.0许可证,允许代码修改,再发布(作为开源或商业软件)。

从结构上看,CAS 包含两个部分: CAS Server 和 CAS Client。CAS Server 需要独立部署,主要负责对用户的认证工作;CAS Client 负责处理对客户端受保护资源的访问请求,需要登录时,重定向到 CAS Server。下图 是 CAS 最基本的协议过程:

CAS Client 与受保护的客户端应用部署在一起,以 Filter 方式保护受保护的资源。对于访问受保护资源的每个 Web 请求,CAS Client 会分析该请求的 Http 请求中是否包含 Service Ticket,如果没有,则说明当前用户尚未登录,于是将请求重定向到指定好的 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 协议中还提供了 Proxy (代理)模式,以适应更加高级、复杂的应用场景,具体介绍可以参考 CAS 官方网站上的相关文档。


2. tomcat配置https支持(包括证书生成步骤)


3. cas服务端搭建

  • cas服务端war包下载地址:

    点击官网下载

    点击百度网盘提取 提取码:1bm9

  • 把war包放tomcat下,启动tomcat会自动解压,我们把名称改成cas,方便访问

  • 修改cas服务端日志文件生成位置:

    tomcat/webapps/cas/WEB-INF/classes/log4j2.xml

用户名:casuser

密码:Mellon

(初始的账号密码)

  • 配置数据源,数据库用户认证

    第一步:新建数据和表:

    DROP TABLE IF EXISTS `my_cas`;
    ​
    ​
    CREATE TABLE `my_cas` (
    ​
      `id` int(11) NOT NULL AUTO_INCREMENT,
    ​
      `username` varchar(30) DEFAULT NULL,
    ​
      `password` varchar(100) DEFAULT NULL,
    ​
      PRIMARY KEY (`id`)
    ​
    ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
    insert  into `my_cas`(`id`,`username`,`password`) values (1,'admin','123456');

    第二步:修改cas配置文件,配置自定义的用户表,以及用户密码MD5加密

    先注释掉原来默认的用户名密码

    修改: tomcat/webapps/cas/WEB-INF/classes/application.properties

    #CAS Authentication Credentials
    #cas.authn.accept.users=casuser::Mellon
    cas.authn.jdbc.query[0].url=jdbc:mysql://ip:3306/test_cas?serverTimezone=GMT
    cas.authn.jdbc.query[0].user=root
    cas.authn.jdbc.query[0].password=123456
    cas.authn.jdbc.query[0].sql=select * from my_cas where username=?
    cas.authn.jdbc.query[0].fieldPassword=password
    cas.authn.jdbc.query[0].driverClass=com.mysql.jdbc.Driver
    cas.authn.jdbc.query[0].passwordEncoder.type=DEFAULT
    cas.authn.jdbc.query[0].passwordEncoder.characterEncoding=UTF-8
    #MD5加密策略
    cas.authn.jdbc.query[0].passwordEncoder.encodingAlgorithm=MD5
    cas.tgc.secure=false
    cas.serviceRegistry.initFromJson=true
    ​

    注意:修改好后用户表里password存的应该是加密后的

    数据库生成下md5密码

    SELECT MD5('123456');

    第三步:放入mysql驱动jar包,放入位置:tomcat\webapps\cas\WEB-INF\lib

    点击百度网盘提取 提取码:1bm9

  • 至此,cas服务端已经搭建完毕。


4. cas客户端搭建

  • 本文介绍两个例子,均实践成功,分别是springBoot整合cas客户端和ssm整合cas客户端

  • 两种方式都需在pom中添加cas客户端依赖

    <dependency>
      <groupId>org.jasig.cas.client</groupId>
      <artifactId>cas-client-core</artifactId>
      <version>3.4.1</version>
    </dependency>

    1.springBoot整合cas客户端

    • 项目中添加cas配置类

    package tca.xxx.xxx.cas;
    ​
    import org.jasig.cas.client.session.SingleSignOutFilter;
    import org.jasig.cas.client.session.SingleSignOutHttpSessionListener;
    import org.jasig.cas.client.util.AssertionThreadLocalFilter;
    import org.jasig.cas.client.util.HttpServletRequestWrapperFilter;
    import org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.boot.web.servlet.FilterRegistrationBean;
    import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.PropertySource;
    import org.springframework.stereotype.Component;
    ​
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    ​
    @Configuration
    @Component
    @PropertySource({"classpath:common.properties"})
    public class CasConfigure{
    ​
        /**
         * cas服务端地址  https://ip:8443/cas
         */
        @Value("${casServicePath}")
        private String  casServerLoginUrl;
        /**lo
         * 当前应用地址  你自己项目访问地址
         */
        @Value("${myServicePath}")
        private String serverName;
        /**
         * 该监听器用于实现单点登出功能,session失效监听器
         */
        @Bean
        public ServletListenerRegistrationBean<SingleSignOutHttpSessionListener> singleSignOutHttpSessionListener() {
            ServletListenerRegistrationBean<SingleSignOutHttpSessionListener> listener = new ServletListenerRegistrationBean<>();
            listener.setEnabled(true);
            listener.setListener(new SingleSignOutHttpSessionListener());
            listener.setOrder(1);
            return listener;
        }
        /**
         * 该过滤器用于实现单点登出功能,当一个系统登出时,cas服务端会通知,各个应
         * 用进行进行退出操作,该过滤器就是用来接收cas回调的请求,如果是前后端分离
         * 应用,需要重写SingleSignOutFilter过滤器,按自已的业务规则去处理
         */
        @Bean
        public FilterRegistrationBean singleSignOutFilter() {
            FilterRegistrationBean filterRegistration = new FilterRegistrationBean();
            filterRegistration.setFilter(new SingleSignOutFilter());
            //filterRegistration.setEnabled(true);
            filterRegistration.addUrlPatterns("/*");
            filterRegistration.addInitParameter("casServerUrlPrefix", casServerLoginUrl);
            filterRegistration.setOrder(2);
            return filterRegistration;
        }
        /**
         * 该过滤器负责单点登录功能,用户登录的认证工作
         * @return
         */
        @Bean
        public FilterRegistrationBean authenticationFilterRegistrationBean() {
            FilterRegistrationBean authenticationFilter = new FilterRegistrationBean();
            authenticationFilter.setFilter(new MyAuthenticationFilter()); //这里就是被换的类
            Map<String, String> initParameters = new HashMap<String, String>();
            initParameters.put("casServerLoginUrl", casServerLoginUrl);
            initParameters.put("ignorePattern", "/logout/success|/index");
            initParameters.put("serverName",serverName);
            authenticationFilter.setInitParameters(initParameters);
            authenticationFilter.setOrder(3);
            return authenticationFilter;
        }
    ​
        /**
         * 该过滤器用于单点登录功能,负责对Ticket的校验工作
         * @return
         */
        @Bean
        public FilterRegistrationBean ValidationFilterRegistrationBean(){
            FilterRegistrationBean authenticationFilter = new FilterRegistrationBean();
            authenticationFilter.setOrder(4);
            authenticationFilter.setFilter(new Cas20ProxyReceivingTicketValidationFilter());
            Map<String, String> initParameters = new HashMap<>();
            initParameters.put("casServerUrlPrefix", casServerLoginUrl);
            initParameters.put("serverName", serverName);
            initParameters.put("redirectAfterValidation", "true");
            initParameters.put("useSession", "true");
            initParameters.put("authn_method", "mfa-duo");
            authenticationFilter.setInitParameters(initParameters);
            List<String> urlPatterns = new ArrayList<String>();
            urlPatterns.add("/*");
            authenticationFilter.setUrlPatterns(urlPatterns);
            return authenticationFilter;
        }
        /**
         * 该过滤器用于单点登录功能 ,对HttpServletRequest请求包装, 可通过HttpServletRequest的getRemoteUser()方法获得登录用户的登录名
         * @return
         */
        @Bean
        public FilterRegistrationBean casHttpServletRequestWrapperFilter(){
            FilterRegistrationBean authenticationFilter = new FilterRegistrationBean();
            authenticationFilter.setFilter(new HttpServletRequestWrapperFilter());
            authenticationFilter.setOrder(5);
            List<String> urlPatterns = new ArrayList<String>();
            urlPatterns.add("/*");
            authenticationFilter.setUrlPatterns(urlPatterns);
            return authenticationFilter;
        }
    ​
        /**
         * 该过滤器使得可以通过org.jasig.cas.client.util.AssertionHolder来获取用户的登录名。
         比如AssertionHolder.getAssertion().getPrincipal().getName()。
         这个类把Assertion信息放在ThreadLocal变量中,这样应用程序不在web层也能够获取到当前登录信息
         * @return
         */
        @Bean
        public FilterRegistrationBean casAssertionThreadLocalFilter(){
            FilterRegistrationBean authenticationFilter = new FilterRegistrationBean();
            authenticationFilter.setFilter(new AssertionThreadLocalFilter());
            authenticationFilter.setOrder(6);
            List<String> urlPatterns = new ArrayList<String>();
            urlPatterns.add("/*");
            authenticationFilter.setUrlPatterns(urlPatterns);
            return authenticationFilter;
        }
    }
    ​
    ​
    • 根据自己的需求逻辑编写自己的MyAuthenticationFilter类,此类在重写AuthenticationFilter基础上,再根据自己需求修改即可。注:无特殊需求上述配置中 “authenticationFilter.setFilter(new MyAuthenticationFilter()); //这里就是被换的类” 这段配置MyAuthenticationFilter()用默认的AuthenticationFilter()即可。

    • 单点登出

    /**
    * 单点登出
    * @return
    */
    @RequestMapping("/logout")
    public String logout(HttpServletRequest request){
        return "redirect:https://ip:8443/cas/logout";
    }

    2.ssm整合cas客户端

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
       <!--登出监听器-->
        <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>
            <init-param>
                <param-name>casServerUrlPrefix</param-name>
                <param-value>https://ip:8443/cas</param-value>
            </init-param>
        </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://ip:8443/cas/login</param-value>
            </init-param>
            <init-param>
                <param-name>serverName</param-name>
                <param-value>https://10.0.0.101:8447/gatewayMassage/</param-value>
            </init-param>
            <!--忽略验证的url,多个url使用"|"分割-->
            <init-param>
                <param-name>ignorePattern</param-name>
                <param-value>/logout/success|/index</param-value>
            </init-param>
        </filter>
     
        <!--ticke验证过滤器-->
        <filter>
            <filter-name>CAS Validation Filter</filter-name>
            <filter-class>org.jasig.cas.client.validation.Cas30ProxyReceivingTicketValidationFilter</filter-class>
            <init-param>
                <param-name>casServerUrlPrefix</param-name>
                <param-value>https://ip:8443/cas</param-value>
            </init-param>
            <init-param>
                <param-name>serverName</param-name>
                <param-value>https://10.0.0.101:8447/gatewayMassage/</param-value>
            </init-param>
            <init-param>
                <param-name>redirectAfterValidation</param-name>
                <param-value>true</param-value>
            </init-param>
            <init-param>
                <param-name>useSession</param-name>
                <param-value>true</param-value>
            </init-param>
            <init-param>
                <param-name>authn_method</param-name>
                <param-value>mfa-duo</param-value>
            </init-param>
        </filter>
     
        <!--wrapper过滤器-->
        <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 Single Sign Out Filter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
     
        <filter-mapping>
            <filter-name>CAS Validation Filter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
     
        <filter-mapping>
            <filter-name>CAS Authentication Filter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
     
        <filter-mapping>
            <filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
      <!-- 这个类把Assertion信息放在ThreadLocal变量中,这样应用程序不在web层也能够获取到当前登录信息 -->
         <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>
    </web-app>
    
  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值