单点登录(Single Sign On , 简称 SSO )是目前比较流行的服务于企业业务整合的解决方案之一, SSO 使得在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。
CAS(Central Authentication Service)是一款不错的针对 Web 应用的单点登录框架。
CAS的下载地址:http://www.jasig.org/cas/download 下载服务端cas-server-3.5.2-release.zip和客户端cas-client-3.2.1-release.zip
我们用3个web工程为例子演示CAS的使用。CASServer是CAS服务端,提供统一的登录页面。AA和BB分别是两个业务工程,在没登录之前,我们访问AA或BB都会跳到CASServer的登录页面。登录之后可以在AA和BB之间任意切换。退出之后必须得重新登录。
- 服务端配置
解压cas-server-3.5.2-release.zip后进入目录,可以看到cas-server-webapp,我们在这个工程的基础上新建我们的工程CASServer。这是个maven工程,配置文件和源码里面都有,jar包可以从cas-server-3.5.2\modules\cas-server-webapp-3.5.2.war里面拷过去。
取消https配置,这个工程默认是支持https,必须手工取消,否则logout不能通过http方式生效。取消的话改动两个地方
WEB-INF/deployerConfigContext.xml增加p:requireSecure="false"
<bean class="org.jasig.cas.authentication.handler.support.HttpBasedServiceCredentialsAuthenticationHandler" p:httpClient-ref="httpClient" p:requireSecure="false"/>
WEB-INF/spring-configuration/ticketGrantingTicketCookieGenerator.xml修改p:cookieSecure="false"
<bean id="ticketGrantingTicketCookieGenerator" class="org.jasig.cas.web.support.CookieRetrievingCookieGenerator" p:cookieSecure="false"
整个工程的配置文件很多,其实我们只要关注/WEB-INF/deployerConfigContext.xml这一个主要配置文件
里面定义了一个id为authenticationManager的bean,负责基于提供的凭证信息进行用户认证。
里面有两个属性credentialsToPrincipalResolvers和authenticationHandlers
credentialsToPrincipalResolvers用来将传递进来的安全实体信息转换成完整的org.jasig.cas.authentication.principal.Principal
authenticationHandlers用于用户认证。
我们可以实现自己的authenticationManager和authenticationHandlers,并配置到deployerConfigContext.xml
编写MyAuthenticationHandler,提供了一个很简单的验证功能,只要输入用户名aa密码123就算验证通过
public class MyAuthenticationHandler extends AbstractUsernamePasswordAuthenticationHandler { @Override protected boolean authenticateUsernamePasswordInternal( UsernamePasswordCredentials credentials) throws AuthenticationException { String username = credentials.getUsername(); String password = credentials.getPassword(); if(username.equals("aa")&&password.equals("123")){ return true; } return false; } }
编写MyAuthenticationManagerImpl,核心是SimplePrincipal principalTas = new SimplePrincipal("aaaaaaaaaaaaaa");这一行。封装一个SimplePrincipal 对象给客户端。这里是一个字符串,实际过程中可以是一个代表权限的json字符串。
public class MyAuthenticationManagerImpl extends AbstractAuthenticationManager { /** An array of authentication handlers. */ @NotNull @Size(min = 1) private List<AuthenticationHandler> authenticationHandlers; /** An array of CredentialsToPrincipalResolvers. */ @NotNull @Size(min = 1) private List<CredentialsToPrincipalResolver> credentialsToPrincipalResolvers; @Override protected Pair<AuthenticationHandler, Principal> authenticateAndObtainPrincipal( Credentials credentials) throws AuthenticationException { boolean foundSupported = false; boolean authenticated = false; AuthenticationHandler authenticatedClass = null; for (final AuthenticationHandler authenticationHandler : this.authenticationHandlers) { if (authenticationHandler.supports(credentials)) { foundSupported = true; if (!authenticationHandler.authenticate(credentials)) { if (log.isInfoEnabled()) { log.info("AuthenticationHandler: " + authenticationHandler.getClass().getName() + " failed to authenticate the user which provided the following credentials: " + credentials.toString()); } } else { if (log.isInfoEnabled()) { log.info("AuthenticationHandler: " + authenticationHandler.getClass().getName() + " successfully authenticated the user which provided the following credentials: " + credentials.toString()); } authenticatedClass = authenticationHandler; authenticated = true; break; } } } if (!authenticated) { if (foundSupported) { throw BadCredentialsAuthenticationException.ERROR; } throw UnsupportedCredentialsException.ERROR; } foundSupported = false; for (final CredentialsToPrincipalResolver credentialsToPrincipalResolver : this.credentialsToPrincipalResolvers) { if (credentialsToPrincipalResolver.supports(credentials)) { final Principal principal = credentialsToPrincipalResolver .resolvePrincipal(credentials); foundSupported = true; if (principal != null) { SimplePrincipal principalTas = new SimplePrincipal("aaaaaaaaaaaaaa"); return new Pair<AuthenticationHandler, Principal>( authenticatedClass, principalTas); } } } if (foundSupported) { if (log.isDebugEnabled()) { log.debug("CredentialsToPrincipalResolver found but no principal returned."); } throw BadCredentialsAuthenticationException.ERROR; } log.error("CredentialsToPrincipalResolver not found for " + credentials.getClass().getName()); throw UnsupportedCredentialsException.ERROR; } public List<AuthenticationHandler> getAuthenticationHandlers() { return authenticationHandlers; } public void setAuthenticationHandlers( List<AuthenticationHandler> authenticationHandlers) { this.authenticationHandlers = authenticationHandlers; } public List<CredentialsToPrincipalResolver> getCredentialsToPrincipalResolvers() { return credentialsToPrincipalResolvers; } public void setCredentialsToPrincipalResolvers( List<CredentialsToPrincipalResolver> credentialsToPrincipalResolvers) { this.credentialsToPrincipalResolvers = credentialsToPrincipalResolvers; } }
自此服务端配置完成,可以访问http://127.0.0.1/CASServer/login,用用户名aa密码123登陆成功说明一切正常。
- 客户端配置
新建web工程AA,可以引入上个工程里面所有的jar包。
修改web.xml
<?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:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <display-name>AA</display-name> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> <context-param> <param-name>contextConfigLocation</param-name> <param-value> classpath:applicationContext*.xml </param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- CAS config begin --> <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 Authentication Filter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> <init-param> <param-name>targetBeanName</param-name> <param-value>casAuthenticationFilter</param-value> </init-param> </filter> <filter-mapping> <filter-name>CAS Authentication Filter</filter-name> <url-pattern>*.jsp</url-pattern> </filter-mapping> <filter> <filter-name>CAS Validation Filter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> <init-param> <param-name>targetBeanName</param-name> <param-value>casValidationFilter</param-value> </init-param> </filter> <filter-mapping> <filter-name>CAS Validation Filter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <filter> <filter-name>CAS HttpServletRequestWrapperFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> <init-param> <param-name>targetBeanName</param-name> <param-value>casHttpServletRequestWrapperFilter</param-value> </init-param> </filter> <filter-mapping> <filter-name>CAS HttpServletRequestWrapperFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <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>
里面引入了spring的支持,spring的配置文件applicationContext-cas.xml。还有cas客户端相关的一些filter。
这些filter有org.jasig.cas.client.session.SingleSignOutFilter,org.jasig.cas.client.authentication.AuthenticationFilter,org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter,org.jasig.cas.client.util.HttpServletRequestWrapperFilter,org.jasig.cas.client.util.AssertionThreadLocalFilter。
关于各个filter的具体作用可以参考这篇文章http://blog.csdn.net/yuwenruli/article/details/6600032
applicationContext-cas.xml配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <bean id="casAuthenticationFilter" class="org.jasig.cas.client.authentication.AuthenticationFilter"> <property name="casServerLoginUrl" value="http://127.0.0.1/CASServer/login" /> <property name="serverName" value="127.0.0.1" /> </bean> <bean id="casValidationFilter" class="org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter"> <property name="ticketValidator"> <ref bean="Cas20ServiceTicketValidator" /> </property> <property name="useSession" value="true" /> <property name="serverName" value="127.0.0.1" /> <property name="redirectAfterValidation" value="true" /> </bean> <bean id="Cas20ServiceTicketValidator" class="org.jasig.cas.client.validation.Cas20ServiceTicketValidator"> <constructor-arg index="0" value="http://127.0.0.1/CASServer" /> </bean> <bean id="casHttpServletRequestWrapperFilter" class="org.jasig.cas.client.util.HttpServletRequestWrapperFilter" /> </beans>
主要将casServerLoginUrl改成cas服务端的地址,serverName改成当前业务应用发布的地址。
新建测试主页面index.jsp,加入
<%=request.getUserPrincipal().getName() %> <a href="http://127.0.0.1/CASServer/logout">logout</a>
用同样的方法创建web工程BB。
- 测试
发布3个工程到本地tocmat。
第一次访问http://127.0.0.1/AA或http://127.0.0.1/BB 都会跳到CASServer的登陆页面
登陆成功后跳到相应工程的index页面,以后可以在AA和BB两个工程间自由切换。logout后必须重新登陆。
相关推荐
集成框架中使用CAS实现单点登录技术方案.pdf
集成cas实现单点登录认证.zip
1 单点登录总体解决方案 2 CAS原理和协议 3 CAS安全性 4 CAS工作模式 5 系统设计方案 6 CAS关键技术 6.1 域名规范 6.2 中文用户登录提交时乱码 ...7 单点登录风险 ...9.3 TOMCAT中使用CAS实现单点登录LDAP方式
java cas实现单点登录文档 仅供参考
NULL 博文链接:https://ajita.iteye.com/blog/2023940
用cas实现mantis单点登录和登出,详细讲了mantis的程序修改用cas实现SSO,已经在实际中应用,非常有帮助
cas实现单点登录服务端及客户端,压缩包内提供三个工程,一个cas服务器,两个测试客户端,可同时部署到一个tomcat下,或者分开部署。端口号默认使用的8000
CAS实现sso单点登录原理,可以方便技术人员理解
CAS(Central Authentication Service)是一款不错的针对 Web 应用的单点登录框架,本文介绍了 CAS 的原理、协议、在 Tomcat 中的配置和使用,对于采用 CAS 实现轻量级单点登录解决方案的入门读者具有一定指导作用。
CAS单点登录CAS单点登录CAS单点登录CAS单点登录
基于Java中CAS的单点登录,有服务端的所有源码,将tomcat目录下的所有资源直接拷到Tomcat服务中间件的webapp目录下,阅读tomcat-webapp中的read.txt文档,查看使用说明,适用于第一次开发CAS单点登录的同学们,简单...
cas 单点登录 解决方案.
CAS整合LDAP实现单点登录的原理及部署学习笔记,cas实现单点登录,ldap负责账户管理
cas实现单点登录
用cas实现单点登录 构造实现 内外分离的系统 更高的提高系统的安全性
使用 CAS 在 Tomcat 中实现单点登录
Tomcat 下用cas实现单点登录,实现系统整合。
资源列表(1:cas CAS Server,2:Cas_Client_One 授权系统,3:graduationDesign 用户组织管理系统,4:CAS单点登录论文.doc,5:CAS单点登录文献综述.doc,6:基于CAS的用户管理单点登录门户系统ppt.ppt)
shiro+cas实现单点登录 示例代码,送源码分析url:http://note.youdao.com/noteshare?id=a83380ee8fc6913162042e865689844e&sub=CD905CCCE4134A159326DC2DFC1AF268
本文在已有的禅道集成CAS单点登录的客户端插件基础上进行的修改,因原有插件在我们的系统上调试无法成功,做了一些定制,环境如下: 1. CAS server 版本:4.0.0 2. 禅道开源版本: 9.6.3 3. 禅道CAS client 插件版本...