springmvc--sso单点登录cas统一身份认证器

开发环境

  1. maven
  2. idea
  3. Windows 10
  4. JDK 1.8+

域名解析的配置

这里通过SwitchHosts来实现:以管理员身份打开

前两个:两个客户端应用的域名

后一个:是服务端的域名。

CAS服务器安装

下载服务端的overlay包:

https://github.com/apereo/cas-overlay-template

下载下来的压缩包:

服务端项目构建:

命令行状态下,在文件夹cas-overlay-template-master中运行命令:

build.cmd package

注意:

  1. 该操作是在windows下cmd下的操作。
  2. CAS 5.2.3的编译jdk版本必须是1.8以上
  3. Maven必须安装了和配置ok,这里使用的是3.5.2,主要maven不要配置私服
  4. 构建时必须联网,因为要下载相关依赖。

稍等片刻(视网络环境)执行完毕后,在target下找到cas.war备用:

准备好tomcat软件,将cas.war拷贝到tomcat的webapp目录中,

启动tomcat即可

出现下面就ok了使用浏览器访问

 

ip:port/cas/login  登录页面    默认 用户名密码(casuser/Mellon)

去除https协议认证

打开application.properties文件,在文件最后添加一行(注释是我自己写的,可以不要):

##
#不使用加密传输https协议,仅使用http,默认是打开状态
#
cas.tgc.secure=false

注册允许访问的客户端

第一步在ServiceId的值中加入“|http”。

提示:这里的值支持正则表达式,因此,也可以限定某个或某些具体的域名或ip才能访问服务端。如^http://localhost.*$,是只允许本地所有的客户端的访问。

{

  "@class" : "org.apereo.cas.services.RegexRegisteredService",

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

  "name" : "HTTPS and IMAPS",

  "id" : 10000001,

  "description" : "This service definition authorizes all application urls that support HTTPS and IMAPS protocols.",

  "evaluationOrder" : 10000

}

第二步:修改application.properties文件,告知 CAS 服务端从本地加载服务定义文件的位置等,将下面的配置复制到配置文件的最后:
 

#开启识别json文件,默认false
cas.serviceRegistry.initFromJson=true

相关属性说明(了解):

  1. @class:必须为org.apereo.cas.services.RegisteredService的实现类
  2. serviceId:对服务进行描述的表达式,可用于匹配一个或多个 URL 地址
  3. name: 服务名称
  4. id:全局唯一标志
  5. evaluationOrder:定义多个服务的执行顺序

修改完成后,需要重启服务端才能生效!

注面销页

ip:port/cas/logout 

打开服务端的\cas\WEB-INF\classes\application.properties文件,在文件最后添加一行

##
#Logout 退出
#
#是否允许退出后跳转到登录页面并指定再次登录后跳转的页面,默认是false,即登录不重定向到service参数指定的页面
cas.logout.followServiceRedirects=true

退出标签链接格式

<a href="http://CAS服务器IP:port/cas/logout?service=http://客户端IP:port">退出</a>

当点击之后回跳到登录页面

客户端搭建

客户端的开发可以参考官方文档:

https://apereo.github.io/cas/5.2.x/integration/CAS-Clients.html

