准备工作
cas单点登录开始前准备,请参考cas4.2.7实现单点登录。
与shiro进行整合
注:准备工作的基础上,对cas客户端进行如下改进。
引入相关jar包
shiro-cas-1.2.6.jar
shiro-core-1.2.6.jar
shiro-spring-1.2.6.jar
shiro-web-1.2.6.jar
web.xml引入shiro过滤器
<?xml version="1.0" encoding="UTF-8"?> <web-app version="3.0" 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/javaeehttp://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"><display-name>Archetype Created Web Application</display-name><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener><context-param><param-name>contextConfigLocation</param-name><param-value>classpath:spring-web.xml, classpath:spring-shiro.xml</param-value></context-param><!-- Shiro配置 --><filter><filter-name>shiroFilter</filter-name><filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class><init-param><param-name>targetFilterLifecycle</param-name><param-value>true</param-value></init-param></filter><filter-mapping><filter-name>shiroFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping><!-- ****************** 单点登录开始 ********************--><!-- 用于实现单点登出功能 可选 --><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>http://127.0.0.1:8080/cas-web/</param-value></init-param></filter><filter-mapping><filter-name>CAS Single Sign Out Filter</filter-name><url-pattern>/*</url-pattern></filter-mapping><!-- 该过滤器对HttpServletRequest请求包装, 可通过HttpServletRequest的getRemoteUser()方法获得登录用户的登录名,可选 --><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()。这个类把Assertion信息放在ThreadLocal变量中,这样应用程序不在web层也能够获取到当前登录信息 --><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><!-- ****************** 单点登录结束 ********************--><servlet><servlet-name>springMVC</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:spring-web.xml</param-value></init-param><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>springMVC</servlet-name><url-pattern>/</url-pattern></servlet-mapping><welcome-file-list><welcome-file>index.jsp</welcome-file></welcome-file-list> </web-app>
引入shiro的配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><context:property-placeholder location="classpath:shiro.properties" ignore-unresolvable="true"/><bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"><property name="securityManager" ref="securityManager"/><!-- 设定角色的登录链接,这里为cas登录页面的链接可配置回调地址 --><property name="loginUrl" value="${cas.loginUrl}" /><property name="successUrl" value="${shiro.successUrl}" /><property name="filters"><map><entry key="casFilter" value-ref="casFilter"/></map></property><property name="filterChainDefinitions"><value>/shiro-cas = casFilter/** = authc</value></property></bean><bean id="casFilter" class="org.apache.shiro.cas.CasFilter"><property name="failureUrl" value="${shiro.failureUrl}"/></bean><bean id="ShiroCasRealm" class="com.hjzgg.client.shiro.ShiroCasRealm"/><bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"><property name="realm" ref="ShiroCasRealm"/><property name="subjectFactory" ref="casSubjectFactory"/></bean><bean id="casSubjectFactory" class="org.apache.shiro.cas.CasSubjectFactory"/><bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/><bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"><property name="staticMethod" value="org.apache.shiro.SecurityUtils.setSecurityManager"/><property name="arguments" ref="securityManager"/></bean> </beans>
引入shiro的需要属性
cas.loginUrl=http://127.0.0.1:8080/cas-web/login?service=http://127.0.0.1:8080/cas-client/shiro-cas
cas.logoutUrl=http://127.0.0.1:8080/cas-web/logout?service=http://127.0.0.1:8080/cas-client/shiro-cas
cas.serverUrlPrefix=http://127.0.0.1:8080/cas-web
shiro.cas.service=http://127.0.0.1:8080/cas-client/shiro-cas
shiro.failureUrl=/error
shiro.successUrl=/success
自定义shiro的realm
package com.hjzgg.client.shiro;import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.SimpleAuthenticationInfo; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.cas.CasAuthenticationException; import org.apache.shiro.cas.CasToken; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.subject.SimplePrincipalCollection; import org.apache.shiro.util.StringUtils; import org.jasig.cas.client.authentication.AttributePrincipal; import org.jasig.cas.client.util.AssertionHolder; import org.jasig.cas.client.validation.Assertion; import org.jasig.cas.client.validation.Cas20ServiceTicketValidator; import org.jasig.cas.client.validation.TicketValidationException; import org.jasig.cas.client.validation.TicketValidator; import org.springframework.beans.factory.annotation.Value;import java.util.ArrayList; import java.util.List; import java.util.Map;public class ShiroCasRealm extends AuthorizingRealm {@Value("${shiro.cas.service}")private String shiroCasServiceUrl;@Value("${cas.serverUrlPrefix}")private String casServerUrlPrefix;@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {AttributePrincipal principal = AssertionHolder.getAssertion().getPrincipal();if (principal != null) {Map<String, Object> attributes = principal.getAttributes();if (attributes.size() > 0) { // List<String> roles = CommonUtils.arrayStringtoArrayList((String)attributes.get("roles"));List<String> roles = null;//权限信息对象info,用来存放查出的用户的所有的角色(role)及权限(permission)SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();//用户的角色集合 info.addRoles(roles);//用户的角色对应的所有权限,如果只使用角色定义访问权限,下面的一行可以不要 //info.addStringPermissions(user.getPermissionList()); }}return null;}@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {CasToken casToken = (CasToken) token;if (token == null)return null;String ticket = (String) casToken.getCredentials();if (!StringUtils.hasText(ticket))return null; Cas20ServiceTicketValidator cas20ServiceTicketValidator = new Cas20ServiceTicketValidator(casServerUrlPrefix);cas20ServiceTicketValidator.setEncoding("utf-8");TicketValidator ticketValidator = cas20ServiceTicketValidator;try {Assertion casAssertion = ticketValidator.validate(ticket, shiroCasServiceUrl);AttributePrincipal casPrincipal = casAssertion.getPrincipal();String userId = casPrincipal.getName();List principals = new ArrayList<String>();if (casPrincipal != null) {Map<String, Object> attributes = casPrincipal.getAttributes();principals.add(userId);principals.add(attributes);}PrincipalCollection principalCollection = new SimplePrincipalCollection(principals, getName());return new SimpleAuthenticationInfo(principalCollection, ticket);} catch (TicketValidationException e) {throw new CasAuthenticationException((new StringBuilder()).append("Unable to validate ticket [").append(ticket).append("]").toString(), e);}}@Overrideprotected void onInit() {super.onInit();this.setAuthenticationTokenClass(CasToken.class);} }
引入日志系统
http://www.cnblogs.com/hujunzheng/p/6926429.html
遇到的问题
shiro+cas学习及整合问题
cas4.2.7学习笔记
项目地址
https://github.com/hjzgg/cas4.2.7-authentication/tree/shiro+cas