cas5.3.2单点登录-集成客户端(六)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34021712/article/details/81318649

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

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

环境概述

ip 域名 对应服务
127.0.0.1 server.cas.com CAS服务器
127.0.0.1 app1.cas.com CAS客户端1
127.0.0.1 app2.cas.com CAS客户端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权限认证(五)

猜你喜欢

转载自blog.csdn.net/qq_34021712/article/details/81318649