您的位置:首页 > 编程语言 > Java开发

基于Spirng的Shiro安全框架与CAS SSO的集成

2015-05-20 11:21 465 查看
首先需要在maven的pom文件中添加依赖

< dependency>
<groupId >org.apache.shiro </groupId >
<artifactId > shiro-cas </artifactId >
<version >${shiro.version} </version >
<exclusions >
<exclusion >
<artifactId > servlet-api </artifactId >
<groupId >javax.servlet </groupId >
</exclusion >
<exclusion >
<artifactId >commons-logging </artifactId >
<groupId >commons-logging </groupId >
</exclusion >
</exclusions >
</dependency >
<dependency >
<groupId >org.apache.shiro </groupId >
<artifactId > shiro-spring</ artifactId>
<version >${shiro.version} </version >
</dependency >
<dependency >
<groupId >org.apache.shiro </groupId >
<artifactId > shiro-ehcache </artifactId >
<version >${shiro.version} </version >
</dependency >


在web.xml中添加相应的filter和listener

<!-- The filter-name matches name of a 'shiroFilter' bean inside applicationContext.xml -->
<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>
<filter-name>singleSignOutFilter</filter-name>
<filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class>
</filter>
<listener>
<listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
</listener>

<filter-mapping>
<filter-name>singleSignOutFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>


先来看一下shiro的property文件

shiro.session.timeout=1800000
shiro.session.validate.timespan=1800000
shiro.login.url=http://login.51idc.cn/user/login?service=http://localhost:8086/tickets/shiro-cas
shiro.logout.url=http://login.51idc.cn/user/logout?service=http://localhost:8086/tickets/ticket/create
shiro.login.success.url=http://localhost:
4000
8086/home
shiro.casServer.url=http://login.51idc.cn/user
shiro.client.cas=http://localhost:8086/tickets/shiro-cas
shiro.failureUrl=/error.jsp


下面进行applicationContext-shiro.xml的配置,记得在sping的主配置文件中引用此配置

