cas单点登录 附带server、client所有jar包

一、cas单点登录的应用场景:

很简单的道理,一个大型的网站或者系统,比如Tencent、AliBaBa、BaiDu这些系统,你登录QQ以后再去玩腾讯游戏、腾讯视频、QQ音乐,又或者支付宝、淘宝、再或者百度文库,百度外卖等等这些用户认证系统,再比如一些集团公司的用户OA系统,肯定不会是你登陆完一个应用,再去认证下一个,这样繁琐的逻辑和认证,就应用到了SSO单点登录这种场景。

二、cas单点登录的原理:

盗用一张图,简单描述了CAS原理和协议,直观易懂。说白了就是cas服务端充当公共认证中心,负责颁发票据和检验身份。CAS Client 负责处理对客户端受保护资源的访问请求,需要登录时,重定向到 CAS Server。

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 验证的过程对于用户是透明的。
三、直接进入主题,笔者本次是在Windows环境下,开启不同的Tomcat模拟两个客户端和一个服务端的情况,Linux是一样的道理,待下次进行,附上Linux的操作步骤
1.简单介绍下keytool
Keytool是一个Java数据证书的管理工具。Keytool将密钥(key)和证书(certificates)存在一个称为keystore的文件中在keystore里,包含两种数据: 
a、   密钥实体(Key entity)——密钥(secret key)又或者是私钥和配对公钥(采用非对称加密)  
b、  可信任的证书实体(trusted certificate entries)——只包含公钥  
Alias(别名):每个keystore都关联这一个独一无二的alias,这个alias通常不区分大小写  
keystore的存储位置  
在没有制定生成位置的情况下,keystore会存在与用户的系统默认目录, 如:对于window xp系统,会生成在系统的C:/Documents and Settings/UserName/ 文件名为“.keystore”
2. 服务器生成证书  
(注:生成证书时,CN要和服务器的域名相同,如果在本地测试,则使用localhost)  
Window : keytool -genkey -alias tomcat -keyalg RSA -keystore d:/my.keystore -dname "CN=localhost, OU=localhost, O=localhost, L=SH, ST=SH, C=CN" -keypass changeit -storepass changeit  
Linux : keytool -genkey -alias tomcat -keyalg RSA -keystore ~/my.keystore -dname "CN=localhost, OU=localhost, O=localhost, L=SH, ST=SH, C=CN" -keypass changeit -storepass changeit  
3.导出证书,客户端安装
window : keytool -export -alias tomcat -keystore d:/my.keystore -file d:/mycerts.cer -storepass changeit  
Linux : keytool -export -alias tomcat -keystore ~/my.keystore -file ~/mycerts.cer -storepass changeit  
4.客户端的配置:为JVM导入秘钥
window : keytool -import -trustcacerts -alias tomcat -keystore "%JAVA_HOME%/jre/lib/security/cacerts" -file d:/mycerts.cer -storepass changeit  
Linux : keytool -import -trustcacerts -alias tomcat -keystore "$JAVA_HOME/jre/lib/security/cacerts" -file ~/mycerts.cer -storepass changeit  
5.配置服务端Tomcat/server.xml配置
去掉8443端口的注释
<Connector port="8453" protocol="org.apache.coyote.http11.Http11Protocol" SSLEnabled="true"
               maxThreads="150" scheme="https" secure="true"
               clientAuth="false" sslProtocol="TLS"
               keystoreFile="d:/my.keystore" keystorePass="changeit"
               />
由于我的Tomcat8443端口一直被占用,便改成8453,没什么影响,Linux下的Tomcat配置和上面一样。
6.到此cas服务端配置完成,以下用到的所有jar包或者项目,笔者会提供。现在需要将cas-server-4.0.0-release.zip解压后module里的cas-server-webapp-4.0.0.war部署到你的服务端Tomcat下
进行测试.提供两种访问方式http://localhost:9997/cas/login 或者https://localhost:8453/cas/login都可以,
出现如下页面
初始用户名用默认casuser/Mellon,登陆成功后我们开始改用连接mysql自定义查询登录
需要添加 jar包cas-server-support-jdbc-4.1.4.jar和mysql-connector-java-5.0.8-bin.jar第一个在下载的cas-server-4.0.0-release.zip解压文件有,第二个很常见。
找到下面这个bean注释掉
<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="org.springframework.jdbc.datasource.DriverManagerDataSource">  
     <property name="driverClassName" value="com.mysql.jdbc.Driver" />  
     <property name="url"  value="jdbc:mysql://localhost:3306/txjh?characterEncoding=utf-8" />  
     <property name="username" value="root" />  
     <property name="password" value="1234" />  
     </bean>  
  登录入口,密码MD5加密
     <bean id="primaryAuthenticationHandler"  
        class="org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler"  
       p:dataSource-ref="dataSource"  
       p:passwordEncoder-ref="MD5PasswordEncoder"  
       p:sql="select password from t_user where username=?" />  
         数据库存的是MD5加密后的密码,没有盐和散列算法
     <bean id="MD5PasswordEncoder" class="org.jasig.cas.authentication.handler.DefaultPasswordEncoder">  
     <constructor-arg index="0">  
           <value>MD5</value>  
     </constructor-arg>  
     </bean>