官方提供了多种语言的客户端示例,当然这里选择下载Java的客户端,点击网址(直达:https://github.com/cas-projects/cas-sample-java-webapp)进入下载页面

下载下来的压缩包:

参考上节解压的客户端演示项目中的pom.xml、web.xml来配置当前项目。

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
	xmlns="http://java.sun.com/xml/ns/javaee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
	http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">


    <!--
   <context-param>
       <param-name>renew</param-name>
       <param-value>true</param-value>
   </context-param>
-->
    <!--修改五个位置-->
<!--退出过滤器-->
    <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>
            <!--cas服务器地址 如果突出他会跳转   -->
            <param-value>http://ip:port/cas</param-value>
        </init-param>
    </filter>
<!--退出监听器-->
    <listener>
        <listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
    </listener>
<!--认证过滤器-->
    <filter>
        <filter-name>CAS Authentication Filter</filter-name>
        <!--<filter-class>org.jasig.cas.client.authentication.Saml11AuthenticationFilter</filter-class>-->
        <filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>
        <init-param>
            <param-name>casServerLoginUrl</param-name>
            <!--如果要登录的话,会跳转到一个统一身份认证的服务器的一个登录界面-->
            <param-value>http://ip:port/cas/login</param-value>
        </init-param>
        <init-param>
            <param-name>serverName</param-name>
            <!--登录成功后悔自动跳转回该客户端的地址,一般首页-->
            <param-value>http://ip:port</param-value>
        </init-param>
    </filter>
<!--校验过滤器-->
    <filter>
        <filter-name>CAS Validation Filter</filter-name>
        <!--<filter-class>org.jasig.cas.client.validation.Saml11TicketValidationFilter</filter-class>-->
        <filter-class>org.jasig.cas.client.validation.Cas30ProxyReceivingTicketValidationFilter</filter-class>
        <init-param>
            <param-name>casServerUrlPrefix</param-name>
            <!--校验的cas服务器地址-->
            <param-value>http://ip:port/cas</param-value>
        </init-param>
        <init-param>
            <param-name>serverName</param-name>
            <!--客户端地址,在服务器登录后,自动转回客户端默认地址-->
            <param-value>http:/ip:port</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>acceptAnyProxy</param-name>
            <param-value>true</param-value>
        </init-param>
        <init-param>
            <param-name>proxyReceptorUrl</param-name>
            <param-value>/sample/proxyUrl</param-value>
        </init-param>
        <init-param>
            <param-name>proxyCallbackUrl</param-name>
            <param-value>https://mmoayyed.unicon.net:9443/sample/proxyUrl</param-value>
        </init-param>
        -->
        <init-param>
            <param-name>authn_method</param-name>
            <param-value>mfa-duo</param-value>
        </init-param>
    </filter>
<!--重新封装request对象的过滤器-->
    <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>
    <welcome-file-list>
        <welcome-file>
            index.jsp
        </welcome-file>
    </welcome-file-list>
</web-app>

 

pom依赖

    <dependencies>
        <!-- cas客户端核心 -->
        <dependency>
            <groupId>org.jasig.cas.client</groupId>
            <artifactId>cas-client-core</artifactId>
            <version>3.4.1</version>
        </dependency>
        <!-- slf4j-log4j12 -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.1</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <!-- 编译版本 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.5.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
            <!-- tomcat7插件 -->
            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <version>2.2</version>
                <configuration>
                    <!-- 端口 -->
                    <port>9002</port>
                    <!-- 请求路径 -->
                    <path>/</path>
                </configuration>
            </plugin>
        </plugins>
    </build>

测试页面

<%@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>B CAS 淘宝</title>
</head>
<body>

<h1>B CAS 淘宝</h1>
<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>

log4j.properties

### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

### direct messages to file mylog.log ###
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=c:/mylog.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

### set log levels - for more verbose logging change 'info' to 'debug' ###

log4j.rootLogger=debug, stdout

SSO(Single Sign On)

中文翻译为单点登录,它是目前主流的企业业务整合的解决方案之一,SSO的目标是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。即:使用SSO整合后,只需要登录一次就可以进入多个系统,而不需要重新登录,提供更好的用户体验,降低了安全的风险和管理的消耗。

CAS(Central Authentication Service)

中文翻译为统一身份认证服务或中央身份服务,CAS就是一套方案。它由服务端和客户端组成,实现了SSO,并且容易进行企业应用的集成

专业术语:

TGT(Ticket Granting ticket,票据授予的票据):cas用户登录成功后,服务端会生成一个大票据,封装了TGC和用户信息,可以生成票据的票据,该票据存放于CAS服务端中,可以签发ST默认在内存缓存中(InMemoryService)。默认有效期为120分钟 

 

TGC (Ticket-granting cookie, 票据授予的Cookie):它是由CAS服务端生成,CAS服务器会将TGC写入浏览器的cookie中, 数据结构是个数组对象。所以TGC是一个cookie,用来存放用户身份相关信息(加密过的),是CAS服务器对于浏览器是否信任的凭证,默认有效期为120分钟,浏览器关闭时销毁。

CAS服务端TGC

ST(Service ticket, 服务票据):是TGT签发给某个客户端服务的一次性票据,数据结构是一个长字符串。

当客户端服务拿到该票据后,要立刻回过头来找CAS服务端验证真伪(TGT有能力验证)。验证通过,则可以访问该客户端请求的资源;验证不通过,则抛出异常,提示不识别票据。

1)这个服务票据是临时一次性的,有效期非常的短,也就是说,服务端发出ST,客户端拿到ST,客户端要立刻到服务端去校验,如果中间出现某个环节时间过长,则票据验证失败。

2)客户端到服务端校验ST后,服务端返回的是个XML,内容参考如下:

最终封装成一个信任对象(Assertion)保存到客户端浏览器的session中

 

1)第一次访问客户端

浏览器访问客户端,他会校验是否有session 信任对象(Assertion),

没有就会重定向到CAS服务器上登录页面

,登陆成功,生成相应的票据,生成TGC写入Cookie,

TGT签发ST(给客户端一个临时票据然后客户端拿着票据再重新请求CAS服务比对票据,对比之后票据就清除了),

最终封装成一个信任对象(Assertion)保存到客户端的session中;

如果票据不对则会抛出异常

流程图

2)使用浏览器访问另一个客户端,他会校验是否有session 信任对象-->没有-->重定向到CAS服务器从cookie获取TGC,根据TGC找到TGT然后颁发ST凭证,携带ST到浏览器,浏览器携带ST凭证到CAS服务器比对验证,得到验证结果生成信息对像保存到客户端session中;然后重定向到目标资源;

3)重新访问在浏览器已经打开已经认证过的客户端,他会校验客户端是否有session信任对象-->有-->访问目标资源

 

 


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值