Cas单点登录(整合shiro版本)

Cas单点登录(整合shiro版本)


    单点登录:Single Sign On,简称SSO,SSO使得在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。

CAS框架:CAS(Central Authentication Service)是实现SSO单点登录的框架。
逻辑关系图:(注:图为转载)

分析:
1.图中用户访问cas客户端;
2.需要登录时,重定向到Cas-Server(Cas服务),其中service为Cas-Client路径
(用于Cas-Server执行完后返回到指定路径)
3.cas-server认证用户信息,并生成一个ticket返回给用户;
4.用户使用此ticket访问Cas-Client(连接了Cas-Server具体应用);
5.Cas-Client使用ticket再次访问Cas-Server进行认证;
6.认证成功后返回Server指定路径到Cas-Client,并返回具体登录用户信息,流程结束。

这是原生Cas的一套流程,那么我们需要集成到已经使用Shiro框架的应用中,如何进行无缝衔接呢?

具体流程:
对于Cas-Server就不多说了,官网下载下来后,修改验证用户信息的配置(从数据库中读取数据进行
身份认证),修改配置文件-deployerConfigContext
(其中deployerConfigContext.xml文件是CAS专门提出来的供用户修改的配置,其他配置不建议修改)
<bean id="primaryAuthenticationHandler"
          class="org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler">
      	<property name="dataSource" ref="dataSource" />  
     	<property name="sql" value="select password from userwhere userName=?" />  
    </bean>
    
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">  
       <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
       <property name="url" value="jdbc:mysql://127.0.0.1:3306/**?characterEncoding=utf8" />  
       <property name="username" value="**" />  
       <property name="password" value="**" />  
    </bean> 
注意:其中需要引入包cas-server-support-jdbc-4.0.0.jar(版本号极为重要,与cas-server-core版本一致即可)
还需要引入mysql-connector-java-5.1.34.jar(连接mysql)
连接Cas-Server的使用了Shiro的应用项目连接的整体操作流程,如下:
1.首先需要引入包shiro-cas这个包是shiro和cas连接的通道;
2.修改项目中shiroRealm(自定义的登录验证类,里面包含登录认证、权限认证)
/**
 * shiro登录实现类 
 * 
 */
//重点是集成CasRealm
public class ShiroRealm extends CasRealm {
	
	private Logger log = LoggerFactory.getLogger(ShiroRealm.class);
	
	private TicketValidator ticketValidator;  
	
	 protected TicketValidator ensureTicketValidator()  
	    {  
	        if(ticketValidator == null)  
	            ticketValidator = createTicketValidator();  
	        return ticketValidator;  
	    }  
	
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
		CasToken casToken = (CasToken) authcToken;  
		if (authcToken == null)  
            return null;  
		String ticket = (String) casToken.getCredentials();  
		TicketValidator ticketValidator = ensureTicketValidator();
	  try  
        {  
            Assertion casAssertion = ticketValidator.validate(ticket, getCasService());  
            AttributePrincipal casPrincipal = casAssertion.getPrincipal();  
            String userId = casPrincipal.getName();  
            log.debug("Validate ticket : {} in CAS server : {} to retrieve user : {}", new Object[] {  
                ticket, getCasServerUrlPrefix(), userId  
            });  
            Map<String, Object> attributes = casPrincipal.getAttributes();  
            casToken.setUserId(userId);  
            String rememberMeAttributeName = getRememberMeAttributeName();  
            String rememberMeStringValue = (String)attributes.get(rememberMeAttributeName);  
            boolean isRemembered = rememberMeStringValue != null && Boolean.parseBoolean(rememberMeStringValue);  
            if(isRemembered)  
                casToken.setRememberMe(true);  
            /**  此处是封装用户信息
            sUsr su = new sUsr();
    		su.setUsrCde(userId);
    		sUsr susr = isUsrService.findByCode(su);
    		AccessTokenInfo atInfo = new AccessTokenInfo();
    		atInfo.setUsrCde(userId);
    		//获取apikey
    		AccessTokenInfo ati = accessTokenInfoService.selectOneByObject(atInfo);
    		//构建ShiroUserAccount
    		ShiroUserAccount sua = new ShiroUserAccount(susr,ati);
            */
            List<Object> principals = CollectionUtils.asList(new Object[] {  
            	sua, 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);  
        }  		
	}


	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) {
		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
		//获取登录用户的Shiro对象  ---主体身份信息(验权)
		ShiroUserAccount shiroUser = (ShiroUserAccount)principal.getPrimaryPrincipal(); 
		//断言,若对象为空则直接抛出异常
		Assert.notNull(shiroUser,"找不到principal中的SessionVariable---shiroUser");
		//添加用户拥有的role
		addRoles(info,shiroUser);
		addPermissions(info,shiroUser);
		return info;
	}
	
}

