最近在研究sso单点登录的问题,研究了网上许多案例以及代码,发现总是有很大的差别,最后通过官网下载,才发现cas3 与 cas 4 的配置存在区别,这就是差别很大的原因了。
官网地址如下: https://www.apereo.org/search/node/cas
下面只针对cas4进行整理吧,因为cas4 相对于cas3 来说,是有增无减了。
1.下载
地址http://downloads.jasig.org/
cas-server-4.0.0-release.tar.gz
cas-client-3.3.3-release.tar.gz
2.配置Sever端
解压cas-server-4.0.0,将其中module/cas-server-webapp-4.0.0.war复制到Tomcat的webapps目录下,重命名为cas.war,启动Tomcat解开压缩
启动tomcat
http://localhost:8080/cas,进入登录页面。
默认用户为casuser/Mellon,登录成功即启动正常,cas3的无默认用户,只需用户名密码一直即可。
2.1设置利用数据库来验证用户
需依赖:c3p0-0.9.1.2.jar,mysql-connector-java-5.1.21.jar,cas-server-support-jdbc-4.0.0.jar,cas-server-support-ldap-4.0.0.jar
修改 deployerConfigContext.xml
1)更换验证方式 <!-- <bean id="primaryAuthenticationHandler" class="org.jasig.cas.authentication.AcceptUsersAuthenticationHandler"> <property name="users"> <map> <entry key="casuser" value="Mellon"/> </map> </property> </bean> --> <!-- Define the DB Connection --> <bean id="dbAuthHandler" class="org.jasig.cas.authentication.handler.DefaultPasswordEncoder" p:dataSource-ref="dataSource" p:sql="select passwd from users where name=?" /> <!-- 使用dataSource--> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" p:driverClass="com.mysql.jdbc.Driver" p:jdbcUrl="jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf-8" p:user="root" p:password="123" />
2)更换handler验证方式 <bean id="authenticationManager" class="org.jasig.cas.authentication.PolicyBasedAuthenticationManager"> <constructor-arg> <map> <entry key-ref="proxyAuthenticationHandler" value-ref="proxyPrincipalResolver" /> <entry key-ref="dbAuthHandler" value-ref="primaryPrincipalResolver" /> <!--本来使用primaryAuthenticationHandler,现在使用dbAuthHandler --> <!-- <entry key-ref="primaryAuthenticationHandler" value-ref="primaryPrincipalResolver" /> --> </map> </constructor-arg>
注释了原来的默认用户,使用数据库替代,新建数据库test,暂时没有使用md5加密,数据库test的users表直接设置passwd和name即可
3)使用md5加密,密码校验类自定义实现 <bean id="dbAuthHandler" class="com.test.cas.MyQueryDatabaseAuthenticationHandler" p:dataSource-ref="dataSource" p:sql="select passwd from users where name=?" p:passwordEncoder-ref="passwordEncoder"/> <bean id="passwordEncoder" class="org.jasig.cas.authentication.handler.DefaultPasswordEncoder" c:encodingAlgorithm="md5" p:characterEncoding="UTF-8" />
4)密码校验类自定义实现 public class MyQueryDatabaseAuthenticationHandler extends AbstractJdbcUsernamePasswordAuthenticationHandler{ @NotNull private String sql; @Override protected HandlerResult authenticateUsernamePasswordInternal(UsernamePasswordCredential credential)throws GeneralSecurityException, PreventedException { final String username = credential.getUsername(); final String encryptedPassword = this.getPasswordEncoder().encode(credential.getPassword()+"{"+username+"}"); try { final String dbPassword = getJdbcTemplate().queryForObject(this.sql, String.class, username); if (!dbPassword.equals(encryptedPassword)) { throw new FailedLoginException("Password does not match value on record."); } } catch (final IncorrectResultSizeDataAccessException e) { if (e.getActualSize() == 0) { throw new AccountNotFoundException(username + " not found with SQL query"); } else { throw new FailedLoginException("Multiple records found for " + username); } } catch (final DataAccessException e) { throw new PreventedException("SQL exception while executing query for " + username, e); } return createHandlerResult(credential, new SimplePrincipal(username), null); } public void setSql(final String sql) { this.sql = sql; } }
因为这里的密码采用了 密码{用户名} 加密的方式,所以使用了自定义的密码校验,重启,测试通过
3.配置Client端
3.1 普通方式
新建testweb项目,在Client工程WEB-INF/lib下添加cas-client-core-3.2.1.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>testWeb1</display-name> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file>default.html</welcome-file> <welcome-file>default.htm</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list> <!-- ======================== 单点登录/登出 ======================== --> <!-- 定义serverName,一个全局变量 --> <context-param> <param-name>serverName</param-name> <param-value>http://localhost:8080</param-value> </context-param> <!-- 该过滤器用于实现单点登出功能,可选配置。 --> <filter> <filter-name>CAS Single Sign Out Filter</filter-name> <filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class> </filter> <!-- 该过滤器负责用户的认证工作,必须启用它 --> <filter> <filter-name>CAS Authentication Filter</filter-name> <filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class> <init-param> <param-name>casServerLoginUrl</param-name> <param-value>https://localhost:8080/cas/login</param-value> </init-param> </filter> <!-- 该过滤器负责对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://localhost:8080/cas</param-value> </init-param> <init-param> <param-name>redirectAfterValidation</param-name> <param-value>true</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 Authentication 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 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> <listener> <listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class> </listener> <!-- ======================== 单点登录/登出结束 ======================== --> <servlet> <servlet-name>HelloWorldExample</servlet-name> <servlet-class>servlets.HelloWorld</servlet-class> </servlet> <servlet-mapping> <servlet-name>HelloWorldExample</servlet-name> <url-pattern>HelloWorldExample</url-pattern> </servlet-mapping> </web-app>
这里配置了HelloWorld servlet 来配合测试
public class HelloWorld extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { AttributePrincipal principal = (AttributePrincipal) request.getUserPrincipal(); String username = principal.getName(); response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("<html>"); out.println("<head>"); out.println("<title>Hello World</title>"); out.println("</head>"); out.println("<body>"); out.println("<h1>Hello World!"+username+"</h1>"); out.println("</body>"); out.println("</html>"); } }
访问localhost:8080/testWeb1/HelloWorldExample ,首次访问任一页面就会跳转到
https://localhost:8080/cas/login进行认证
3.2 spring 方式
这里采用spring security 与cas结合的方式
<!-- entry-point-ref入口点的意思,当捕捉到尚未登陆,尝试访问其他url时,会自动跳到入口点 --> <http auto-config="true" entry-point-ref="casAuthenticationEntryPoint" > <custom-filter ref="myFilter" before="FILTER_SECURITY_INTERCEPTOR" /> <!-- CasAuthenticationFilter总是监听/j_spring_cas_security_check请求 --> <!-- 认证请求将被配置的AuthenticationManager处理 --> <custom-filter position="CAS_FILTER" ref="casAuthenticationFilter" /> <access-denied-handler ref="accessDeniedHandler"></access-denied-handler> </http> <beans:bean id="casAuthenticationEntryPoint" class="org.springframework.security.cas.web.CasAuthenticationEntryPoint"> <beans:property name="loginUrl" value="http://sso.test.com/login"></beans:property> <!-- service指定了回调url,当认证成功时,会跳回到这 --> <beans:property name="serviceProperties" ref="serviceProperties"></beans:property> </beans:bean> <!-- service指定了回调url,当认证成功时,会跳回到这 --> <beans:bean id="serviceProperties" class="org.springframework.security.cas.ServiceProperties"> <beans:property name="service" value="http://localhost:8080/testweb/j_spring_cas_security_check"></beans:property> <beans:property name="sendRenew" value="false"></beans:property> </beans:bean> <!--当sso验证成功后,所有请求会在此处理 --> <beans:bean id="casAuthenticationProvider" class="org.springframework.security.cas.authentication.CasAuthenticationProvider"> <beans:property name="authenticationUserDetailsService" ref="authenticationUserDetailsService"/> <beans:property name="serviceProperties" ref="serviceProperties"></beans:property> <!-- 校验服务票据 --> <!-- Cas20TicketValidator 解析从CAS服务器收到的XML,它给CasAuthenticationProvider 返回一个TicketResponse,其中包含用户名和代理列表 --> <!-- 接下来将请求AuthenticationUserDetailsService 去加载应用于包含在Assertion中用户的GrantedAuthority 对象 --> <beans:property name="ticketValidator"> <beans:bean class="org.jasig.cas.client.validation.Cas20ServiceTicketValidator"> <!-- 配置cas服务器 --> <beans:constructor-arg index="0" value="http://sso.test.com/" /> </beans:bean> </beans:property> <beans:property name="key" value="cas" /> </beans:bean> <!-- authorities对应 CAS server的 登录属性, 在此设置到spirng security中,用于spring security的验证 --> <beans:bean id="authenticationUserDetailsService" class="com.test.security.MyGrantedAuthorityFromAssertionAttributesUserDetailsService"> </beans:bean> <authentication-manager alias="authenticationManager"> <authentication-provider ref="casAuthenticationProvider"></authentication-provider> </authentication-manager> <!-- cas 认证失败控制器 --> <beans:bean id="authenticationFailureHandler" class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler"> <beans:property name="defaultFailureUrl" value="/login?error=error" /> </beans:bean> <!-- cas 认证成功控制器 --> <beans:bean id="authenticationSuccessHandler" class="com.test.AuthenticationSuccessHandler"> <beans:property name="defaultTargetUrl" value="/" /> </beans:bean> <beans:bean id="casAuthenticationFilter" class="org.springframework.security.cas.web.CasAuthenticationFilter"> <beans:property name="authenticationManager" ref="authenticationManager"></beans:property> <beans:property name="authenticationFailureHandler" ref="authenticationFailureHandler" /> <beans:property name="authenticationSuccessHandler" ref="authenticationSuccessHandler" /> <beans:property name="filterProcessesUrl" value="/j_spring_cas_security_check" /> </beans:bean>
具体spring security 与cas 的配置结合,可参考 http://5148737.blog.51cto.com/5138737/1827795
本文出自 “bulajunjun” 博客,请务必保留此出处http://5148737.blog.51cto.com/5138737/1827803
原文地址:http://5148737.blog.51cto.com/5138737/1827803