单点登录详解

  • Post author:
  • Post category:其他


单系统登录机制

1、http无状态协议

web应用采用browser/server架构,http作为通信协议。http是无状态协议,浏览器的每一次请求,服务器会独立处理,不与之前或之后的请求产生关联,这个过程用下图说明,三次请求/响应对之间没有任何联系


3c91a3bf-25d8-4b1f-8e4a-68535c51aaa8

但这也同时意味着,任何用户都能通过浏览器访问服务器资源,如果想保护服务器的某些资源,必须限制浏览器请求;要限制浏览器请求,必须鉴别浏览器请求,响应合法请求,忽略非法请求;要鉴别浏览器请求,必须清楚浏览器请求状态。既然http协议无状态,那就让服务器和浏览器共同维护一个状态吧!这就是会话机制

2、会话机制

浏览器第一次请求服务器,服务器创建一个会话,并将会话的id作为响应的一部分发送给浏览器,浏览器存储会话id,并在后续第二次和第三次请求中带上会话id,服务器取得请求中的会话id就知道是不是同一个用户了,这个过程用下图说明,后续请求与第一次请求产生了关联


8a9fb230-d506-4b19-b821-4001c68c4588

服务器在内存中保存会话对象,浏览器怎么保存会话id呢?你可能会想到两种方式

  1. 请求参数
  2. cookie

将会话id作为每一个请求的参数,服务器接收请求自然能解析参数获得会话id,并借此判断是否来自同一会话,很明显,这种方式不靠谱。那就浏览器自己来维护这个会话id吧,每次发送http请求时浏览器自动发送会话id,cookie机制正好用来做这件事。cookie是浏览器用来存储少量数据的一种机制,数据以”key/value“形式存储,浏览器发送http请求时自动附带cookie信息

tomcat会话机制当然也实现了cookie,访问tomcat服务器时,浏览器中可以看到一个名为“JSESSIONID”的cookie,这就是tomcat会话机制维护的会话id,使用了cookie的请求响应过程如下图


518293d9-64b2-459c-9d45-9f353c757d1f

3、登录状态

有了会话机制,登录状态就好明白了,我们假设浏览器第一次请求服务器需要输入用户名与密码验证身份,服务器拿到用户名密码去数据库比对,正确的话说明当前持有这个会话的用户是合法用户,应该将这个会话标记为“已授权”或者“已登录”等等之类的状态,既然是会话的状态,自然要保存在会话对象中,tomcat在会话对象中设置登录状态如下

1
2

HttpSession session = request.getSession();

session.setAttribute(


"isLogin"


,


true


);

用户再次访问时,tomcat在会话对象中查看登录状态

1
2

HttpSession session = request.getSession();

session.getAttribute(


"isLogin"


);

实现了登录状态的浏览器请求服务器模型如下图描述


70e396fa-1bf2-42f8-a504-ce20306e31fa

每次请求受保护资源时都会检查会话对象中的登录状态,只有 isLogin=true 的会话才能访问,登录机制因此而实现。

二、多系统的复杂性

web系统早已从久远的单系统发展成为如今由多系统组成的应用群,面对如此众多的系统,用户难道要一个一个登录、然后一个一个注销吗?就像下图描述的这样


6dfbb0b1-46c0-4945-a3bf-5f060fa80710

web系统由单系统发展成多系统组成的应用群,复杂性应该由系统内部承担,而不是用户。无论web系统内部多么复杂,对用户而言,都是一个统一的整体,也就是说,用户访问web系统的整个应用群与访问单个系统一样,登录/注销只要一次就够了


9fe14ab3-4254-447b-b850-0436e628c254

虽然单系统的登录解决方案很完美,但对于多系统应用群已经不再适用了,为什么呢?

单系统登录解决方案的核心是cookie,cookie携带会话id在浏览器与服务器之间维护会话状态。但cookie是有限制的,这个限制就是cookie的域(通常对应网站的域名),浏览器发送http请求时会自动携带与该域匹配的cookie,而不是所有cookie


4d58ccfa-0114-486d-bec2-c28f2f9eb513

既然这样,为什么不将web应用群中所有子系统的域名统一在一个顶级域名下,例如“*.baidu.com”,然后将它们的cookie域设置为“baidu.com”,这种做法理论上是可以的,甚至早期很多多系统登录就采用这种同域名共享cookie的方式。

