转载--cas5.3.2单点登录-集成客户端

原文地址,转载请注明出处: https://blog.csdn.net/qq_34021712/article/details/81318649     ©王赛超 

之前在服务端整合了数据库,也整合了shiro,我们一直是在服务端玩,登录跳转到登录成功页面,没啥意思,今天我们来将服务端和 客户端整合,使不同的客户端使用cas登录。cas服务端还是基于之前的整合shiro版本。

环境概述

ip域名对应服务
127.0.0.1server.cas.comCAS服务器
127.0.0.1app1.cas.comCAS客户端1
127.0.0.1app2.cas.comCAS客户端2

配置域名

/etc/hosts中增加如下配置:
127.0.0.1 server.cas.com
127.0.0.1 app1.cas.com
127.0.0.1 app2.cas.com

service配置(服务端)

客户端接入 CAS 首先需要在服务端进行注册,否则客户端访问将提示“未认证授权的服务”警告:
这里写图片描述
需求:对所有https和http请求的service进行允许认证,在resources/services下新建文件HTTPSandIMAPS-10000001.json,这个文件是我从cas源代码同路径下拷贝过来的。

{
  "@class" : "org.apereo.cas.services.RegexRegisteredService",
  "serviceId" : "^(https|imaps|http)://.*",
  "name" : "测试客户端",
  "id" : 10000001,
  "description" : "这是一个测试客户端的服务,所有的https或者http访问都允许通过",
  "evaluationOrder" : 10000
}
 
 

    注意:services目录中可包含多个 JSON 文件,其命名必须满足以下规则:${name}-${id}.json,id必须为json文件中内容id一致。
    对其中属性的说明如下,更多详细内容见官方文档-Service-Management
        ● @class:必须为org.apereo.cas.services.RegisteredService的实现类
        ● serviceId:对服务进行描述的表达式,可用于匹配一个或多个 URL 地址
        ● name: 服务名称
        ● id:全局唯一标志
        ● description:服务描述,会显示在默认登录页
        ● evaluationOrder:定义多个服务的执行顺序

    修改application.properties

    配置好service之后,根据官方文档-service-registry,还需修改 application.properties 文件告知 CAS 服务端从本地加载服务定义文件

    #注册客户端
    cas.serviceRegistry.initFromJson=true
    cas.serviceRegistry.watcherEnabled=true
    cas.serviceRegistry.schedule.repeatInterval=120000
    cas.serviceRegistry.schedule.startDelay=15000
    cas.serviceRegistry.managementType=DEFAULT
    cas.serviceRegistry.json.location=classpath:/services
    cas.logout.followServiceRedirects=true
     
     

    启动时,打印如下日志,说明服务注册成功

    2018-07-31 18:49:38,611 WARN [org.apereo.cas.services.ServiceRegistryInitializer] - <Skipping [Apereo] JSON service definition as a matching service [Apereo] is found in the registry>
    2018-07-31 18:49:38,611 WARN [org.apereo.cas.services.ServiceRegistryInitializer] - <Skipping [测试客户端] JSON service definition as a matching service [测试客户端] is found in the registry>
     
     

    客户端配置

    导入证书

    网上说必须保证客户端证书和服务端证书是同一个证书,不然就会报错,我因为是在同一台机器,所以就没有进行这一步操作。

    sudo keytool -import -file /Users/wangsaichao/Desktop/tomcat.cer -alias tomcat -keystore /Library/Java/JavaVirtualMachines/jdk1.8.0_144.jdk/Contents/Home/jre/lib/security/cacerts -storepass changeit
     
     
    搭建客户端

    在官方文档中提供了 CAS Java 客户端样例,即cas-sample-java-webapp。下载项目导入idea

    修改pom.xml
    <!--  为了测试方便,两个客户端都是使用http协议,引入tomcat插件,方便测试,默认是jetty。另一个客户端将端口改为 8082 -->
    <!--  tomcat7 plugin -->
    <plugin>
        <groupId>org.apache.tomcat.maven</groupId>
        <artifactId>tomcat7-maven-plugin</artifactId>
        <version>2.2</version>
        <configuration>
            <port>8081</port>
            <uriEncoding>UTF-8</uriEncoding>
            <server>tomcat7</server>
            <path>/</path>
        </configuration>
    </plugin>
     
     
    修改web.xml

    这里给的例子是client1的,如果是client2只需要将 app1.cas.com:8081改为 app2.cas.com:8082

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns="http://java.sun.com/xml/ns/javaee" xmlns:jsp="http://java.sun.com/xml/ns/javaee/jsp"
             xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
             version="2.5">
        <display-name>cas-app</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>
            <init-param>
                <param-name>casServerUrlPrefix</param-name>
                <param-value>https://server.cas.com: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 Filter</filter-name>
            <filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>
            <init-param>
                <param-name>casServerLoginUrl</param-name>
                <param-value>https://server.cas.com:8443/cas/login</param-value>
                <!-- 使用的CAS-Server的登录地址,一定是到登录的action -->
            </init-param>
            <init-param>
                <param-name>serverName</param-name>
                <param-value>http://app1.cas.com:8081</param-value>
                <!-- 当前Client系统的地址 -->
            </init-param>
        </filter>
        <filter-mapping>
            <filter-name>CAS Filter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
        <!-- 该过滤器负责对Ticket的校验工作 -->
        <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://server.cas.com:8443/cas</param-value>
                <!-- 使用的CAS-Server的地址,一定是在浏览器输入该地址能正常打开CAS-Server的根地址 -->
            </init-param>
            <init-param>
                <param-name>serverName</param-name>
                <param-value>http://app1.cas.com:8081</param-value>
                <!-- 当前Client系统的地址 -->
            </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()
             或者request.getUserPrincipal().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>
        <!-- ========================单点登录结束 ======================== -->
    </web-app>
     
     
    修改index.jsp

    为了看出效果,在两个客户端的index.jsp添加一些标签,和两个客户端互相跳转的路径,下面只给出客户端1的完整实例

    <%@page contentType="text/html" %>
    <%@page pageEncoding="UTF-8" %>
    <%@ page import="java.util.Map" %>
    <%@ page import="java.util.Iterator" %>
    <%@ page import="java.util.List" %>
    <%@ page import="org.jasig.cas.client.authentication.AttributePrincipal" %>
    
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
    "http://www.w3.org/TR/html4/loose.dtd">
    
    <html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>CAS Example Java Web App</title>
    </head>
    <body>
    
    <h1>当前为客户端1</h1>
    <h2><a href="http://app1.cas.com:8081/">客户端1</a></h2>
    <h2><a href="http://app2.cas.com:8082/">客户端2</a></h2>
    <p>A sample web application that exercises the CAS protocol features via the Java CAS Client.</p>
    <hr>
    
    <p><b>Authenticated User Id:</b> <a href="logout.jsp" title="Click here to log out"><%= request.getRemoteUser() %>
    </a></p>
    
    <%
        if (request.getUserPrincipal() != null) {
            AttributePrincipal principal = (AttributePrincipal) request.getUserPrincipal();
    
            final Map attributes = principal.getAttributes();
    
            if (attributes != null) {
                Iterator attributeNames = attributes.keySet().iterator();
                out.println("<b>Attributes:</b>");
    
                if (attributeNames.hasNext()) {
                    out.println("<hr><table border='3pt' width='100%'>");
                    out.println("<th colspan='2'>Attributes</th>");
                    out.println("<tr><td><b>Key</b></td><td><b>Value</b></td></tr>");
    
                    for (; attributeNames.hasNext(); ) {
                        out.println("<tr><td>");
                        String attributeName = (String) attributeNames.next();
                        out.println(attributeName);
                        out.println("</td><td>");
                        final Object attributeValue = attributes.get(attributeName);
    
                        if (attributeValue instanceof List) {
                            final List values = (List) attributeValue;
                            out.println("<strong>Multi-valued attribute: " + values.size() + "</strong>");
                            out.println("<ul>");
                            for (Object value : values) {
                                out.println("<li>" + value + "</li>");
                            }
                            out.println("</ul>");
                        } else {
                            out.println(attributeValue);
                        }
                        out.println("</td></tr>");
                    }
                    out.println("</table>");
                } else {
                    out.print("No attributes are supplied by the CAS server.</p>");
                }
            } else {
                out.println("<pre>The attribute map is empty. Review your CAS filter configurations.</pre>");
            }
        } else {
            out.println("<pre>The user principal is empty from the request object. Review the wrapper filter configuration.</pre>");
        }
    %>
    
    </body>
    </html>
     
     

    测试

    启动服务端和客户端,此时访问
    http://app1.cas.com:8081/
    会跳转至
    https://server.cas.com:8443/login?service=https%3A%2F%2Fapp1.cas.com%3A8081%2F
    输入用户信息,登录成功,返回
    http://app1.cas.com:8081/;jsessionid=3EFAC76F253826DB83F73C8EC7432D10
    这里写图片描述

    整合中出现的错误

    这里首先把出现的错误罗列一下,个跟客户端整合的过程中,也是出现了很多的问题。
    1.javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No name matching cas.com found
    原因:之前生成证书的时候,用的域名是server.cas.com 在开始使用cas 服务端的时候一直配置的域名是cas.com 其实应该带上server 所以,修改客户端中的cas.com 为 server.cas.com。记得修改/etc/hosts中的域名映射。

    2.org.jasig.cas.client.validation.TicketValidationException: No principal was found in the response from the CAS server.
    原因:通过debug,发现后台
    Cas20ServiceTicketValidator.parseResponseFromServer(Cas20ServiceTicketValidator.java:98)也就是这行代码,解析的时候报错了.具体原因是解析html页面报错,返回的是登录页面,在server验证成功后,应该是templates/protocol/3.0/casServiceValidationSuccess.html页面负责生成与客户端交互的xml信息。但是返回的却是登录页面,问题出在哪里呢?网上很多都是说的中文乱码什么的,我这边不是这个原因。还记得我们上一篇 服务端整合shiro,没错 是shiro权限拦截了,因为我们设置了ShiroFilterFactoryBean 并且配置了/**为 user 就是被拦截了。这个其实是不应该配置 ShiroFilterFactoryBean的.
    具体参考 :cas5.3.2单点登录-服务端集成shiro权限认证(五)

    • 0
      点赞
    • 1
      收藏
      觉得还不错? 一键收藏
    • 0
      评论

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

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

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

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

    抵扣说明:

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

    余额充值