Apache Shiro去掉URL中的JSESSIONID

转自: https://blog.csdn.net/yyf314922957/article/details/51038322

最近集成框架用到shiro碰到url有时候会带上jsessionid有时候又没有。以前也碰到但是没有深入研究。

网上查了半天各种方法用了都没用。比如web.xml里面加session-config,添加DisableUrlSessionFilter 等等神马都没用。于是自己研究源码。说了半天废话终于进入正题。先申明下我是菜鸟。说的不对的错的请无视。有些是网上复制的。

先说下为什么网上那些玩意没用。

我们一般用的是DefaultWebSessionManager。shiro默认的是ServletContainerSessionManager这个非常简单的实现代表所有会话管理职责(包括会话集群如果 servlet 容器支持)运行 servlet 容器。 它本质上是一个桥 Shiro 会话 API 的 servlet 容器,没有别的。使用这个默认的一个好处是,使用现有的 servlet 容器的应用程序会话配置(超时,任何特定容器集群机制等)将正常工作。这个默认的缺点是,你与 servlet 容器的特定会话行为。 举个例子,如果你想集群会话,但你使用 Jetty 在生产、测试和 Tomcat 容器配置(或代码)将不具有可移植性。所以我们用DefaultWebSessionManager Shiro 的原生会话管理。所以网上的那些基于servlet 的不起作用。如果你用ServletContainerSessionManager也不存在这个问题。(后续有时间我会说说shiro和redis的集成。用redis管理session和cache。我是看了spring session、spring data redis的源码改造的所以跟spring能很好的集成具体后面再说。)

下面分析源码。先说下shiro的每次访问都会构建subject。

假设我们首次访问系统的登陆界面。然后我们登陆。在我们点击登陆之后会访问DefaultSecurityManager构建Subject。创建Subject之前会做很多事(创建cookie和session等等)其中会访问一下DefaultWebSessionManager的getReferencedSessionId方法。方法里面判断cookie里面是否有sessionid。肯定是没有的啦所以不会向request里面存放ShiroHttpServletRequest的3个静态属性。然后在org.apache.shiro.web.filter.authc.FormAuthenticationFilter登陆成功跳转页面的时候。issueSuccessRedirect方法里面会判断request是否有ShiroHttpServletRequest.COOKIE_SESSION_ID_SOURCE如果有直接跳转到成功页面。具体判断的代码在ShiroHttpServletRequest里面的isRequestedSessionIdFromURL方法上。如果没有会在跳转成功页面url后面加上JSESSIONID。所以url上就多出了JSESSIONID.然后跳转首页时又会访问DefaultSecurityManager构建Subject。同样会进DefaultWebSessionManager的getReferencedSessionId方法这个时候sessionid有值所以request里面存放了

ShiroHttpServletRequest.COOKIE_SESSION_ID_SOURCE。这就是为什么我们删掉JSESSIONID他又不加上的原因。因为你后面每次访问。构建subject的时候sessionid有值request的里面也有值他就不会在url上加JSESSIONID了啊。假设我们删除浏览器cookie这个时候没有了sessionid。我们访问当前地址。同样会创建Subject。由于sessionid没有了所以request里面就不会存值了。然后会进入org.apache.shiro.web.filter.authc.UserFilter判断subject是否有认证信息。没有会通过saveRequestAndRedirectToLogin跳转到登陆页面。saveRequestAndRedirectToLogin里面判断request是否有值没值又会在跳转页面的url上加上JSESSIONID。然后进入登陆界面的时候构建subject 创建session request里面存值。好了说完了。看不懂得自己脑补把。

[java]  view plain  copy
  1. <code class="language-java">private Serializable getReferencedSessionId(ServletRequest request, ServletResponse response) {  
  2.   
  3.         String id = getSessionIdCookieValue(request, response);  
  4.         if (id != null) {  
  5.             request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE,  
  6.                     ShiroHttpServletRequest.COOKIE_SESSION_ID_SOURCE);  
  7.         } else {  
  8.             //not in a cookie, or cookie is disabled - try the request URI as a fallback (i.e. due to URL rewriting):  
  9.   
  10.             //try the URI path segment parameters first:  
  11.             id = getUriPathSegmentParamValue(request, ShiroHttpSession.DEFAULT_SESSION_ID_NAME);  
  12.   
  13.             if (id == null) {  
  14.                 //not a URI path segment parameter, try the query parameters:  
  15.                 String name = getSessionIdName();  
  16.                 id = request.getParameter(name);  
  17.                 if (id == null) {  
  18.                     //try lowercase:  
  19.                     id = request.getParameter(name.toLowerCase());  
  20.                 }  
  21.             }  
  22.             if (id != null) {  
  23.                 request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE,  
  24.                         ShiroHttpServletRequest.URL_SESSION_ID_SOURCE);  
  25.             }  
  26.         }  
  27.       </code>  


  1. public boolean isRequestedSessionIdFromURL() {
  2. if (isHttpSessions()) {
  3. return super.isRequestedSessionIdFromURL();
  4. } else {
  5. String value = (String) getAttribute(REFERENCED_SESSION_ID_SOURCE);
  6. return value != null && value.equals(URL_SESSION_ID_SOURCE);
  7. }
  8. }

