1. 程式人生 > >java鬼混筆記:shiro 11、唯一登入和登入退出Bug

java鬼混筆記:shiro 11、唯一登入和登入退出Bug

完整的專案下載路徑(專案下載網上的hui框架來著,什麼鬼檔案都在裡面,暫清除,所以很多):
http://download.csdn.net/download/u013845177/9992748
相關的lib包路徑:
http://download.csdn.net/download/u013845177/9992728

這次的筆記是在執行程式時,發現一個問題,今天才有空處理。問題舉例來講吧:比如使用者A第1次登入後,由於設定了唯一登入,用了Deque儲存使用者的sessionId,當用戶A退出時, session是清空了,但是Deque中沒有清空。第二次A再次登入,這時Deque又把sessionid放進去,這時Deque中sessionid 有兩個,由於設定了唯一登入,這時要清空第1次登入的sessionid對應的session,但是第1次sessionid清空了,找不到了,所以報了session找不到,控制檯紅紅的。。。

解決方案:自定義一個退出類,手動清空Deque。上程式碼...

package cn.common;

import java.io.Serializable;
import java.util.Deque;
import java.util.LinkedList;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.session.SessionException;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.LogoutFilter;

import cn.entity.User;

public class LSLogoutFilter extends LogoutFilter {
	
	private Cache<String, Deque<Serializable>> cache;
	private CacheManager cacheManager;
	
	public CacheManager getCacheManager() {
		return cacheManager;
	}
	public void setCacheManager(CacheManager cacheManager) {
		 this.cache = cacheManager.getCache("shiro-kickout-session");
	}


	@Override
	protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
		Subject subject = getSubject(request, response);

		String redirectUrl = getRedirectUrl(request, response, subject);

		try {
			// 獲取退出使用者的資訊
			User user = (User) subject.getPrincipal();
			LinkedList ll = (LinkedList) cache.get(user.getUserName());// 找到這個使用者在快取中的Deque
			if(ll != null) {
				ll.removeLast();// 根據LinkedList機制,清空最後一個sessionid
			}
			cache.put(user.getUserName(), ll);// 放回去
			subject.logout();
		} catch (SessionException ise) {
			ise.printStackTrace();
		}
		issueRedirect(request, response, redirectUrl);
		return false;
	}
}

接著在applicationContext-shiro.xml加入這個bean
<!-- 自定義退出功能 -->
<bean id="lSLogoutFilter" class="cn.common.LSLogoutFilter">
 <property name="cacheManager" ref="cacheManager"/>    
</bean>

同時在<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">中加入紅色的程式碼:
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
		<property name="securityManager" ref="securityManager" />
		
		<property name="filters">
			<map>
				<entry key="authc" value-ref="LSFormAuthenticationFilter" /><!-- 配置自定義的form過濾器 -->
				<entry key="kickout" value-ref="kickoutSessionControlFilter"/><!-- 踢人 -->
				<entry key="logout" value-ref="lSLogoutFilter"/><!-- 退出 -->
			</map>
		</property>
		
		<!-- 沒有登入就跳到這 -->
		<property name="loginUrl" value="/login.do" />
		
		<!-- successUrl認證成功後跳轉的url,去掉,因為實際中,比如successUrl對應的是A頁,
		我在訪問C頁面時,有一個功能是要登入才可以操作的,如果我配置了successUrl,那麼我登入成功之後會跳轉A頁面,然後我再各種點點點才回到C頁面,
		這就很蛋疼了,如果我沒配置 successUrl,那麼在登入之後,shiro會自動跳轉到上一個url,也是登入頁面前一個url,那就是C頁面的url,也就是C頁面跳轉到登入頁面後,成功登入後直接返回到C頁面,我就可以繼續在C頁面做事了-->
		<!-- <property name="successUrl" value="index.do"/> -->
		<property name="filterChainDefinitions">
			<value>
				/ssiupload/** = anon
				/up.jsp = anon
				<!-- logout.do shiro自己清空session -->
				/logout.do = logout<!-- 注意這裡引用退出-->
OK。。。