然而,可行并不代表好,共享cookie的方式存在众多局限。首先,应用群域名得统一;其次,应用群各系统使用的技术(至少是web服务器)要相同,不然cookie的key值(tomcat为JSESSIONID)不同,无法维持会话,共享cookie的方式是无法实现跨语言技术平台登录的,比如java、php、.net系统之间;第三,cookie本身不安全。

因此,我们需要一种全新的登录方式来实现多系统应用群的登录,这就是单点登录

三、单点登录

什么是单点登录?单点登录全称Single Sign On(以下简称SSO),是指在多系统应用群中登录一个系统,便可在其他所有系统中得到授权而无需再次登录,包括单点登录与单点注销两部分

1、登录

相比于单系统登录,sso需要一个独立的认证中心,只有认证中心能接受用户的用户名密码等安全信息,其他系统不提供登录入口,只接受认证中心的间接授权。间接授权通过令牌实现,sso认证中心验证用户的用户名密码没问题,创建授权令牌,在接下来的跳转过程中,授权令牌作为参数发送给各个子系统,子系统拿到令牌,即得到了授权,可以借此创建局部会话,局部会话登录方式与单系统的登录方式相同。这个过程,也就是单点登录的原理,用下图说明

下面对上图简要描述

  1. 用户访问系统1的受保护资源,系统1发现用户未登录,跳转至sso认证中心,并将自己的地址作为参数
  2. sso认证中心发现用户未登录,将用户引导至登录页面
  3. 用户输入用户名密码提交登录申请
  4. sso认证中心校验用户信息,创建用户与sso认证中心之间的会话,称为全局会话,同时创建授权令牌
  5. sso认证中心带着令牌跳转会最初的请求地址(系统1)
  6. 系统1拿到令牌,去sso认证中心校验令牌是否有效
  7. sso认证中心校验令牌,返回有效,注册系统1
  8. 系统1使用该令牌创建与用户的会话,称为局部会话,返回受保护资源
  9. 用户访问系统2的受保护资源
  10. 系统2发现用户未登录,跳转至sso认证中心,并将自己的地址作为参数
  11. sso认证中心发现用户已登录,跳转回系统2的地址,并附上令牌
  12. 系统2拿到令牌,去sso认证中心校验令牌是否有效
  13. sso认证中心校验令牌,返回有效,注册系统2
  14. 系统2使用该令牌创建与用户的局部会话,返回受保护资源

用户登录成功之后,会与sso认证中心及各个子系统建立会话,用户与sso认证中心建立的会话称为全局会话,用户与各个子系统建立的会话称为局部会话,局部会话建立之后,用户访问子系统受保护资源将不再通过sso认证中心,全局会话与局部会话有如下约束关系

  1. 局部会话存在,全局会话一定存在
  2. 全局会话存在,局部会话不一定存在
  3. 全局会话销毁,局部会话必须销毁

你可以通过博客园、百度、csdn、淘宝等网站的登录过程加深对单点登录的理解,注意观察登录过程中的跳转url与参数

2、注销

单点登录自然也要单点注销,在一个子系统中注销,所有子系统的会话都将被销毁,用下面的图来说明


3b139d2e-0b83-4a69-b4f2-316adb8997ce

sso认证中心一直监听全局会话的状态,一旦全局会话销毁,监听器将通知所有注册系统执行注销操作

下面对上图简要说明

  1. 用户向系统1发起注销请求
  2. 系统1根据用户与系统1建立的会话id拿到令牌,向sso认证中心发起注销请求
  3. sso认证中心校验令牌有效,销毁全局会话,同时取出所有用此令牌注册的系统地址
  4. sso认证中心向所有注册系统发起注销请求
  5. 各注册系统接收sso认证中心的注销请求,销毁局部会话
  6. sso认证中心引导用户至登录页面

四、部署图

单点登录涉及sso认证中心与众子系统,子系统与sso认证中心需要通信以交换令牌、校验令牌及发起注销请求,因而子系统必须集成sso的客户端,sso认证中心则是sso服务端,整个单点登录过程实质是sso客户端与服务端通信的过程,用下图描述


fb29685c-487c-42b9-9ceb-6c7ee29e98c9

sso认证中心与sso客户端通信方式有多种,这里以简单好用的httpClient为例,web service、rpc、restful api都可以

五、实现