我的办法在每次跳转之前就判断sessionid是否有值。因为每次跳转之前subject就已经创建了session。至于如果禁用cookies。同样还是会在url上加上jsessionid。我们只是把判断给至前了。并没有修改原有逻辑。具体代码如下

  1. /**
  2.  * clear JSESSIONID in URL if session id is not null 
  3.  * {@link DefaultWebSessionManager} getReferencedSessionId
  4.  * {@link ShiroHttpServletRequest} isRequestedSessionIdFromURL
  5.  * 
  6.  * @author Infinite Justice
  7.  */
  8. public class UserFilter extends AccessControlFilter{
  9.     
  10.     private Cookie sessionIdCookie;
  11.     
  12.     public Cookie getSessionIdCookie() {
  13.         return sessionIdCookie;
  14.     }
  15.     public void setSessionIdCookie(Cookie sessionIdCookie) {
  16.         this.sessionIdCookie = sessionIdCookie;
  17.     }
  18.     
  19.     @Override
  20.     protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
  21.         if (isLoginRequest(request, response)) {
  22.             return true;
  23.         } else {
  24.             Subject subject = getSubject(request, response);
  25.             // If principal is not null, then the user is known and should be allowed access.
  26.             return subject.getPrincipal() != null;
  27.         }
  28.     }
  29.     
  30.     @Override
  31.     protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
  32.         saveRequest(request);
  33.         String sessionid = sessionIdCookie.readValue(WebUtils.toHttp(request), WebUtils.toHttp(response));
  34.         // clear JSESSIONID in URL if session id is not null 
  35.         if(sessionid != null){
  36.             request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE,ShiroHttpServletRequest.COOKIE_SESSION_ID_SOURCE);
  37.             request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, sessionid);
  38.             request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
  39.         }
  40.         redirectToLogin(request, response);
  41.         return false;
  42.     }
  43. }


  1. /**
  2.  * clear JSESSIONID in URL if session id is not null 
  3.  * {@link DefaultWebSessionManager} getReferencedSessionId
  4.  * {@link ShiroHttpServletRequest} isRequestedSessionIdFromURL
  5.  * 
  6.  * @author Infinite Justice
  7.  */
  8. public class LoginFilter extends FormAuthenticationFilter{
  9.     
  10.     private Cookie sessionIdCookie;
  11.     
  12.     public Cookie getSessionIdCookie() {
  13.         return sessionIdCookie;
  14.     }
  15.     public void setSessionIdCookie(Cookie sessionIdCookie) {
  16.         this.sessionIdCookie = sessionIdCookie;
  17.     }
  18.     @Override
  19.     protected void setFailureAttribute(ServletRequest request, AuthenticationException ae) {
  20.         request.setAttribute(getFailureKeyAttribute(), ae);
  21.     }
  22.     
  23.     @Override
  24.     protected void issueSuccessRedirect(ServletRequest request, ServletResponse response) throws Exception {
  25.         String sessionid = sessionIdCookie.readValue(WebUtils.toHttp(request), WebUtils.toHttp(response));
  26.         // clear JSESSIONID in URL if session id is not null 
  27.         if(sessionid != null){
  28.             request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE,ShiroHttpServletRequest.COOKIE_SESSION_ID_SOURCE);
  29.             request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, sessionid);
  30.             request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
  31.         }
  32.         super.issueSuccessRedirect(request, response);
  33.     }
  34. }

另一种解决办法:

  1. public class RedisWebSessionManager extends DefaultWebSessionManager {
  2. /**
  3. * Stores the Session's ID, usually as a Cookie, to associate with future requests.
  4. * @param session the session that was just{@link #createSession created}.
  5. */
  6. @Override
  7. protected void onStart(Session session, SessionContext context) {
  8. super.onStart(session, context);
  9. ServletRequest request = WebUtils.getRequest(context);
  10. request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE,ShiroHttpServletRequest.COOKIE_SESSION_ID_SOURCE);
  11. }
  12. }



——————————————————————————————黄金分割线————————————————————————————————————————

如果你的shiro版本在1.3.2版本以上这个BUG已经解决只需要在配置文件如下配置中添加红色部分


<!-- 会话管理器 -->

<bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">

<property name="sessionIdUrlRewritingEnabled" value="false" />

<!-- 验证会话时会话的过期时间(毫秒) -->

<property name="globalSessionTimeout" value="3600000" />

<property name="sessionFactory" ref="sessionFactory" />

<property name="sessionValidationScheduler" ref="redisValidationScheduler" />

<property name="sessionDAO" ref="sessionDAO" />

<property name="sessionIdCookie" ref="sessionIdCookie" />

<property name="sessionListeners">

<list>

<ref bean="redisSessionListener" />

</list>

</property>

</bean>



源代码中的解释如下

// always set rewrite flag - SHIRO-361

request.setAttribute(ShiroHttpServletRequest.SESSION_ID_URL_REWRITING_ENABLED, isSessionIdUrlRewritingEnabled());

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值