概念或其它内容可以参考我一系列的博客相关文章 http://sgq0085.iteye.com/category/302777
1.Maven主要依赖
<dependency> <groupId>org.jasig.cas.client</groupId> <artifactId>cas-client-core</artifactId> <version>3.3.3</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-ehcache</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-cas</artifactId> <version>1.2.3</version> </dependency>
2.web.xml
<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>shiroFilter</param-value> </init-param> <!-- targetFilterLifecycle设为true是将filter放入web容器中成为真正意义上的filter。 否则只是个代理filter,不具有filter的生命周期,因此无法执行filter的init、destroy方法 --> <init-param> <param-name>targetFilterLifecycle</param-name> <param-value>true</param-value> </init-param> </filter>
3.shiro的Spring配置文件
1.主要是配置了casFilter 和 DefaultWebSecurityManager的subjectFactory参数;
2.casFilter 中 failureUrl 参数对应的地址 cas-failure需要自己实现,当登录认证失败的时候,会访问这个地址,可以通过该地址将该请求指向一个错误页面;LoginController中实现
3.注意Bean ShiroFilterFactoryBean属性loginUrl的值是 cas服务器地址,并将当前项目登录地址(注意那个/login)作为参数传入进去的。这里 /login和下面filterChainDefinitions中/login = cas保持一直;
<?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" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd"> <!-- 读取配置文件 --> <context:property-placeholder location="classpath*:cas.properties" ignore-unresolvable="true"/> <bean name="singleSignOutFilter" class="org.jasig.cas.client.session.SingleSignOutFilter"/> <bean name="assertionThreadLocalFilter" class="org.jasig.cas.client.util.AssertionThreadLocalFilter"/> <bean id="casFilter" class="org.apache.shiro.cas.CasFilter"> <!-- cas-failure 通过SpringMVC 跳转JSP --> <property name="failureUrl" value="cas-failure"/> </bean> <!-- Shiro's main business-tier object for web-enabled applications --> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="realm" ref="shiroCasRealm"/> <property name="cacheManager" ref="shiroEhcacheManager"/> <property name="subjectFactory" ref="casSubjectFactory"/> </bean> <!-- 項目自定义的Realm --> <bean id="shiroCasRealm" class="com.gqshao.cas.realm.MyCasRealm"> <property name="casServerUrlPrefix" value="https://sso.gqshao.com:8443/cas-server"/> <property name="casService" value="http://sso.gqshao.com:8090/client/login"/> </bean> <bean id="casSubjectFactory" class="org.apache.shiro.cas.CasSubjectFactory"/> <!-- Shiro Filter --> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="securityManager" ref="securityManager"/> <!-- 用于调用Controller --> <property name="loginUrl" value="https://sso.gqshao.com:8443/cas-server/login?service=http://sso.gqshao.com:8090/client/login"/> <property name="successUrl" value="/"/> <!-- 自己实现的formAuthcFilter,加入key type --> <property name="filters"> <util:map> <entry key="cas" value-ref="casFilter"/> </util:map> </property> <property name="filterChainDefinitions"> <value> /login = cas /logout = logout /static/** = anon /cas-failure = anon /** = user </value> </property> </bean> <!-- 用户授权信息Cache, 采用EhCache --> <bean id="shiroEhcacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager"> <property name="cacheManagerConfigFile" value="classpath:security/ehcache-shiro.xml"/> </bean> <!-- 保证实现了Shiro内部lifecycle函数的bean执行 --> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/> <!-- AOP式方法级权限检查 --> <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor"> <property name="proxyTargetClass" value="true"/> </bean> <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"> <property name="securityManager" ref="securityManager"/> </bean> </beans>
4.LoginController
1.failure方法是登录失败指定跳转到某条失败页面中
2.logoutUrl用于返回登出地址,实际的地址应该为https://sso.gqshao.com/adp-cas/logout?service=http://sso.gqshao.com:8080/adp-web/logout,/logout配置在shiro配置文件中filterChainDefinitions下ShiroFilterFactoryBean中
@Controller
public class LoginController {
@Value("${client.logoutUrl}")
public String logoutUrl;
@RequestMapping("/cas-failure")
public String failure() {
return "error/casFailure";
}
@RequestMapping("/logout-url")
@ResponseBody
public String logoutUrl() {
return logoutUrl;
}
}
5.Shiro的Realm实现
继承CasRealm
public class MyCasRealm extends CasRealm {
/**
* 认证回调函数,登录时调用.
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) {
return super.doGetAuthenticationInfo(authcToken);
}
/**
* 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用.
*/
@Override
@SuppressWarnings("unchecked")
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
List<Object> listPrincipals = principals.asList();
String name = listPrincipals.get(0).toString();
Map<String, String> attributes = (Map<String, String>) listPrincipals.get(1);
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
Set<String> roles = Sets.newHashSet("admin","operator");
authorizationInfo.setRoles(roles);
Set<String> permissions = Sets.newHashSet("show-info");
authorizationInfo.setStringPermissions(permissions);
return authorizationInfo;
}
}
6.注意
1.通过shiro-cas整合后AssertionHolder不可用
2.实际部署在tomcat时,Windows环境下catalina.bat文件中需要添加set JAVA_OPTS=%JAVA_OPTS% -Dfile.encoding=UTF-8;Linux环境中catalina.sh文件中配置JAVA_OPTS="$JAVA_OPTS -Dfile.encoding=UTF-8"