记录一次解决shiro+cas的集成问题【重复重定向】

首先简介一下工作中的情况:

公司之前的两个项目,权限和认证是用shir做的。现在需要将这两个项目作为客户端,做单点登陆(sso)。

这个重复重定向的问题真是由于自己不熟悉shiro造成的,网上的解决方案大概我都看过了,都试过了,然而。。。

工作准备:

1.之前没有做过单点登陆,所以用了一天的时间了解了一下单点登陆的各种框架和协议

1.目前文档和教程多的就是cas(我也是用了这种)

2.像腾讯和新浪使用的是oauth(比较新的,文档和使用的人比较少)

3.自己写一个单点登陆(我也看过别人写的简单的,总结来说简单的太简单,复杂的太复杂)

2.注意一下前提:之前没有用过shiro(这点很重要,也是这点导致集成的时候出现重定向的问题)、也没用过sso

3.先给大家看一下web.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-mapping>
    <filter-name>shiroFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

4.这是spring-context-shiro.xml(和网上的没啥区别,但是问题就是出现在这里,细节细节细节!!)

<?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-4.0.xsd
		http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context-4.0.xsd"
	default-lazy-init="true">

	<description>Shiro Configuration</description>

	<!-- 加载配置属性文件 -->
	<context:property-placeholder
		ignore-unresolvable="true" location="classpath:xxx.properties" />

	<!-- Shiro权限过滤过滤器定义 -->
	<!-- !!!!!!这个地方是要注意的第一个地方!!!!!!! -->、
	注意:
		${adminPath}/cas = cas 当时没认真看这里,这就是根据不同的url指定不同的过滤器
		为什么说要注意这里呢?
		因为看到这篇文章的猿猴们应该都之后cas的基本原理了。
		1.当我们第一次访问这个客户端的时候,先去cas认证,并且返回一个ticket
		2.然后关键的一点来了,客户端要有个东西去验证ticket,谁来验证啊???
		3.就是这块指定的过滤器,它就相当于当前客户端的验证服务。我们继续
	<bean name="shiroFilterChainDefinitions" class="java.lang.String">
		<constructor-arg>
			<value>
				/static/** = anon
				/gis/** = anon
				/userfiles/** = anon
				/jsp/** = authc
				${adminPath}/cas = cas
				${adminPath}/login = authc
				${adminPath}/logout = logout
				${adminPath}/** = user
				/act/rest/service/editor/** = perms[act:model:edit]
				/act/rest/service/model/** = perms[act:model:edit]
				/act/rest/service/** = user
				/ReportServer/** = user				
			</value>
		</constructor-arg>
	</bean>

	<!-- 安全认证过滤器 -->
	<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
		<property name="securityManager" ref="securityManager" /><!-- 
			<property name="loginUrl" value="${cas.server.url}?service=${cas.project.url}${adminPath}/cas" 
			/> -->
		<property name="loginUrl" value="${cas.server.url}?service=${cas.project.url}${adminPath}/cas" />
		<property name="successUrl" value="${cas.project.url}" />
		<property name="filters">
			<map>
				<entry key="cas" value-ref="casFilter" />
				<entry key="authc" value-ref="formAuthenticationFilter" />
			</map>
		</property>
		<property name="filterChainDefinitions">
			<ref bean="shiroFilterChainDefinitions" />
		</property>
	</bean>

	<!-- CAS认证过滤器 -->
	<bean id="casFilter" class="org.apache.shiro.cas.CasFilter">
		<property name="failureUrl" value="${adminPath}/login" />
	</bean>
	<!--这个是自定义的Realm,和网上的一样-->
	<bean id="casRealm" class="com.capinfo.hwxt.modules.sys.security.ShiroDbRealm">
        <!-- 认证通过后的默认角色 -->
        <property name="defaultRoles" value="ROLE_USER" />
        <!-- cas服务端地址前缀 -->
        <property name="casServerUrlPrefix" value="${cas.server.url}" />
        <!-- 应用服务地址,用来接收cas服务端票据 -->
		第二个关键点来了:
			这块是当前客户端的验证服务所以和上面第一个注意的地方要对应起来。
			${adminPath}/cas正好是cas过滤器匹配的url。这是重中之重!!!!
		
        <property name="casService" value="${cas.project.url}${adminPath}/cas" />
    </bean>
	<!-- 定义Shiro安全管理配置 -->
	<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
		<property name="realm" ref="casRealm" />
		<property name="sessionManager" ref="sessionManager" />
		<property name="cacheManager" ref="shiroCacheManager" />
	</bean>

	<!-- 自定义会话管理配置 -->
	<bean id="sessionManager"
		class="com.capinfo.hwxt.common.security.shiro.session.SessionManager">
		<property name="sessionDAO" ref="sessionDAO" />
		<property name="sessionListeners" ref="userSessionListener" /> 
		<!-- 会话超时时间,单位:毫秒 -->
		<property name="globalSessionTimeout" value="${session.sessionTimeout}" />

		<!-- 定时清理失效会话, 清理用户直接关闭浏览器造成的孤立会话 -->
		<property name="sessionValidationInterval" value="${session.sessionTimeoutClean}" />
		<!-- <property name="sessionValidationSchedulerEnabled" value="false"/> -->
		<property name="sessionValidationSchedulerEnabled" value="true" />

		<property name="sessionIdCookie" ref="sessionIdCookie" />
		<property name="sessionIdCookieEnabled" value="true" />
		 
	</bean>

 	<bean id="userSessionListener" class="com.capinfo.hwxt.modules.sys.listener.UserSessionListener">
 	</bean>
	<!-- 指定本系统SESSIONID, 默认为: JSESSIONID 问题: 与SERVLET容器名冲突, 如JETTY, TOMCAT 等默认JSESSIONID, 
		当跳出SHIRO SERVLET时如ERROR-PAGE容器会为JSESSIONID重新分配值导致登录会话丢失! -->
	<bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
		<constructor-arg name="name" value="jrjjg.session.id" />
	</bean>

	<!-- 自定义Session存储容器 -->
	<!-- <bean id="sessionDAO" class="com.capinfo.hwxt.common.security.shiro.session.JedisSessionDAO"> -->
	<!-- <property name="sessionIdGenerator" ref="idGen" /> -->
	<!-- <property name="sessionKeyPrefix" value="${redis.keyPrefix}_session_" 
		/> -->
	<!-- </bean> -->
	<bean id="sessionDAO"
		class="com.capinfo.hwxt.common.security.shiro.session.CacheSessionDAO">
		<property name="sessionIdGenerator" ref="idGen" />
		<property name="activeSessionsCacheName" value="activeSessionsCache" />
		<property name="cacheManager" ref="shiroCacheManager" />
	</bean>

	<!-- 定义授权缓存管理器 -->
	<!-- <bean id="shiroCacheManager" class="com.capinfo.hwxt.common.security.shiro.cache.SessionCacheManager" 
		/> -->
	<bean id="shiroCacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
		<property name="cacheManager" ref="cacheManager" />
	</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>

5.这里是xxx.propeties文件的关键配置:

cas.server.url=http://127.0.0.1:8080/cas
cas.project.url=http://127.0.0.1:8081/项目名
adminPath=/a

大家如果将我上面的两个关键位置弄明白了,重定向的问题应该就不会发生了。

总结:

不能急于求成,不了解这个shiro给我造成了很大的阻碍。

不能盲目的看别人的结论,要认清其中的原理。

如果你是第一次使用shiro和cas集成,你可以直接关注一下我标红的文字(xml中有两个重点不能标红,注意看一下)



  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
Spring Boot 是一个快速开发框架,它提供了一系列的工具和插件,可以快速构建一个企业级的应用程序。而 Shiro 是一个强大而灵活的安全框架,可以提供身份验证、授权、密码加密、会话管理等功能。CAS 是一个单点登录(SSO)协议,可以实现用户在多个应用系统中使用同一个身份验证。 下面是一个简单的 Spring Boot + Shiro + CAS 的示例应用程序: 1. 创建一个 Spring Boot 应用程序,并添加依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring-boot-web-starter</artifactId> <version>1.5.3</version> </dependency> <dependency> <groupId>org.jasig.cas.client</groupId> <artifactId>cas-client-core</artifactId> <version>3.6.0</version> </dependency> ``` 2. 配置 Shiro: ```java @Configuration public class ShiroConfig { @Bean public CasRealm casRealm() { CasRealm realm = new CasRealm(); realm.setCasServerUrlPrefix("https://cas.example.com/cas"); realm.setCasService("https://myapp.example.com/cas"); realm.setDefaultRoles("user"); realm.setRoleAttributeNames("memberOf"); return realm; } @Bean public DefaultWebSecurityManager securityManager() { DefaultWebSecurityManager manager = new DefaultWebSecurityManager(); manager.setRealm(casRealm()); return manager; } @Bean public ShiroFilterFactoryBean shiroFilter() { ShiroFilterFactoryBean filter = new ShiroFilterFactoryBean(); filter.setSecurityManager(securityManager()); filter.setLoginUrl("https://cas.example.com/cas/login?service=https://myapp.example.com/cas"); filter.setSuccessUrl("/home"); filter.setUnauthorizedUrl("/403"); filter.setFilterChainDefinitionMap(Collections.singletonMap("/**", "authc")); return filter; } } ``` 3. 配置 CAS: ```java @Configuration public class CasConfig { @Bean public CasAuthenticationFilter casAuthenticationFilter() { CasAuthenticationFilter filter = new CasAuthenticationFilter(); filter.setCasServerLoginUrl("https://cas.example.com/cas/login"); filter.setServerName("https://myapp.example.com/cas"); filter.setAuthenticationSuccessHandler(authenticationSuccessHandler()); filter.setAuthenticationFailureHandler(authenticationFailureHandler()); return filter; } @Bean public SimpleUrlAuthenticationSuccessHandler authenticationSuccessHandler() { SimpleUrlAuthenticationSuccessHandler handler = new SimpleUrlAuthenticationSuccessHandler(); handler.setDefaultTargetUrl("/home"); handler.setAlwaysUseDefaultTargetUrl(true); return handler; } @Bean public SimpleUrlAuthenticationFailureHandler authenticationFailureHandler() { SimpleUrlAuthenticationFailureHandler handler = new SimpleUrlAuthenticationFailureHandler(); handler.setDefaultFailureUrl("/login?error=true"); return handler; } @Bean public FilterRegistrationBean<CasAuthenticationFilter> casFilterRegistrationBean() { FilterRegistrationBean<CasAuthenticationFilter> registration = new FilterRegistrationBean<>(); registration.setFilter(casAuthenticationFilter()); registration.addUrlPatterns("/*"); registration.setName("CAS Authentication Filter"); registration.setOrder(1); return registration; } @Bean public ServletListenerRegistrationBean<SingleSignOutHttpSessionListener> singleSignOutHttpSessionListener() { ServletListenerRegistrationBean<SingleSignOutHttpSessionListener> registration = new ServletListenerRegistrationBean<>(); registration.setListener(new SingleSignOutHttpSessionListener()); registration.setOrder(2); return registration; } @Bean public ServletRegistrationBean<Servlet> casValidationServletRegistrationBean() { ServletRegistrationBean<Servlet> registration = new ServletRegistrationBean<>(); registration.setServlet(new Cas20ProxyReceivingTicketValidationFilter()); registration.addUrlMappings("/cas/*"); registration.setName("CAS Validation Filter"); registration.setOrder(3); return registration; } } ``` 4. 创建一个 HomeController: ```java @Controller public class HomeController { @GetMapping("/home") public String home() { return "home"; } @GetMapping("/403") public String error403() { return "403"; } } ``` 5. 创建一个 CAS 认证服务器: ```java @SpringBootApplication public class CasServerApplication { public static void main(String[] args) { SpringApplication.run(CasServerApplication.class, args); } } ``` 6. 创建一个 CAS 客户端: ```java @SpringBootApplication @EnableScheduling public class CasClientApplication { public static void main(String[] args) { SpringApplication.run(CasClientApplication.class, args); } } ``` 这就是一个简单的 Spring Boot + Shiro + CAS 的示例应用程序。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值