Shiro首次重定向url携带jsessionid出现400错误

发布于:2022-12-29 ⋅ 阅读:(1105) ⋅ 点赞:(0)

事发现场

将我的网盘项目部署到服务器上之后,第一次加载时不显示静态资源,但是在本地测试时,是可以显示的,可能是本地缓存的原因,当时并没有发现这个问题。
于是我关闭浏览器重新打开了本地项目,问题出现了,没有网页样式。是不是没有请求到资源?F12一看的确是这样,它报了400错误,请求的url是错的,当然找不到资源了
在这里插入图片描述
正常的请求应该是http://localhost:8080/css/xxxxx
刷新页面又正常了
在这里插入图片描述
所以解决问题的关键点就在于这个jsessionid

解决方式

方式一

我在首页添加了令牌的验证,在Shiro第一次重定向时,会重写url,带有jsessionid,它就是sessionid,是servlet容器(tomcat)用来记录用户session的。
由于这个网盘是基于SpringBoot写的,tomcat内嵌在里头,所以我首先想到的是修改yml配置,指定会话跟踪模式为cookie

# 指定会话跟踪模式为cookie
  servlet:
    session:
      tracking-modes: 'cookie'

方式二

在Shiro配置类中指定会话跟踪模式

    @Bean
    public ServletContextInitializer servletContextInitializer() {
        return new ServletContextInitializer() {
            @Override
            public void onStartup(ServletContext servletContext) throws ServletException {
                servletContext.setSessionTrackingModes(Collections.singleton(SessionTrackingMode.COOKIE) );
            }
        };
    }

方式三

我在ShiroHttpSession中找到了这个常量
在这里插入图片描述
ShiroHttpServletResponse和DefaultWebSessionManager都引用了这个常量
在这里插入图片描述
首先去ShiroHttpServletResponse这个类里看下

private static final String DEFAULT_SESSION_ID_PARAMETER_NAME = ShiroHttpSession.DEFAULT_SESSION_ID_NAME;

它将DEFAULT_SESSION_ID_NAME重新定义成了DEFAULT_SESSION_ID_PARAMETER_NAME,就是JSESSIONID
它被引用到两个方法里,doIsEncodeable和toEncoded
在这里插入图片描述
在执行doIsEncodeable方法之前,它还会在isEncodeable这个方法里判断是否需要编码

1.url重写是否全局禁用,能不能在url加session
2.有没有session
3.request的cookie有没有session

    protected boolean isEncodeable(final String location) {

        // First check if URL rewriting is disabled globally
        if (Boolean.FALSE.equals(request.getAttribute(ShiroHttpServletRequest.SESSION_ID_URL_REWRITING_ENABLED)))
            return (false);

        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 HttpServletRequest hreq = request;
        final HttpSession session = hreq.getSession(false);
        if (session == null)
            return (false);
        if (hreq.isRequestedSessionIdFromCookie())
            return (false);

        return doIsEncodeable(hreq, session, location);
    }

满足条件后会执行doIsEncodeable,在url后添加jsessionid

        String contextPath = getRequest().getContextPath();
        if (contextPath != null) {
            String file = url.getFile();
            if ((file == null) || !file.startsWith(contextPath))
                return (false);
            String tok = ";" + DEFAULT_SESSION_ID_PARAMETER_NAME + "=" + session.getId();
            if (file.indexOf(tok, contextPath.length()) >= 0)
                return (false);
        }

        // This URL belongs to our web application, so it is encodeable
        return (true);

toEncoded也是一种编码方式,但只需要两个参数url和sessionid

    protected String toEncoded(String url, String sessionId) {

        if ((url == null) || (sessionId == null))
            return (url);

        String path = url;
        String query = "";
        String anchor = "";
        int question = url.indexOf('?');
        if (question >= 0) {
            path = url.substring(0, question);
            query = url.substring(question);
        }
        int pound = path.indexOf('#');
        if (pound >= 0) {
            anchor = path.substring(pound);
            path = path.substring(0, pound);
        }
        StringBuilder sb = new StringBuilder(path);
        if (sb.length() > 0) { // session id param can't be first.
            sb.append(";");
            sb.append(DEFAULT_SESSION_ID_PARAMETER_NAME);
            sb.append("=");
            sb.append(sessionId);
        }
        sb.append(anchor);
        sb.append(query);
        return (sb.toString());

    }

再看DefaultWebSessionManager这个类,在它的构造方法里,发现了
this.sessionIdUrlRewritingEnabled = false;

    public DefaultWebSessionManager() {
        Cookie cookie = new SimpleCookie(ShiroHttpSession.DEFAULT_SESSION_ID_NAME);
        cookie.setHttpOnly(true); //more secure, protects against XSS attacks
        this.sessionIdCookie = cookie;
        this.sessionIdCookieEnabled = true;
        this.sessionIdUrlRewritingEnabled = false;
    }

也就是说,我在Shiro配置类里初始化一个DefaultWebSessionManager就好了,因为它的sessionIdUrlRewritingEnabled默认是false

    @Bean
    public DefaultWebSecurityManager securityManager(@PathVariable("userRealm") UserRealm userRealm,
                                                     @PathVariable("sessionManager") DefaultWebSessionManager sessionManager){
        DefaultWebSecurityManager manager=new DefaultWebSecurityManager();
        manager.setRealm(userRealm);

        sessionManager.setSessionIdUrlRewritingEnabled(false);
        manager.setSessionManager(sessionManager);
        manager.setRememberMeManager(manager.getRememberMeManager());
        return manager;
    }
    @Bean
    public DefaultWebSessionManager sessionManager(){
        return new DefaultWebSessionManager();
    }
本文含有隐藏内容,请 开通VIP 后查看