亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定

奇怪的;jsessionid

標簽:
JavaScript

背景

由于最近在整理session&cookie的一些原理https://my.oschina.net/qixiaobo025/blog?search=session

我们可以看到在cookie没有开启的情况下 servlet会通过传输sessionid来完成用户的标识~

我们来考虑这个问题,服务端如何来判断客户端是否开启cookie了呢???


问题

对于cookie是否禁用 在客户端的判断比较容易 但是在服务端来说基本不太现实。

我们可以判断cookie被启用 但是比较难以判断cookie是被禁用的。毕竟当客户端没有传入cookie

也有可能是客户端第一次访问而已。那么如何判断是否是cookie被禁用呢?

一个简单能思考到的方案如下:

  1. 客户端访问指定url

  2. 服务端设置cookie 设置重定向

  3. 客户端重定向到服务端

  4. 服务端检查客户端有没有携带cookie 携带cookie则认为cookie启用否则认为cookie被禁用

考虑下列场景

请求url上增加了;jsessionid的【注意不是QueryString而是url进行了重写】

可是carOwner项目都是移动端客户 莫非移动端客户都禁止了cookie???


分析

当cookie被禁用了之后 那么为了记住用户的身份 必然需要在客户端向服务端进行请求的时候传递一些必要的信息

在cookie启用的场景下需要传递sessionId那么在cookie禁用的场景下呢?自然是通过传输sessionId

servlet在做一些response的时候帮我们做了一些事情 当我们调用response

response.encodeRedirectURL(targetUrl)
/**
 * Encode the session identifier associated with this response
 * into the specified redirect URL, if necessary.
 *
 * @param url URL to be encoded
 */@Overridepublic String encodeRedirectURL(String url) { 
    if (isEncodeable(toAbsolute(url))) {
        return (toEncoded(url, request.getSessionInternal().getIdInternal()));
    } else {
        return (url);
    }
 
}

从这段注释可以看出 当使用上述api时会自动“判断cookie是否被禁用” 

似乎很神奇 按照我们之前的描述 想要判断cookie是否被禁用至少要进行一次重定向 那servlet是怎么判断的呢???

/**
 * Return <code>true</code> if the specified URL should be encoded with
 * a session identifier.  This will be true if all of the following
 * conditions are met:
 * <ul>
 * <li>The request we are responding to asked for a valid session
 * <li>The requested session ID was not received via a cookie
 * <li>The specified URL points back to somewhere within the web
 *     application that is responding to this request
 * </ul>
 *
 * @param location Absolute URL to be validated
 */protected boolean isEncodeable(final String location) { 
    if (location == null) {        return (false);
    } 
    // Is this an intra-document reference?
    if (location.startsWith("#")) {        return (false);
    } 
    // Are we in a valid session that is not using cookies?
    final Request hreq = request;    final Session session = hreq.getSessionInternal(false);    if (session == null) {        return (false);
    }    if (hreq.isRequestedSessionIdFromCookie()) {        return (false);
    } 
    // Is URL encoding permitted
    if (!hreq.getServletContext().getEffectiveSessionTrackingModes().
            contains(SessionTrackingMode.URL)) {        return false;
    } 
    if (SecurityUtil.isPackageProtectionEnabled()) {        return (
            AccessController.doPrivileged(new PrivilegedAction<Boolean>() { 
            @Override
            public Boolean run(){                return Boolean.valueOf(doIsEncodeable(hreq, session, location));
            }
        })).booleanValue();
    } else {        return doIsEncodeable(hreq, session, location);
    }
} 
private boolean doIsEncodeable(Request hreq, Session session,
                               String location) {    // Is this a valid absolute URL?
    URL url = null;    try {
        url = new URL(location);
    } catch (MalformedURLException e) {        return (false);
    } 
    // Does this URL match down to (and including) the context path?
    if (!hreq.getScheme().equalsIgnoreCase(url.getProtocol())) {        return (false);
    }    if (!hreq.getServerName().equalsIgnoreCase(url.getHost())) {        return (false);
    }
    int serverPort = hreq.getServerPort();    if (serverPort == -1) {        if ("https".equals(hreq.getScheme())) {
            serverPort = 443;
        } else {
            serverPort = 80;
        }
    }
    int urlPort = url.getPort();    if (urlPort == -1) {        if ("https".equals(url.getProtocol())) {
            urlPort = 443;
        } else {
            urlPort = 80;
        }
    }    if (serverPort != urlPort) {        return (false);
    }
 
    String contextPath = getContext().getPath();    if (contextPath != null) {
        String file = url.getFile();        if (!file.startsWith(contextPath)) {            return (false);
        }
        String tok = ";" +
                SessionConfig.getSessionUriParamName(request.getContext()) +                "=" + session.getIdInternal();        if( file.indexOf(tok, contextPath.length()) >= 0 ) {            return (false);
        }
    } 
    // This URL belongs to our web application, so it is encodeable
    return (true);
 
}

从这段代码来看当且仅当 当前请求中并没有从cookie中获取到session 【另外就是允许在url中跟踪用户===》目前tomcat均是默认开启】

并且当前重定向url必须和当前port contextPath相同的场景下将会在url上添加上sessionId【需要额外处理url中包含了sessionId的场景】

从这种情况下来看其实并没有判断服务端cookie是否被禁用【当然cookie被禁用了之后也能走到这段逻辑,自然也是OK的】


复盘

判断我们车主端使用跳转来指定页面 通常需要微信用户授权后跳转到首页