只是简要介绍下基于java的实现过程,不提供完整源码,明白了原理,我相信你们可以自己实现。sso采用客户端/服务端架构,我们先看sso-client与sso-server要实现的功能(下面:sso认证中心=sso-server)

sso-client

  1. 拦截子系统未登录用户请求,跳转至sso认证中心
  2. 接收并存储sso认证中心发送的令牌
  3. 与sso-server通信,校验令牌的有效性
  4. 建立局部会话
  5. 拦截用户注销请求,向sso认证中心发送注销请求
  6. 接收sso认证中心发出的注销请求,销毁局部会话

sso-server

  1. 验证用户的登录信息
  2. 创建全局会话
  3. 创建授权令牌
  4. 与sso-client通信发送令牌
  5. 校验sso-client令牌有效性
  6. 系统注册
  7. 接收sso-client注销请求,注销所有会话

接下来,我们按照原理来一步步实现sso吧!

1、sso-client拦截未登录请求

java拦截请求的方式有servlet、filter、listener三种方式,我们采用filter。在sso-client中新建LoginFilter.java类并实现Filter接口,在doFilter()方法中加入对未登录用户的拦截

1
2
3
4
5
6
7
8
9
10
11
12

public


void


doFilter(ServletRequest request, ServletResponse response, FilterChain chain)


throws


IOException, ServletException {




HttpServletRequest req = (HttpServletRequest) request;



HttpServletResponse res = (HttpServletResponse) response;



HttpSession session = req.getSession();




if


(session.getAttribute(


"isLogin"


)) {




chain.doFilter(request, response);



return


;



}



//跳转至sso认证中心



res.sendRedirect(


"sso-server-url-with-system-url"


);

}

2、sso-server拦截未登录请求

拦截从sso-client跳转至sso认证中心的未登录请求,跳转至登录页面,这个过程与sso-client完全一样

3、sso-server验证用户登录信息

用户在登录页面输入用户名密码,请求登录,sso认证中心校验用户信息,校验成功,将会话状态标记为“已登录”

1
2
3
4
5
6

@RequestMapping


(


"/login"


)

public


String login(String username, String password, HttpServletRequest req) {




this


.checkLoginInfo(username, password);



req.getSession().setAttribute(


"isLogin"


,


true


);



return


"success"


;

}

4、sso-server创建授权令牌

授权令牌是一串随机字符,以什么样的方式生成都没有关系,只要不重复、不易伪造即可,下面是一个例子

1

String token = UUID.randomUUID().toString();

5、sso-client取得令牌并校验

sso认证中心登录后,跳转回子系统并附上令牌,子系统(sso-client)取得令牌,然后去sso认证中心校验,在LoginFilter.java的doFilter()中添加几行

1
2
3
4
5
6
7
8
9
10
11

// 请求附带token参数

String token = req.getParameter(


"token"


);

if


(token !=


null


) {




// 去sso认证中心校验token



boolean


verifyResult =


this


.verify(


"sso-server-verify-url"


, token);



if


(!verifyResult) {




res.sendRedirect(


"sso-server-url"


);



return


;



}



chain.doFilter(request, response);

}

verify()方法使用httpClient实现,这里仅简略介绍,httpClient详细使用方法请参考官方文档

1
2

HttpPost httpPost =


new


HttpPost(


"sso-server-verify-url-with-token"


);

HttpResponse httpResponse = httpClient.execute(httpPost);

6、sso-server接收并处理校验令牌请求

用户在sso认证中心登录成功后,sso-server创建授权令牌并存储该令牌,所以,sso-server对令牌的校验就是去查找这个令牌是否存在以及是否过期,令牌校验成功后sso-server将发送校验请求的系统注册到sso认证中心(就是存储起来的意思)

令牌与注册系统地址通常存储在key-value数据库(如redis)中,redis可以为key设置有效时间也就是令牌的有效期。redis运行在内存中,速度非常快,正好sso-server不需要持久化任何数据。

令牌与注册系统地址可以用下图描述的结构存储在redis中,可能你会问,为什么要存储这些系统的地址?如果不存储,注销的时候就麻烦了,用户向sso认证中心提交注销请求,sso认证中心注销全局会话,但不知道哪些系统用此全局会话建立了自己的局部会话,也不知道要向哪些子系统发送注销请求注销局部会话


3b221593-f9c4-45af-a567-4937786993e8

7、sso-client校验令牌成功创建局部会话

