shiro集成cas

        shiro是一个权限管理框架,将安全认证相关的功能抽取出来组成,使用shiro就可以非常快速的完成认证、授权等功能的开发,降低系统成本。为了能够为多个系统提供统一认证入口,又使用了cas,而且二者都涉及到对session管理,所以需要集成。

cas基本协议过程:


基础模式的SSO访问流程步骤:

  1. 访问服务:客户端发送请求访问应用系统提供的服务资源。
  2. 定向认证:客户端重定向用户请求到中心认证服务器。
  3. 用户认证:用户进行身份认证
  4. 发放票据:服务器会产生一个随机的 Service Ticket 。
  5. 验证票据: SSO 服务器验证票据 Service Ticket 的合法性,验证通过后,允许客户端访问服务。
  6. 传输用户信息: SSO 服务器验证票据通过后,传输用户认证结果信息给客户端。

cas认证时序图


       对于访问受保护资源的每个 Web 请求,CAS Client 会分析该请求的 Http 请求中是否包含 Service Ticket,如果没有,则说明当前用户尚未登录,于是将请求重定向到指定好的 CAS Server 登录地址,并传递 Service (也就是要访问的目的资源地址),以便登录成功过后转回该地址。用户在第 3 步中输入认证信息,如果登录成功,CAS Server 随机产生一个相当长度、唯一、不可伪造的 Service Ticket,并缓存以待将来验证,之后系统自动重定向到 Service所在地址,并为客户端浏览器设置一个 Ticket Granted Cookie(TGC),CAS Client 在拿到Service 和新产生的 Ticket 过后,在第 5,6 步中与 CAS Server 进行身份合适,以确保 Service Ticket 的合法性。

       在该协议中,所有与 CAS 的交互均采用 SSL 协议,确保,ST 和 TGC 的安全性。协议工作过程中会有 2 次重定向的过程,但是 CAS Client 与 CAS Server 之间进行 Ticket 验证的过程对于用户是透明的。

Shiro CAS 认证流程

·       1 用户首次访问受保护 的资源;例如 http://casclient/security/view.do