再启动,输入用户名和密码,登录成功
7.接下来准备客户端(子应用项目)
其实随便建个web项目,添加如下jar包和几张页面,
先说web.xml,笔者在这准备三个项目,两个放在同一个服务器下(Tomcat)就是端口一致,另一个单独放
< listener >
        < listener-class > org.jasig.cas.client.session.SingleSignOutHttpSessionListener </ listener-class >
</ listener >
    <!-- 登出filter -->
    < 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://localhost:8453/cas </ param-value >
        </ init-param >
    </ filter >
<!-- 拦截单点登录验证 -->
    < 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://localhost:9997/cas/login </ param-value >//这是cas服务端的地址
        </ init-param >
        < init-param >
        <!-- 把子系统注册给认证中心 这里的ip是各个子应用所部署的服务器地址-->
            < param-name > serverName </ param-name >
            < param-value > http://localhost:9998 </ param-value >
        </ init-param >
    </ filter >
<!-- 请求参数ticket验证(ticket即子系统与CAS系统进行交互的凭证) -->
    < 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.Cas20ProxyReceivingTicketValidationFilter </ filter-class >
        < init-param >
cas服务端的地址
            < param-name > casServerUrlPrefix </ param-name >
            < param-value > http://localhost:9997/cas </ param-value >
        </ init-param >
        < init-param >
            < param-name > serverName </ param-name >
            < param-value > http://localhost:9998 </ param-value >子应用地址
        </ init-param >
    </ filter >
<!-- 该过滤器负责实现HttpServletRequest请求的包裹,
   比如允许开发者通过HttpServletRequest的getRemoteUser()方法获得SSO登录用户的登录名,可选配置。 -->
    < filter >
        < filter-name > CAS HttpServletRequest Wrapper Filter </ filter-name >
        < filter-class > org.jasig.cas.client.util.HttpServletRequestWrapperFilter </ filter-class >
    </ filter >
<!--
   该过滤器使得开发者可以通过org.jasig.cas.client.util.AssertionHolder来获取用户的登录名。
   比如AssertionHolder.getAssertion().getPrincipal().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 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 >
   < filter-mapping >
         < filter-name > CAS Assertion Thread Local Filter </ filter-name >
         < url-pattern > /* </ url-pattern >
   </ filter-mapping >
    < welcome-file-list >
        < welcome-file >
            index.jsp
        </ welcome-file >
    </ welcome-file-list >

注意:不同的子应用在配置wen.xml时候,ip要写对应的端口。这个xml是我的第一个子系统web配置,其余两个就是改了ticket验证、拦截单点登录、登出的子应用ip
再配置index.jsp,加上几个超链接,超链分别是其他子应用的jsp页面,这样就实现了登陆完这个应用再去访问其他的应用,而不用再去登录接口
index页面如下
<%@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>CAS Example Java Web App</h1>
<p>A sample web application that exercises the CAS protocol features via the Java CAS Client.</p>
<hr>
<a href="http://localhost:9998/hello1/index.jsp">9998hello1</a> 
<a href="http://localhost:9996/hello1/index.jsp">9996hello1</a> 
<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>
我解释下,我在本地9998的Tomcat部署了hello和hello1两个项目,在9996部署了hello1,cas服务端是9997,同时启动三个服务器,
地址栏:http://localhost:9998/hello/index.jsp,回去服务端认证并且带着地址,认证成功会有如下页面,然后点击另外两个超链,不用登陆,实现了不同系统间的单点登录。


总结:正常来讲,这些都是在Linux操作的,但是先力保在windows操作成功,其余的就是熟练运用Linux指令,搭建虚拟机环境。

写这篇文章本来是因为做shiro的项目,遇到要结合单点登录,就随机记录下来,因为很不容易。用到的项目和jar包、下载文件,会整理下放在下载地址里。


  • 6
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值