/**
 * 微信授权回调接口
 */@RequestMapping(value = "/wxRedirect")public String wxRedirect(HttpServletRequest request, String code, String state) throws Exception {
    String[] params = state.split("\\|");    if (!TextUtils.isEmpty(code) && params.length == 2) {
        PappStation pappStation = wxStationService.getPappStationbyWxAppId(params[0]);        if (pappStation != null) {
            OauthAPI oauthAPI = new OauthAPI(wxConfigService.getConfig(pappStation));
            OauthGetTokenResponse response = oauthAPI.getToken(code);            if (response.getErrcode() == null || ResultType.SUCCESS.getCode().toString().equals(response.getErrcode())) {
                SessionUtil.saveToSession(request, SessionUtil.KEY_APP, pappStation);
                GetUserInfoResponse userinfo = oauthAPI.getUserInfo(response.getAccessToken(), response.getOpenid());                //保存或更新用户信息
                wxUserService.createOrUpdateUser(createUserObject(userinfo, pappStation.getWxAppId()));
                Puser puser = wxUserService.getUserInfoByOpenId(response.getOpenid());
                SessionUtil.saveToSession(request, SessionUtil.KEY_USER, puser);                //重定向到用户实际访问的页面
                return "redirect:" + mConstant.getClientUrl() + "?appid=" + params[0]
                        + "&openid=" + response.getOpenid() + "#" + params[1];
            } else {
                J2Cache.getChannel().evict("apiConfig", pappStation.getWxAppId());
                logger.warn("clear cache for {}", pappStation.getWxAppId());
            }
        }
    }    return "redirect:" + mConstant.getClientErrorPage();
}

其实springmvc在使用redirect的时候其实走到了RedirectView

/**
 * Convert model to request parameters and redirect to the given URL.
 * @see #appendQueryProperties
 * @see #sendRedirect
 */@Overrideprotected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request,
      HttpServletResponse response) throws IOException {
 
   String targetUrl = createTargetUrl(model, request);
   targetUrl = updateTargetUrl(targetUrl, model, request, response);
 
   FlashMap flashMap = RequestContextUtils.getOutputFlashMap(request);   if (!CollectionUtils.isEmpty(flashMap)) {
      UriComponents uriComponents = UriComponentsBuilder.fromUriString(targetUrl).build();
      flashMap.setTargetRequestPath(uriComponents.getPath());
      flashMap.addTargetRequestParams(uriComponents.getQueryParams());
      FlashMapManager flashMapManager = RequestContextUtils.getFlashMapManager(request);      if (flashMapManager == null) {         throw new IllegalStateException("FlashMapManager not found despite output FlashMap having been set");
      }
      flashMapManager.saveOutputFlashMap(flashMap, request, response);
   }
 
   sendRedirect(request, response, targetUrl, this.http10Compatible);
} 
 
 
/**
 * Send a redirect back to the HTTP client
 * @param request current HTTP request (allows for reacting to request method)
 * @param response current HTTP response (for sending response headers)
 * @param targetUrl the target URL to redirect to
 * @param http10Compatible whether to stay compatible with HTTP 1.0 clients
 * @throws IOException if thrown by response methods
 */protected void sendRedirect(HttpServletRequest request, HttpServletResponse response,
      String targetUrl, boolean http10Compatible) throws IOException {
 
   String encodedRedirectURL = response.encodeRedirectURL(targetUrl);   if (http10Compatible) {      if (this.statusCode != null) {
         response.setStatus(this.statusCode.value());
         response.setHeader("Location", encodedRedirectURL);
      }      else {         // Send status code 302 by default.
         response.sendRedirect(encodedRedirectURL);
      }
   }   else {
      HttpStatus statusCode = getHttp11StatusCode(request, response, targetUrl);
      response.setStatus(statusCode.value());
      response.setHeader("Location", encodedRedirectURL);
   }
}

很明显这边调用了

response.encodeRedirectURL(targetUrl)

而根据我们上面描述就是 当该请求并没有cookie中获取到session中时 一旦调用encodeRedirectURL 那么在默认场景下将会使得url被重写

当然除了该接口encodeRedirectUrl之外还有

/**
 * Encode the session identifier associated with this response
 * into the specified URL, if necessary.
 *
 * @param url URL to be encoded
 */@Overridepublic String encodeURL(String url) {
 
    String absolute;    try {
        absolute = toAbsolute(url);
    } catch (IllegalArgumentException iae) {        // Relative URL
        return url;
    } 
    if (isEncodeable(absolute)) {        // W3c spec clearly said
        if (url.equalsIgnoreCase("")) {
            url = absolute;
        } else if (url.equals(absolute) && !hasPath(url)) {
            url += '/';
        }        return (toEncoded(url, request.getSessionInternal().getIdInternal()));
    } else {        return (url);
    }
 
}

作者:Mr_Qi                    

来源:https://my.oschina.net/qixiaobo025/blog/1794325

點擊查看更多內容
TA 點贊

若覺得本文不錯,就分享一下吧!

評論

作者其他優質文章

正在加載中
  • 推薦
  • 評論
  • 收藏
  • 共同學習,寫下你的評論
感謝您的支持,我會繼續努力的~
掃碼打賞,你說多少就多少
贊賞金額會直接到老師賬戶
支付方式
打開微信掃一掃,即可進行掃碼打賞哦
今天注冊有機會得

100積分直接送

付費專欄免費學

大額優惠券免費領

立即參與 放棄機會
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號

舉報

0/150
提交
取消