<!-- Shiro Filter
anon:匿名过滤器,不用登录也可以访问
authc:如果继续操作,需要做对应的表单验证否则不能通过
authcBasic:基本http验证过滤,如果不通过,跳转登录页面
logout:登录退出过滤器
noSessionCreation:没有session创建过滤器
perms:权限过滤器
port:端口过滤器,可以设置是否是指定端口如果不是跳转到登录页面
rest:http方法过滤器,可以指定如post不能进行访问等
roles:    角色过滤器,判断当前用户是否指定角色
ssl:请求需要通过ssl,如果不是跳转回登录页
user:如果访问一个已知用户,比如记住我功能,走这个过滤器
-->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager" />
<!--没有单点登录下的配置:没有权限或者失败后跳转的页面 -->
<!-- <property name="loginUrl" value="/login/toLoginAction"/> -->
<!--有单点登录的配置:登录 CAS 服务端地址,参数 service 为服务端的返回地址 -->
<property name="loginUrl" value="${shiro.login.url}" />
<property name="successUrl" value="${shiro.login.success.url}" />
<property name="filters">
<map>
<entry key="casFilter" value-ref="casFilter" />
<entry key="anon" value-ref="anonymousFilter" />
<entry key="logout" value-ref="logoutFilter" />
<entry key="loginSuccessFilter" value-ref="loginSuccessFilter" />
</map>
</property>
<property name="filterChainDefinitions">
<value>
/shiro-cas = casFilter
/**/*.js = anon
/**/*.css = anon
/static/** = anon
/api/** = anon
/logout = logout
/admin/** = loginSuccessFilter,roles[admin]
/** =loginSuccessFilter,roles[employee]
</value>
</property>
</bean>
<bean id="casFilter" class="org.apache.shiro.cas.CasFilter">
<!--配置验证错误时的失败页面(Ticket 校验不通过时展示的错误页面) -->
<property name="failureUrl" value="${shiro.failureUrl}" />
</bean>

<bean id="logoutFilter" class="org.apache.shiro.web.filter.authc.LogoutFilter">
<property name="redirectUrl" value="${shiro.logout.url}" />
</bean>

<bean id="anonymousFilter" class="org.apache.shiro.web.filter.authc.AnonymousFilter" />

<!-- 自定义的filter-->
<bean id="loginSuccessFilter" class="com.anchnet.tickets.web.filters.LoginSuccessFilter" />

<!-- Shiro's main business-tier object for web-enabled applications -->
<property name="sessionManager" ref="defaultWebSessionManager"/>
<property name="realms">
<list>
<ref bean="casRealm" />
</list>
</property>
<property name="subjectFactory" ref="casSubjectFactory" />

<property name="cacheManager" ref="shiroEhcacheManager" />
</bean>

<bean id="casRealm" class="com.anchnet.tickets.service.account.CustomCASRealm">
<property name="defaultRoles" value="ROLE_USER" />
<property name="casServerUrlPrefix" value="${shiro.casServer.url}" />
<!--客户端的回调地址设置,必须和上面的shiro-cas过滤器拦截的地址一致 -->
<property name="casService" value="${shiro.client.cas}" />
</bean>

<!--Define the realm you want to use to connect to your back-end security
datasource: -->
<bean id="casSubjectFactory" class="org.apache.shiro.cas.CasSubjectFactory" />

<!-- default web session manager -->
<bean id="defaultWebSessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
<property name="globalSessionTimeout" value="${shiro.session.timeout}"/>
<property name="sessionIdCookie" ref="simpleCookie"/>
<property name="sessionValidationScheduler" ref="sessionValidationScheduler"/>
<property name="sessionValidationSchedulerEnabled" value="true"/>
<property name="deleteInvalidSessions" value="true"/>
</bean>

<bean id="simpleCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
<constructor-arg index="0" value="JSESSIONID_COOKIE"/>
<property name="httpOnly" value="true"/>
</bean>

<bean id="sessionValidationScheduler" class="org.apache.shiro.session.mgt.ExecutorServiceSessionValidationScheduler">
<property name="sessionManager" ref="defaultWebSessionManager"/>
<property name="interval" value="${shiro.session.validate.timespan}"/>
</bean>

<!-- 用户授权信息Cache, 采用EhCache -->
<bean id="shiroEhcacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
<property name="cacheManagerConfigFile" value="classpath:cache/ehcache-shiro.xml" />
</bean>

<!-- 保证实现了Shiro内部lifecycle函数的bean执行 -->
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />

<!--AOP式方法级权限检查 -->
<!--Enable Shiro Annotations for Spring-configured beans. Only run after -->
<!--the lifecycleBeanProcessor has run: -->
<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>


上面的用户授权的cache采用ehcache,以下是ehcache-shiro.xml的配置

<ehcache updateCheck="false" name="shiroCache">
<!-- http://ehcache.org/ehcache.xml -->
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="false"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
/>
</ehcache>


下面详细介绍 CasRealm bean的实现

import java.io.Serializable;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.authz.UnauthorizedException;
import org.apache.shiro.cas.CasRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Objects;
import com.google.common.collect.ImmutableList;

public class CustomCASRealm extends CasRealm {

private static Logger logger = LoggerFactory
.getLogger(CustomCASRealm.class);

// @Autowired
protected AccountService accountService;

@Override
protected AuthorizationInfo doGetAuthorizationInfo(
PrincipalCollection principals) {

SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
String loginName = (String) principals.getPrimaryPrincipal();
if (loginName == null) {
throw new UnauthorizedException("无效的凭证");
}
try {
Map rolesMaps = (Map) principals.asList().get(1);
String roles = (String) rolesMaps.get("role");
if (roles.length() > 0) {
roles = roles.substring(1);
roles = roles.substring(0, roles.length() - 1);
logger.debug("!!!!! get roles:{}", roles);
authorizationInfo.addRoles(ImmutableList.copyOf(StringUtils.split(roles, ", ")));
} else {
logger.debug("user {} has no roles!!!", loginName);
}

} catch (Exception e) {
e.printStackTrace();
throw new UnauthorizedException("无效的凭证");
}
return authorizationInfo;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  shiro spring cas