令牌校验成功后,sso-client将当前局部会话标记为“已登录”,修改LoginFilter.java,添加几行

1
2
3

if


(verifyResult) {




session.setAttribute(


"isLogin"


,


true


);

}

sso-client还需将当前会话id与令牌绑定,表示这个会话的登录状态与令牌相关,此关系可以用java的hashmap保存,保存的数据用来处理sso认证中心发来的注销请求

8、注销过程

用户向子系统发送带有“logout”参数的请求(注销请求),sso-client拦截器拦截该请求,向sso认证中心发起注销请求

1
2
3
4

String logout = req.getParameter(


"logout"


);

if


(logout !=


null


) {




this


.ssoServer.logout(token);

}

sso认证中心也用同样的方式识别出sso-client的请求是注销请求(带有“logout”参数),sso认证中心注销全局会话

1
2
3
4
5
6
7
8

@RequestMapping


(


"/logout"


)

public


String logout(HttpServletRequest req) {




HttpSession session = req.getSession();



if


(session !=


null


) {




session.invalidate();


//触发LogoutListener



}



return


"redirect:/"


;

}

sso认证中心有一个全局会话的监听器,一旦全局会话注销,将通知所有注册系统注销

1
2
3
4
5
6
7
8

public


class


LogoutListener


implements


HttpSessionListener {




@Override



public


void


sessionCreated(HttpSessionEvent event) {}



@Override



public


void


sessionDestroyed(HttpSessionEvent event) {




//通过httpClient向所有注册系统发送注销请求



}

}





1.1服务端配置

1.1.1环境说明

  • Windows10 64位
  • jdk1.8.0_05
  • apache-tomcat-8.0.47-windows-x64
  • 会使用到的:cas-server-webapp-4.0.0.war、cas-client-core-3.2.1.jar、commons-logging、cas-server-support-jdbc-4.0.0.jar
  • 确保本地jdk环境已经搭建好

1.1.2修改hosts文件

由于在本地测试的时候,服务端和客户端默认的ip地址都是127.0.0.1,为了方便区分,所以需要为了服务端和客户端配置不同的域名加以区分。

编辑文件 C:\Windows\System32\drivers\etc\hosts 在文件末端添加下面两条信息:

  • server.jix.com  =>> 对应部署cas server的tomcat,这个虚拟域名还用于服务端证书生成
  • client1.jix.com  =>>  对应部署client1客户端应用的tomcat
  • client2.jix.com =>>  对应部署client2客户端应用的tomcat

【由于CAS是基于HTTPS协议,所以需要配置服务端的tomcat,使之支持SSL安全协议访问】

1.1.3配置https协议(安全证书配置)

1.打开cmd命令窗口

2.生成证书,在cmd窗口输入以下命令:

keytool -genkey -alias ssodemo -keyalg RSA -keysize 1024 -keypass jixsso -validity 365 -keystore F:\jix\sso.keystore -storepass jixsso
 


[说明]:-alias后面的别名可以自定义,-keypass指定证书密钥库的密码, -storepass和前面keypass密码相同,否则下面tomcat 配置https 会访问失败 -keystore指定证书的位置,这里指定放在F盘的jix目录,密钥库名称可以自定义..这里是jixsso.keystore

3.命令输入完成,回车之后,会提示你输入一些资料,见下图:

 

证书命令图2.1

 



注意

】:第一个让你输入的“您的名字与姓氏是什么”,请必须输入在C:\Windows\System32\drivers\etc\hosts文件中加入的服务端的域名.我这里也就是server.jix.com,为何这么做?首先cas只能通过域名来访问,不能通过ip访问,同时上方是生成证书,所以要求比较严格,所以如果不这么做的话,在完成最终配置之后,cas也可以正常访问,访问一个客户端应用虽然能进入cas验证首页,但是,当输入信息正确后,cas在回调转入你想访问的客户端应用的时候,会出现

No subject alternative names present

错误异常信息

,这个错误也就是在上面输入的第一个问题答案不是域名导致、或者与hosts文件配置的不一致导致

4.导出证书:

在cmd窗口继续输入以下命令,导出证书

keytool -export -alias ssodemo -keystore F:\jix\sso.keystore -file F:\jix\sso.crt -storepass jixsso