3.配置shiro.xml文件:
shiroRealm:
 <bean id="shiroRealm" class="com.**.ShiroRealm">
   		<!-- cas服务端地址前缀 -->
		<property name="casServerUrlPrefix" value="http://127.0.0.1:8080/SSO" />
		<!-- 应用服务地址,用来接收cas服务端票据,客户端的cas入口 -->
		<property name="casService" value="http://127.0.0.1:8585/**/shiro-cas" />
    </bean>  

shiroFilter:
<!--shiro过滤器配置,bean的id值须与web中的filter-name的值相同-->  
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">  
        <property name="securityManager" ref="securityManager" />  
        	<!-- 验证用户未登录时跳转的登录地址 -->
		<property name="loginUrl" value="http://127.0.0.1:8080/SSO/login?service=http://127.0.0.1:8585/**/shiro-cas" />
		<property name="successUrl" value="" />
		<!-- 验证用户权限的跳转地址 -->
		<property name="unauthorizedUrl" value="/" />
		 
		 <property name="filters">  
           	    <map> 
           		<!--添加cas的过滤器到shiro  -->  
                	<entry key="casFilter" value-ref="casFilter"/>  
                	<!--添加登出过滤  -->  
                	<entry key="logoutFilter" value-ref="logoutFilter" />
            	   </map>  
   		</property>
		 
        <property name="filterChainDefinitions">  
            <value> 
            	/shiro-cas = casFilter            	
            	/person/**=authc
            </value>  
        </property>  
    </bean>      
casFilter:
<bean id="casFilter" class="org.apache.shiro.cas.CasFilter">
		<!-- 配置验证错误时的失败页面 -->
		<property name="failureUrl" value="http://127.0.0.1:8080/SSO/login?service=http://127.0.0.1:8585/themis_front/shiro-cas" />
		<property name="successUrl" value="/themis/ReviewQuery" />
	</bean>
logoutFilter:
<bean id="logoutFilter" class="org.apache.shiro.web.filter.authc.LogoutFilter">
		<!-- 配置验证错误时的失败页面 -->
		<property name="redirectUrl" value="http://127.0.0.1:8080/SSO/logout?service=http://127.0.0.1:8585/themis_front/shiro-cas" />
	</bean>

cas针对subject工厂配置:
<bean id="casSubjectFactory" class="org.apache.shiro.cas.CasSubjectFactory"></bean>
    
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">  
        <!--单个realm使用realm,如果有多个realm,使用realms属性代替-->  
        <property name="realm" ref="shiroRealm" />  
          <!-- session 管理器 -->
		<property name="sessionManager" ref="sessionManager" />
		<!-- 缓存管理器 -->
		<property name="cacheManager" ref="shiroCacheManager" />
		<property name="subjectFactory" ref="casSubjectFactory"></property>
    </bean>  
如下是shiro剩余的基本配置:
     <!-- session管理器 -->
	<bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
		<!-- 超时时间 -->
		<property name="globalSessionTimeout" value="1800000"/>
		<!-- session存储的实现 -->
		<property name="sessionDAO" ref="shiroSessionDao"/>
		<!-- sessionIdCookie的实现,用于重写覆盖容器默认的JSESSIONID -->
		<property name="sessionIdCookie" ref="sharesession"/>
		<!-- 定时检查失效的session -->
		<property name="sessionValidationSchedulerEnabled" value="true" />
	</bean>
	
	 <!-- sessionIdCookie的实现,用于重写覆盖容器默认的JSESSIONID -->
   <bean id="sharesession" class="org.apache.shiro.web.servlet.SimpleCookie">
       <!-- cookie的name,对应的默认是 JSESSIONID -->
       <constructor-arg name="name" value="SHAREJSESSIONID"/>
		<!-- 记住我cookie生效时间30天 -->
		<property name="maxAge" value="2592000" />
   </bean>
   
	
  <!-- session存储的实现 -->
   <bean id="shiroSessionDao" class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO" />
   <!-- 缓存管理实现 -->
   <bean id="shiroCacheManager" class="org.apache.shiro.cache.MemoryConstrainedCacheManager" />
      
    <!-- 保证实现了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>





  • 4
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
# 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系统就能访问其中的系统
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值