·       2 由于未通过认证,Shiro首先把请求地址(http://casclient/security/view.do)缓存起来。

·        3然后跳转到 CAS服务器进行登录认证,在 CAS 服务端认证完成后需要返回到请求的 CAS 客户端,因此在请求时,必须在参数中添加返回地址 ( 在 Shiro 中名为 CAS Service)。 例如 http://casserver/login?service=http://casclient/shiro-cas

·        4由CAS服务器认证通过后,CAS 服务器为返回地址添加ticket。例如http://casclient/shiro-cas?ticket=ST-4-BWMEnXfpxfVD2jrkVaLl-cas

·        5接下来,Shiro会校验 ticket 是否有效。由于 CAS 客户端不提供直接认证,所以 Shiro 会向 CAS 服务端发起 ticket 校验检查,只有服务端返回成功时,Shiro 才认为认证通过。

·        6认证通过,进入授权检查。Shiro授权检查与前面提到的相同。

·       7 最后授权检查通过,用户正常访问到 http://casclient/security/view.do

项目中配置:

Shiro在1.2.0的时候提供了对cas的集成。因此在项目中添加shiro-cas的依赖
    <dependency>
       <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-cas</artifactId>
       <version>${shiro.version}</version>
    </dependency>
         Shirocas集成后,cas client的配置更加简单了。原理就是将casFilter添加到到shiroFilter的filterChain中。   shiroFilter是在web.xml中定义的
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jee="http://www.springframework.org/schema/jee"
	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.0.xsd 
	http://www.springframework.org/schema/aop 
	http://www.springframework.org/schema/aop/spring-aop-3.0.xsd 
	http://www.springframework.org/schema/tx  
	http://www.springframework.org/schema/tx/spring-tx-3.0.xsd 
	http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd
	http://www.springframework.org/schema/context
	http://www.springframework.org/schema/context/spring-context-3.0.xsd"
	default-lazy-init="true">

	<!-- spring 可支持注解 -->
	<context:annotation-config /> 

	<!-- 用于扫描其他的.properties配置文件 -->
	<bean id="propertyConfigurer"
		class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
		<property name="locations">
			<list>
				<value>classpath:config/shiro-cas.properties</value>
			</list>
		</property>

	</bean>

	<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~配置sessionManager start~~~~~~~~~~~~~~~~~~~~~ -->

	<!-- 缓存管理器redis-start -->

	<!-- 自定义cacheManager -->
	<bean id="redisManager" class="com.tgb.itoo.authority.cache.RedisManager"></bean>

	<bean id="redisCache" class="com.tgb.itoo.authority.cache.RedisCache">
		<constructor-arg ref="redisManager"></constructor-arg>
	</bean>

	<!-- 自定义redisManager-redis -->
	<bean id="redisCacheManager" class="com.tgb.itoo.authority.cache.RedisCacheManager">
		<property name="redisManager" ref="redisManager" />
	</bean>

	<!-- 缓存管理器redis-end-李社河-2015年4月14日 -->

	<!-- session会话存储的实现类 -->
	<bean id="redisShiroSessionDAO" class="com.tgb.itoo.authority.cache.RedisSessionDAO">
		<property name="redisManager" ref="redisManager" />
	</bean>

	<!-- sessionIdCookie的实现,用于重写覆盖容器默认的JSESSIONID -->
	<bean id="sharesession" class="org.apache.shiro.web.servlet.SimpleCookie">
		<!-- cookie的name,对应的默认是 JSESSIONID -->
		<constructor-arg name="name" value="SHAREJSESSIONID" />
		<!-- jsessionId的path为 / 用于多个系统共享jsessionId -->
		<property name="path" value="/" />
	</bean>

	<!-- session管理器 -->
	<bean id="sessionManager"
		class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
		<!-- 设置全局会话超时时间,默认30分钟(1800000) -->
		<property name="globalSessionTimeout" value="1800000" />
		<!-- 是否在会话过期后会调用SessionDAO的delete方法删除会话 默认true -->
		<property name="deleteInvalidSessions" value="true" />

		<!-- 会话验证器调度时间 -->
		<property name="sessionValidationInterval" value="1800000" />

		<!-- session存储的实现 -->
		<property name="sessionDAO" ref="redisShiroSessionDAO" />
		<!-- sessionIdCookie的实现,用于重写覆盖容器默认的JSESSIONID -->
		<property name="sessionIdCookie" ref="sharesession" />
		<!-- 定时检查失效的session -->
		<property name="sessionValidationSchedulerEnabled" value="true" />

	</bean>


	<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~配置sessionManager end~~~~~~~~~~~~~~~~~~~~~~~~ -->

	<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~配置securityManager start~~~~~~~~~~~~~~~~~~~ -->


	<!-- 取得用户的权限信息集合 -->

	<!-- shiro于数据交互的类 ,自己写的类的实现-ShiroRealmBean自己重写的类的实现 -->
	<bean id="shiroRealm" class="com.tgb.itoo.authority.service.ShiroRealmBean">
		<property name="defaultRoles" value="user"></property>
		<!-- 注入自己实现的类,授权的过程-PermissionManager是云平台重写的授权的过程,用户Id->角色->资源 -->
		<property name="casServerUrlPrefix" value="${casServerUrlPrefix}"></property>
		<property name="casService" value="${casService}"></property>
	</bean>

	<!-- 如果要实现cas的remember me的功能,需要用到下面这个bean,并设置到securityManager的subjectFactory中 -->
	<bean id="casSubjectFactory" class="org.apache.shiro.cas.CasSubjectFactory" />

	<!-- shiro管理核心类 -->
	<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
		<property name="realm" ref="shiroRealm"></property>
		<property name="sessionMode" value="http"></property>
		<property name="subjectFactory" ref="casSubjectFactory"></property>
		<property name="cacheManager" ref="redisCacheManager" />
		<property name="sessionManager" ref="sessionManager"></property>
	</bean>

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

	<!-- 开启shiro的注解,需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证 -->
	<bean
		class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
		depends-on="lifecycleBeanPostProcessor"></bean>
	<bean
		class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
		<property name="securityManager" ref="securityManager" />
	</bean>

	<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~配置securityManager end~~~~~~~~~~ -->


	<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 配置shiroSecurityFilter start~~~~~~~~~~ -->
	<!-- shiro过滤器 start -->
	<bean id="shiroSecurityFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
		<property name="securityManager" ref="securityManager"></property>
		<property name="loginUrl" value="${loginUrl}"></property>
		<property name="filters">
			<map>
                                <!--添加casFilter到shiroFilter --> 
				<entry key="casFilter">
					<bean class="org.apache.shiro.cas.CasFilter">
						<!--配置验证错误时的失败页面 /main 为系统登录页面 -->
						<property name="failureUrl" value="/message.jsp" />
						<property name="successUrl" value="getSystemindex" />
					</bean>
				</entry>		
			</map>
		</property>
		<!-- 过滤器链,请求url对应的过滤器 -->
		<property name="filterChainDefinitions">
			<value>
				/mobile_**/**=anon
				/message.jsp=anon
				/shiro-cas=casFilter
				<!-- /shirologout=logoutFilter -->
				/logout=logout
				/**=user
			</value>
		</property>
	</bean>
	<!-- shiro过滤器 end -->
	<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~配置shiroSecurityFilter end~~ -->

</beans>

shiroRealmBean:负责授权

package com.tgb.itoo.authority.service;

import java.util.Iterator;
import java.util.List;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cas.CasRealm;
import org.apache.shiro.subject.PrincipalCollection;

/**
 * 
 * @author hanyi
 *
 */
public class ShiroRealmBean extends CasRealm {

	private ShiroBean permissionMgr;

	/**
	 * 负责授权
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(
			PrincipalCollection principals) {

		String permissionName;
		try {
			//得到userCode
			SimpleAuthorizationInfo author = new SimpleAuthorizationInfo();
			String  userCode = (String) principals.getPrimaryPrincipal();

			//通过自己写的实现来得到用户权限集合
			List<String> lstPermission = permissionMgr
					.queryUserPermission(userCode);
			Iterator<String> it = lstPermission.iterator();

			//遍历权限集合添加到授权信息对象
			while (it.hasNext()) {
				permissionName = it.next().toString();
				author.addStringPermission(permissionName);
			}

			return author;

		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}


	public ShiroBean getPermissionMgr() {
		return permissionMgr;
	}

	public void setPermissionMgr(ShiroBean permissionMgr) {
		this.permissionMgr = permissionMgr;
	}

}

说明:shiroRealmBean继承了CasRealm,CasRealm又继承了AuthorizingRealm。所以,

shiroRealmBean中具体写了授权实现逻辑,而认证则调用了CasRealm中的方法

shiro-cas.properties文件

loginUrl=http://192.168.22.246:8888/cas/login?service=http://localhost:8091/itoo-exam-template-web/shiro-cas
successUrl=http://localhost:8091/itoo-exam-template-web/addTemplet
casServerUrlPrefix=http://192.168.22.246:8888/cas
casService=http://localhost:8091/itoo-exam-template-web/shiro-cas

说明:

loginUrl:cas登录页面(带有请求的受保护资源,用于返回时)

casServerUrlPrefix是CAS服务端地址。

casService是应用服务地址,用来接收CAS服务端票据。

    没有单点登录情况下的话,登录认证和授权认证默认在AuthorizingRealm的doGetAuthorizationInfo和doGetAuthenticationInfo中进行,所以我这里是通过shiroDbRealm(继承AuthorizingRealm的自定义类)覆写doGetAuthorizationInfo和doGetAuthenticationInfo,实现自定义登录认证和授权认证。

 

     有单点登录情况下,登录认证是在casserver进行的,那么执行流程是这样的:用户从 cas server登录成功后,跳到cas client的CasRealm执行默认的doGetAuthorizationInfo和doGetAuthenticationInfo,此时doGetAuthenticationInfo做的工作是把登录用户信息传递给shiro,保持默认即可,而对于授权的处理,可以通过MyCasRealm(继承CasRealm的自定义类)覆写doGetAuthorizationInfo进行自定义授权认证。



  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
# sso-shiro-cas spring下使用shiro+cas配置单点登录,多个系统之间的访问,每次只需要登录一次 ## 系统模块说明 1. cas: 单点登录模块,这里直接拿的是cas的项目改了点样式而已 2. doc: 文档目录,里面有数据库生成语句,采用的是MySQL5.0,数据库名为db_test 3. spring-node-1: 应用1 4. spring-node-2: 应用2 其中node1跟node2都是采用spring + springMVC + mybatis 框架,使用maven做项目管理 ## cas集成说明 1.首先采用的是查数据库的方式来校验用户身份的,在cas/WEB-INF/deployerConfigContext.xml中第135行构建了这个类型 ``` xml ``` 其中QueryDatabaseAuthenticationHandler这个类是自定义构建的,在cas/WEB-INF/lib/cas-jdbc-1.0.0.jar里面,有兴趣的同学可以发编译看下,关于几个属性的说明 1. dataSource: 数据源,配置MySQL的连接信息 2. passwordEncoder: 加密方式,这里用的是MD5 3. sql: sql查询语句,这个语句就是根据用户输入的账号查询其密码 #### 以上就是单点登录管理的主要配置 ## 应用系统的配置node1 1. 应用系统采用shiro做权限控制,并且跟cas集成 2. 在/spring-node-1/src/main/resources/conf/shiro.properties 文件中 ``` properties shiro.loginUrl=http://127.0.0.1:8080/cas/login?service=http://127.0.0.1:8081/node1/shiro-cas shiro.logoutUrl=http://127.0.0.1:8080/cas/logout?service=http://127.0.0.1:8081/node1/shiro-cas shiro.cas.serverUrlPrefix=http://127.0.0.1:8080/cas shiro.cas.service=http://127.0.0.1:8081/node1/shiro-cas shiro.failureUrl=/users/loginSuccess shiro.successUrl=/users/loginSuccess ``` 其中shiro.loginUrl 跟 shiro.logoutUrl的前面是cas验证的地址,后面的是我们应用系统的地址,这样配置的方式是为了在访问我们的应用系统的时候,先到cas进行验证,如果验证成功了,cas将重定向到shiro.successUrl 所表示的地址 3.在/spring-node-1/src/main/resources/conf/shiro.xml 文件中 ``` xml /shiro-cas = casFilter /logout = logoutFilter /users/** = user ``` > 其中shiroFilter这个类主要用于需要拦截的url请求,需要注意的是这个是shiro的拦截,我们还需要配置cas的过滤配置casFilter > casRealm这个类是需要我们自己实现的,主要用于shiro的权限验证,里面的属性说明如下 1. defaultRoles: 默认的角色 2. casServerUrlPrefix: cas地址 3. casService: 系统应用地址 最后我们还需要在/spring-node-1/src/main/webapp/WEB-INF/web.xml 文件中配置相关的过滤器拦截全部请求 ``` xml shiroFilter org.springframework.web.filter.DelegatingFilterProxy targetFilterLifecycle true shiroFilter /* ``` ## 系统运行 1. 端口说明,cas:8080,node1:8081,node2:8082,大家可以采用maven提供的tomcat7插件,配置如下: ``` xml org.apache.tomcat.maven tomcat7-maven-plugin 2.1 8081 UTF-8 tomcat7 /node1 ``` 这样的配置,我们甚至都不需要配置tomcat服务器了,建议这种方式 2.各个模块的访问地址 > cas:http://127.0.0.1:8080/cas > node1:http://127.0.0.1:8081/node1 > node2:http://127.0.0.1:8082/node2 3.访问系统 > 输入 http://127.0.0.1:8081/node1/shiro-cas ,进入cas验证 > 输入用户名 admin,密码 admin@2015,验证成功后将会重定向到http://127.0.0.1:8081/node1//users/loginSuccess ,也就是node1系统的主页,里面的节点2代表的是node2系统的主页,你会发现我们不需要登录到node2系统就能访问其中的系统了

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值