【说明】:-alias后面的名称要与生成证书的命令里面的alias的名称一致. –keystore后面指定证书存放的位置,这里我放在F盘jix目录,同时证书名称要与【生成证书】对应的命令里的keystore名称一致.这里是sso.keystore,-file后面才crt路径,我也指定在F盘jix目录. –storepass的证书密码要与上面输入的密码一致.

如下图所示:

证书命令图2.2
 
 

下面是F盘jix目录下生成的crt文件:

证书位置图2.3

 

5.客户端导入证书

在cmd窗口输入命令 (以管理员方式运行)

keytool -import -keystore "%JAVA_HOME%\../jre8\lib\security\cacerts" -file F:\jix\sso.crt -alias ssodemo3
【说明】:-file指定证书的位置,也就是上一步导出证书的位置,即F:\jix\sso.crt 命令中指定了JAVA_HOME,意思是将证书导入到客户端证书库,也就是jdk证书库中.因为客户端应用运行在本地,需要jdk的支持。
回车之后,会让你输入密钥库口令,注意,这里的密码必须要输入changeit,不能输入上面指定的密码jixsso,切记,否则导入客户端证书会有问题,如果是多台机器演示,需要在每一台客户端导入该证书,步骤都是一样的。当看到提示“是否信任此证书”,输入y回车即可,见下图:(说明,命令中的-alias后面的别名可以自定义,如果出现【证书未导入,别名<***>已经存在】的错误,该意思是说客户端的密钥库中已经存在该别名证书了,重新指定其他别名即可.

证书命令图2.4

 
点击回车可以看到证书已添加到秘钥库中


至此,CAS所需的证书环境,已经配置好。

下面,开始我们的CAS服务、Tomcat、以及多客户端的配置及测试访问。

1.1.4部署CAS-Server相关的Tomcat

1. 配置HTTPS

解压apache-tomcat-8.0.47-windows-x64.zip,我本地路径为E:\Tomcat-anzhuangbao\apache-tomcat-8.0.47-windows-x64\apache-tomcat-8.0.47-server,编辑E:\Tomcat-anzhuangbao\apache-tomcat-8.0.47-windows-x64\apache-tomcat-8.0.47-server\conf\server.xml,找到下面片段:

<!–

<Connector executor=”tomcatThreadPool”

port=”8080″ protocol=”HTTP/1.1″

connectionTimeout=”20000″

redirectPort=”8443″ />

–>

去掉注释,修改成:

<Connector port=”8443″ protocol=”org.apache.coyote.http11.Http11Protocol”

maxThreads=”150″ SSLEnabled=”true” scheme=”https” secure=”true”

keystoreFile=” F:\jix\sso.keystore ” keystorePass=”jixsso”

clientAuth=”false” sslProtocol=”TLS” />

其中,keystoreFile就是创建证书的路径,keystorePass就是创建证书的密码

2. 验证HTTPS配置

其他按照默认配置不作修改,双击E:\Tomcat-anzhuangbao\apache-tomcat-8.0.47-windows-x64\apache-tomcat-8.0.47-server\bin\startup.bat启动tomcat 验证https是否配置成功,我本地使用谷歌浏览器访问,在地址栏输入

https://server.jix.com:8443/出现下面画面,其实这就表明cas服务端tomcat的https配置是没有问题了.

服务端登录图2.5

点击高级,然后继续访问,将会出现下面tomcat默认首页.tomcat已经支持https协议访问了,一切ok!

Tomcat页面图2.7

3. 部署CAS-Server

CAS-Server 下载地址:

http://www.jasig.org/cas/download

本文以cas-server-webapp-4.0.0.rar为例,解压提取cas-server-webapp-4.0.0.war文件,把改文件copy到E:\Tomcat-anzhuangbao\apache-tomcat-8.0.47-windows-x64\apache-tomcat-8.0.47-server\webapps目下,并重命名为:cas.war.

启动tomcat,在浏览器地址栏输入:https://server.jix.com:8443/cas ,回车,出现CAS服务端的登录验证首页:

Cas登录图2.8

【说明】:此时,CAS只是单独运行,至于登录的用户名和密码是什么,请查看:

E:\Tomcat-anzhuangbao\apache-tomcat-8.0.47-windows-x64\apache-tomcat-8.0.47-server\webapps\cas\WEB-INF\deployerConfigContext.xml文件中有这样一段

配置:

<beanid=”primaryAuthenticationHandler”

class=”org.jasig.cas.authentication.AcceptUsersAuthenticationHandler”>

<property name=”users”>

<map>

<entry key=”casuser” value=”Mellon”/>

</map>

</property>

</bean>

这个配置是默认静态配置用户名和密码,那就在浏览器的CAS服务的登陆框中输入用户名casuser和密码Mellon,登录看看效果,就会出现验证成功的页面,如下图。你也可以在文件中自己配置自己的用户名和密码。

登录成功图2.9

看到上述页面表示CAS-Server已经部署成功。

1.1.5 CAS与数据库交互

【说明】:我本地使用的是oracle数据库。

1、,需要将几个jar文件,放到CAS服务的lib目录下,我本地使用的jar版本分别是commons-dbcp-1.2.1.jar、commons-pool.jar、cas-server-support-jdbc-4.0.0.jar、ojdbc6.jar,这4个缺一不可。将这4个jar放到E:\Tomcat-anzhuangbao\apache-tomcat-8.0.47-windows-x64\apache-tomcat-8.0.47-server\webapps\cas\WEB-INF\lib目录下。

2、修改配置,支持mysql数据库交互验证

编辑E:\Tomcat-anzhuangbao\apache-tomcat-8.0.47-windows-x64\apache-tomcat-8.0.47-server\webapps\cas\WEB-INF\ deployerConfigContext.xml文件,你会看到有这样一段配置:

Cas服务端配置图2.10

注释掉第二个entry配置,最终配置如下:

<constructor-arg>

<map>

<entrykey-ref=”proxyAuthenticationHandler”value-ref=”proxyPrincipalResolver” />

<!– 注释这个–>

<!–<entrykey-ref=”primaryAuthenticationHandler”value-ref=”primaryPrincipalResolver” />–>

<!– key-ref指定自己的本地数据库访问 –>

<entry key-ref=”dbAuthHandler”value-ref=”primaryPrincipalResolver”/>

</map>

</constructor-arg>

上述配置截图:

Cas服务端配置图2.11

然后再在这个xml中新加入2个bean配置,如下:

<!– 指定dbcp数据源–>

<bean id=”dataSource” class=”org.apache.commons.dbcp.BasicDataSource”>

<property name=”driverClassName”value=”oracle.jdbc.driver.OracleDriver”></property>

<property name=”url” value=”jdbc:oracle:thin:@10.65.106.71:1521:orcl”></property>

<property name=”username” value=”dass_up”></property>

<property name=”password” value=”123″></property>

</bean>

<!– 访问远程数据库 –>

<beanid=”dbAuthHandler”class=”org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler”>

<property name=”dataSource”ref=”dataSource”></property>

<property name=”sql”value=”select password fromt_system_user where username=?”></property>

</bean>

要说明的是,红色标注的内容,我想大家都能看的明白,就是指定数据库驱动和连接信息。其中,sql语句的意思就是,根据用户名获取密码,CAS会根据你页面输入的用户名获取该用户密码,和你输入的密码进行校验,来判断输入是否正确。Sql中的表换成远程数据库的表即可。只要根据用户名查询密码即可。

以上配置截图:

Cas服务端配置图2.12


至此,CAS与数据库交互验证的配置已经配置完成

,你可以重新访问cas,输入数据库中存在的用户名和密码,来看看效果如何~如果登录成功,说明配置无误。否则,请耐心检查配置是否有问题,jar包是否缺少。

现在,CAS已经支持数据库交互验证了,服务端tomcat也支持HTTPS协议访问,现在,我们来搭建客户端,实现多个客户端的单点登录。这里,我本地只使用2个tomcat客户端来测试,其实已经满足单点登录的要求了,至少2个应用。

1.2 CAS客户端配置

1.2.1 部署CAS客户端相关的Tomcat

首先,客户端应用是要和CAS服务端进行交互的,所以这里需要jar文件,放在客户端应用的lib目录下。分别是:cas-client-core-3.2.1.jar、commons-logging.jar

这里呢,我就直接使用tomcat默认自带的 webapps\examples 作为测试的简单web项目。我就不去另写一个web测试的demo了。

既然需要2个客户端应用,则需要2个tomcat做为客户端服务器,所以,我本地解压了2份tomcat,作为客户端服务器,并重新命名,本地路径分别为:E:\Tomcat-anzhuangbao\apache-tomcat-8.0.47-windows-x64\apache-tomcat-8.0.47- client1和E:\Tomcat-anzhuangbao\apache-tomcat-8.0.47-windows-x64\apache-tomcat-8.0.47– client2

首先,将上面2个jar分别放到E:\Tomcat-anzhuangbao\apache-tomcat-8.0.47-windows-x64\apache-tomcat-8.0.47- client1\webapps\examples\WEB-INF\lib目录

和E:\Tomcat-anzhuangbao\apache-tomcat-8.0.47-windows-x64\apache-tomcat-8.0.47– client2\webapps\examples\WEB-INF\lib目录


1、  配置apache-tomcat-7.0.57-client1客户端1:

修改tomcat的启动端口:

编辑E:\Tomcat-anzhuangbao\apache-tomcat-8.0.47-windows-x64\apache-tomcat-8.0.47- client1\conf\server.xml文件,找到如下2处内容:

<Connector port=”8080″protocol=”HTTP/1.1″

connectionTimeout=”20000″

redirectPort=”8443″ />

这里请将port=”8080″修改成其他4位端口,不能和CAS服务端的tomcat相同,否则,在同一台机器上测试会出现端口占用的错误,我修改成18080,如果是在不同的机器上,则不需要配置这些。

<Connector port=”8009″protocol=”AJP/1.3″ redirectPort=”8443″ />

这里请将port=”8009″修改成其他4位端口,不能和CAS服务端相同.我修改成18009

好,启动这个tomcat,即运行E:\Tomcat-anzhuangbao\apache-tomcat-8.0.47-windows-x64\apache-tomcat-8.0.47- client1\bin\startup.bat,如果启动窗口中没有出现错误,说明端口配置无误。请记住你配置的端口号。浏览器输入

http://client1.jix.com:18080/examples/servlets/

,请注意红色部分域名,就是本文档一开始需要配置的C:\Windows\System32\drivers\etc\hosts的域名,用于不同的客户端域名访问,回车:

客户端登录图2.13

看到上述界面表示apache-tomcat-8.0.47- client1的基本安装配置已经成功。

接下来需要配置最重要的内容,让客户端应用和CAS服务连接:

编辑E:\Tomcat-anzhuangbao\apache-tomcat-8.0.47-windows-x64\apache-tomcat-8.0.47- client1\webapps\examples\WEB-INF\web.xml,在最下面加入如下配置:

<!– 用于单点退出,该过滤器用于实现单点登出功能,可选配置–>

<listener>                                           <listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>

</listener>

<!–该过滤器用于实现单点登出功能,可选配置 –>

<filter>

<filter-name>CAS Single Sign OutFilter</filter-name>

<filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class>

</filter>

<filter-mapping>

<filter-name>CASSingle Sign Out Filter</filter-name>

<url-pattern>/*</url-pattern>

</filter-mapping>

<filter>

<filter-name>CASFilter</filter-name>

<filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>

<init-param>

<param-name>casServerLoginUrl</param-name>

<param-value>https://server.jix.com:8443/cas/login</param-value>

</init-param>

<init-param>

<param-name>serverName</param-name>

<param-value>http://client1.jix.com:18080</param-value>

</init-param>

</filter>

<filter-mapping>

<filter-name>CASFilter</filter-name>

<url-pattern>/*</url-pattern>

</filter-mapping>

        <!-- 该过滤器负责对Ticket的校验工作,必须启用它 -->

<filter>

<filter-name>CAS Validation Filter</filter-name>

<filter-class>

org.jasig.cas.client.validation.Cas10TicketValidationFilter</filter-class>

<init-param>

<param-name>casServerUrlPrefix</param-name>

<param-value>https://server.jix.com:8443/cas</param-value>

</init-param>

<init-param>

<param-name>serverName</param-name>

<param-value>http://client1.jix.com:18080</param-value>

</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()。
-->

<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>

配置完成后,启动CAS服务端tomcat,再启动该客户端1的tomcat,在浏览器访问:


http://client1.jix.com:18080/examples/servlets/servlet/HelloWorldExample

看看是否跳转到了CAS认证界面,回车之后,会出现如下图:

Cas服务端登录图2.14

由于你没有登录CAS认证系统,CAS认证系统拦截到你访问的客户端应用,首先进入到认证系统登录界面,同时URL后面加上你想访问的地址信息,当你登录成功后,CAS服务会转向到你刚刚访问的地址,也就是


http://client1.jix.com:18080/examples/servlets/servlet/HelloWorldExample

转向到这个地址之后,浏览器会显示如下内容:

客户端验证成功图2.15

上面这个内容,显示的就是你访问tomcat中的examples项目的一个servlet的返回结果。

这里,你会发现浏览器地址栏多了一个内容,即多了一个jsessionid参数,这个就是CAS认证的原理所在,使用的是COOKIE机制。

1.2.2 配置CAS客户端2

配置与上面的客户端配置步骤相同,其中需要注意的就是,这第二个客户端的tomcat端口要与上面的客户端和CAS服务端的端口要不一样,否则出现端口占用的错误。

主要配置如下:

客户端配置图2.16

Port修改成28080

Port修改成28009

修改编辑E:\Tomcat-anzhuangbao\apache-tomcat-8.0.47-windows-x64\apache-tomcat-8.0.47 – client2\webapps\examples\WEB-INF\web.xml文件,加入的内容就是上面在第一个客户端的web.xml内容一致,只不过需要修改2处内容,就是几个url地址, 最终的配置如下:

<!– 用于单点退出,该过滤器用于实现单点登出功能,可选配置–>

<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>

</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.jix.com:8443/cas/login</param-value>

</init-param>

<init-param>

<param-name>serverName</param-name>

<param-value>http://client2.jix.com:28080</param-value>

</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.Cas10TicketValidationFilter</filter-class>

<init-param>

<param-name>casServerUrlPrefix</param-name>

<param-value>https://server.jix.com:8443/cas</param-value>

</init-param>

<init-param>

<param-name>serverName</param-name>

<param-value>http://client2.jix.com:28080</param-value>

</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()。
-->

<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>

1.2.3 测试验证SSO

至此,2个客户端也已经配置完毕,启动配置好的三个tomcat分别为:CAS服务端tomcat、2个客户端tomcat

我本地路径分别为:

服务端tomcat:E:\Tomcat-anzhuangbao\apache-tomcat-8.0.47-windows-x64\apache-tomcat-8.0.47-server

客户端1:E:\Tomcat-anzhuangbao\apache-tomcat-8.0.47-windows-x64\apache-tomcat-8.0.47 – client1

客户端2:E:\Tomcat-anzhuangbao\apache-tomcat-8.0.47-windows-x64\apache-tomcat-8.0.47 – client2

访问客户端1—-> 跳转到cas server 验证 —-> 显示客户端1的应用 —->新开选项卡访问客户端2 —-> 显示客户端2应用 —-> 注销cas server —-> 打开客户端1/客户端2 —-> 重新跳转到cas server 验证.

下面截图,根据上面所示进行测试,看看是否与上面说的流程一致:

首先,打开谷歌浏览器,地址栏输入:


http://client1.jix.com:18080/examples/servlets/servlet/HelloWorldExample

回车,将会出现CAS认证界面:

服务端登录图2.17

输入用户名和密码,登录成功后,显示的界面:

客户端1登录成功图2.18

重新打开一个选项卡,地址栏输入


http://client2.jix.com:28080/examples/servlets/servlet/HelloWorldExample

回车,将直接显示客户端2界面,没有重新登录,浏览器显示界面:

客户端2登录图2.19

根据上面显示的界面,按照普通想逻辑,当访问客户端2的时候,应该会被CAS拦截,转到CAS认证服务的界面,但是结果却直接显示客户端2的界面,原因就是因为你在访问客户端1的时候已经登录认证过了,CAS会在你浏览器中注入COOKIE,记录你的认证凭证,如果你的浏览器没有关闭或者退出的话,当你访问客户端2应用的时候,CAS检测到认证的凭证,所以,就直接显示了客户端2的界面。


这里,其实就已经说明,CAS单点登录系统已经搭建完毕!运行一切正常!



下面,我们新打开一个选项卡(也可在当前页面的地址栏输入),在浏览器地址栏中输入


https://server.jix.com:8443/cas/logout

回车显示:

Cas退出成功图2.20

上述表示 认证注销成功,此时如果再访问 :


http://client1.jix.com:18080/examples/servlets/servlet/HelloWorldExample


http://client2.jix.com:28080/examples/servlets/servlet/HelloWorldExample

都将会跳转到CAS服务重新进行认证。

到此,SSO之CAS单点登录系统已经搭建完毕!