在shiro-cas中實現 Jasig-cas的Single Sign Out 功能


1 Single Sign Out 功能

即單點登出功能。也就是在任意子系統進行登出操作后,其他子系統會自動登出。

實際CAS登出的步驟為

 

所以每個子系統都需要實現一個sso登出響應。

cas-client-core包中有Single Sign Out的Session容器實現。

具體在包 org.jasig.cas.client.session 中。

 

2 實現Shiro的SSO登出功能

1 實現CasSecurityManager

主要目的是為了在登陸成功后保存 ST票據,並與 Shiro的sessionId進行關系映射。

 1 /**
 2  * 安全管理中心。<br>
 3  * 主要目的是保存session和ticket之間的關系。
 4  * @author Weicl
 5  * @since 2016.4.25
 6  */
 7 public class CasSecurityManager extends DefaultWebSecurityManager{
 8     
 9     Logger logger = LoggerFactory.getLogger(getClass());
10     
11     @Override
12     protected void onSuccessfulLogin(AuthenticationToken token,
13             AuthenticationInfo info, Subject subject) {
14         
15         if (token instanceof CasToken) {
16             logger.info("save token info: " + token.getCredentials() + " -> " + subject.getSession(false).getId());
17             SsoUtils.putTokenCache((String)token.getCredentials(), subject.getSession(false).getId());
18             subject.getSession(false).setAttribute("_serviceTicket_", token.getCredentials());
19         }
20         
21         super.onSuccessfulLogin(token, info, subject);
22     }
23 }
PS: SsoUtils的putTokenCache。可以用ehcache或HashMap實現,其實沒關系。

 

2 實現LogoutSloFilter

這個攔截器用來處理sso登出請求。

 1 /**
 2  * 單點登出處理
 3  * @author Weicl
 4  * @since 2016.4.25
 5  */
 6 public class LogoutSloFilter extends AdviceFilter{
 7     private final Logger logger = LoggerFactory.getLogger(getClass());
 8     private final Pattern pattern = Pattern.compile("<samlp:SessionIndex>([^<]*)</samlp:SessionIndex>");
 9     
10     @Autowired
11     private NativeSessionManager nativeSessionManager;
12     
13     @Override
14     protected boolean preHandle(ServletRequest request, ServletResponse response)
15             throws Exception {
16         
17         
18         try {
19             String logoutRequest = request.getParameter("logoutRequest");
20             String serviceTicket = extractServiceTicket(logoutRequest);
21             
22             logger.info(" slo serviceTicket : " + serviceTicket);
23             
24             String sessionId = (String)SsoUtils.getTokenCache(serviceTicket);
25             nativeSessionManager.stop(new DefaultSessionKey(sessionId));
26                         
27         } catch (Exception e) {
28             e.printStackTrace();
29         }
30         
31         response.getWriter().write("OK");
32         return false;
33     }
34     
35     /**
36      * 獲取登出請求中的Ticket
37      * @param logoutRequest
38      * @return
39      */
40     private String extractServiceTicket(String logoutRequest) {
41         Matcher matcher = pattern.matcher(logoutRequest);
42         if (matcher.find()) {
43             return matcher.group(1);
44         }
45         return "";
46     }
47 }

3 實現TicketSessionListener

這個類的作用是當session終止的時候,釋放 SsoUtil 中的tokenCache。因為應用的session不存在了,保存這個映射關系也沒有意義,而且浪費緩存空間。

 1 /**
 2  * 票據及session監聽器
 3  * @author Weicl
 4  * @since 2016.4.25
 5  */
 6 public class TicketSessionListener implements SessionListener{
 7 
 8     Logger logger = LoggerFactory.getLogger(getClass());
 9 
10     @Override
11     public void onStart(Session session) {
12         
13     }
14 
15     @Override
16     public void onStop(Session session) {
17         logger.info("===============================");
18         logger.info("stop session:" + session.getId());
19         
20         String ticket = (String)session.getAttribute("_serviceTicket_");
21         if (ticket != null) {
22             logger.info("remove serviceTicket: " + ticket);
23             SsoUtils.removeTokenCache(ticket);
24         }
25     }
26 
27     @Override
28     public void onExpiration(Session session) {
29         onStop(session);
30     }
31 }

4 配置到spring中

一下為添加/修正的關鍵代碼。其他shiro的配置這邊就不貼出來了。

 1     <!-- Shiro權限過濾過濾器定義 -->
 2     <bean name="shiroFilterChainDefinitions" class="java.lang.String">
 3         <constructor-arg>
 4             <value>
 5                 /static/** = anon
 6                 /cas = cas
 7                 /login = authc
 8                 /logout = logout
 9                 /logoutSlo = logoutSlo
10                 /** = user
11             </value>
12         </constructor-arg>
13     </bean>
14 
15      <!-- 安全認證過濾器 -->
16     <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
17         <property name="securityManager" ref="securityManager" />
18         <property name="loginUrl" value="${cas.server.url}/login?service=${cas.project.url}${adminPath}/cas" />
19         <!-- 
20         <property name="loginUrl" value="${adminPath}/login" /> -->
21         <property name="successUrl" value="${adminPath}/login" />
22         <property name="filters">
23             <map>
24                 <entry key="cas" value-ref="casFilter"/>
25                 <entry key="authc" value-ref="formAuthenticationFilter"/>
26                 <entry key="logout" value-ref="logoutFilter"></entry>
27                 <entry key="logoutSlo" value-ref="logoutSloFilter"></entry>
28             </map>
29         </property>
30         <property name="filterChainDefinitions">
31             <ref bean="shiroFilterChainDefinitions"/>
32         </property>
33     </bean>
34 
35     <bean id="logoutSloFilter" class="cn.xxxxxx.base.modules.sys.security.LogoutSloFilter">
36     </bean>
37     
38     <!-- 定義Shiro安全管理配置 -->
39     <bean id="securityManager" class="cn.xxxxxx.base.common.security.shiro.session.CasSecurityManager">
40         <!-- <property name="realm" ref="systemAuthorizingRealm" /> -->
41         <property name="realm" ref="systemCasRealm" />
42         <property name="sessionManager" ref="sessionManager" />
43         <property name="cacheManager" ref="shiroCacheManager" />
44     </bean>

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM