关于shiro使用时候,cookie被禁用的处理

        在shiro使用过程中,保持客户端的状态是通过两种方式关联。一种方式是通过cookie返回,一种是通过重定向回写url。但是重定向解决不了ajax请求。 如果客户端禁用了cookie,会导致shiro无法获得seesion保存的认证,授权信息。导致shiro无法使用。

        解决思路:在客户端与服务端进行交互之前,普通请求通过重定向会写url带上会话信息。ajax请求通过写消息头形式,返回特定错误让客户端获取相应头得到seesionId。如果请求后台没有用到seesion,可以不用先获取会话,否则所有的请求都必须先获得会话。

客户端获取到消息头后,保存会话id,每次请求在通过header带上会话信息(一定要带上,特别是重定向的请求,必须从url获取到会话id)。

        也可以不需要先获取认证信息,如果使用cookie形式的方式,是不需要先获的会话。服务端使用了会话,自动写cookie到客户端。但是禁用了cookie,服务端产生了会话,相应得到了正确处理,然后在响应头里写消息头,客户端每次请求都从消息头里获取会话id,当然这样实现也是可以的。


代码如下,兼容cookie模式。

public class OssWebSessionManager extends DefaultWebSessionManager implements WebSessionManager {
  
	private static final Logger log = LoggerFactory.getLogger(OssWebSessionManager.class);
	
	private boolean sessionIdHeaderEnabled;
	 
	public static final String HEADER_SESSION_NAME = "X-AUTH-SESSION";
	
	public static final String HEADER_SESSION_ID_SOURCE = "header";
   
     public OssWebSessionManager() {
         super();
         //重定向无法手动带上header
         super.setSessionIdUrlRewritingEnabled(true);
         sessionIdHeaderEnabled=true;
     }
     
     @Override
     protected Session createExposedSession(Session session,SessionContext context) {
    	 return super.createExposedSession(session, context);
     }
     
     @Override
     protected Session createExposedSession(Session session, SessionKey key) {
    	 return super.createExposedSession(session, key);
     }
      
     @Override
     protected void onStart(Session session, SessionContext context) {
         super.onStart(session, context);

         HttpServletRequest request = WebUtils.getHttpRequest(context);
         HttpServletResponse response = WebUtils.getHttpResponse(context);
         //用header存储会话sessionId
         if (sessionIdHeaderEnabled) {
             Serializable sessionId = session.getId();
             storeSessionId(sessionId, request, response);
         } 
     }
     
     @Override
     public Serializable getSessionId(SessionKey key) {
         Serializable id = super.getSessionId(key);
         if(null != id){
        	 return id;
         }
         if (WebUtils.isWeb(key)) {
             ServletRequest request = WebUtils.getRequest(key);
             ServletResponse response = WebUtils.getResponse(key);
             id = getHeaderSessionId(request, response);
         }
         return id;
     }

   
     protected Serializable getHeaderSessionId(ServletRequest request, ServletResponse response) {
    	 String id=getHeaderSessionId((HttpServletRequest)request);
    	 if (id != null) {
             request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE,OssWebSessionManager.HEADER_SESSION_ID_SOURCE);
         }
    	 if (id != null) {
             request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, id);
             request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
         }
         request.setAttribute(ShiroHttpServletRequest.SESSION_ID_URL_REWRITING_ENABLED, isSessionIdUrlRewritingEnabled());
         return id;
     }
     
     @Override
     protected void onExpiration(Session s, ExpiredSessionException ese, SessionKey key) {
         super.onInvalidation(s, ese, key);
         onInvalidation(key);
     }
	
     @Override
     protected void onInvalidation(Session session, InvalidSessionException ise, SessionKey key) {
         super.onInvalidation(session, ise, key);
         onInvalidation(key);
     }
     
     @Override
     protected void onStop(Session session, SessionKey key) {
         super.onStop(session, key);
         onInvalidation(key);
     }
     
     @Override
     public boolean isServletContainerSessions() {
         return false;
     }

     private void storeSessionId(Serializable currentId, HttpServletRequest request, HttpServletResponse response) {
         if (currentId == null) {
             String msg = "sessionId cannot be null when persisting for subsequent requests.";
             throw new IllegalArgumentException(msg);
         }
         response.setHeader(OssWebSessionManager.HEADER_SESSION_NAME,currentId.toString());
         log.trace("Set session ID  header for session with id {}", currentId.toString());
     }
     
     /**
      * 获取请求的token
      */
     private String getHeaderSessionId(HttpServletRequest httpRequest){
    	 String sessionId=null;
    	 //从header中获取session
    	 sessionId = httpRequest.getHeader(OssWebSessionManager.HEADER_SESSION_NAME);
         //如果header中不存在token,则从参数中获取token
         if(!StringUtils.hasText(sessionId)){
        	 sessionId = httpRequest.getParameter(OssWebSessionManager.HEADER_SESSION_NAME);
         }
         return sessionId;
     }
     
     private void onInvalidation(SessionKey key) {
    	 if (WebUtils.isWeb(key)) {
        	 ServletResponse response = WebUtils.getResponse(key);
        	 if(null != response){
        		 ((HttpServletResponse)response).addHeader(OssWebSessionManager.HEADER_SESSION_NAME, "");
        	 }
         }
     }

	public boolean isSessionIdHeaderEnabled() {
		return sessionIdHeaderEnabled;
	}

	public void setSessionIdHeaderEnabled(boolean sessionIdHeaderEnabled) {
		this.sessionIdHeaderEnabled = sessionIdHeaderEnabled;
	}
}

需要认证的请求
public class OssAuthenticationFilter extends AuthenticationFilter {

	private static final Logger log = LoggerFactory.getLogger(OssAuthenticationFilter.class);

		
	@Override
	protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
		Subject subject=SecurityUtils.getSubject();
		if(isRelogin( request,  response, subject)){
			return false; 
		}
		return subject.isAuthenticated();
	}
	
	protected  boolean isRelogin(ServletRequest request, ServletResponse response,Subject subject) throws IOException{
		Session session=subject.getSession(false);
		if(null == session){
			 if(isAjax(request)){
					//无法手动带上sessionId,从消息头获取sessionId
				    session=subject.getSession();
	            	response.getWriter().write(JSON.toJSONString(ResultBuilder.genExpResult(new AppBizException(AppExcCodesEnum.SESSION_TIMEOUT))));
	            }else{
	            	request.setAttribute(ShiroHttpServletRequest.SESSION_ID_URL_REWRITING_ENABLED, true);
	                this.saveRequestAndRedirectToLogin(request, response);
	            }
			 return true;
		}
		return false;
	}
	
	protected  boolean isAjax(ServletRequest request){
        String header = ((HttpServletRequest) request).getHeader("X-Requested-With");
        if("XMLHttpRequest".equalsIgnoreCase(header)){
            return Boolean.TRUE;
        }
        return Boolean.FALSE;
    }

}


	
不需要认证,只需要有会话的请求
public class OssNoAuthenticationFilter extends OssAuthenticationFilter {

	private static final Logger log = LoggerFactory.getLogger(OssNoAuthenticationFilter.class);
	
	@Override
	protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
		Subject subject=SecurityUtils.getSubject();
		if(isRelogin( request,  response, subject)){
			return false; 
		}
		return true;
	}
}


shiro过滤器配置
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">  
	    <!-- Shiro的核心安全接口,这个属性是必须的 -->  
	    <property name="securityManager" ref="securityManager"/>  
	    <!-- 要求登录时的链接(可根据项目的URL进行替换),非必须的属性,默认会自动寻找Web工程根目录apos.htmlhtml"页面 -->
	    <property name="loginUrl" value="${shiro.loginUrl}"/>
	    <!-- 登录成功后要跳转的连接 -->  
	    <property name="successUrl" value="/sys/manager/index"/>
	    <!-- 用户访问未对其授权的资源时,所显示的连接 -->  
	    <!-- 若想更明显的测试此属性可以修改它的值,如unauthor.jsp-->  
	    <property name="unauthorizedUrl" value="/sys/manager/login"/>  
	    <property name="filters">
			<map>
			<entry key="authc">
			    <bean class="tc.oss.web.shiro.OssAuthenticationFilter" />
			</entry>
			<entry key="noAuthc">
                <bean class="tc.oss.web.shiro.OssNoAuthenticationFilter" />
            </entry>
			<entry key="validCode">
                <bean class="tc.oss.web.shiro.ValidCodeAuthenticationFilter">
                     <property name="validCodeUrl" value="/sys/manager/validCode" />
                </bean>
            </entry>
			<!-- <entry key="ssl">
			    <ref bean="sslFilter" />
			</entry> -->
			</map>
		</property>
	    <property name="filterChainDefinitions">  
	        <value>
	        	/statics/**=anon
				/js/**=anon
	        	/page/**=anon
	        	/sys/manager/login=noAuthc
	        	/sys/manager/captcha=noAuthc
	        	/favicon.ico=anon
	        	/sys/manager/validCode=authc
	        	/sys/manager/commitCode=authc
	        	/**=authc
	        </value>
	    </property>
	</bean>

这样客户端禁用cookie也能用了,请求必须带上header。从url或者响应中获取
url回调的
 function refreshCode(){
	  var sid=window.location.href.split(";")[1].split("=")[1];
	  $.ajax({
	         type: "GET",
	         url: "${contextPath}/sys/manager/captcha?t=" + $.now(),
	         beforeSend: function (XMLHttpRequest) {
	        	 var sessionid = "X-AUTH-SESSION";
	        	 XMLHttpRequest.setRequestHeader(sessionid, sid);
	         },
	         success: function(r){
	        	 $("#captchaImg").attr("src",r);
	         }
	     });
  }
ajax异步请求的没测试了,应该是没问题的了


 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值