session 共享 比较邪道的实现方式

注意 :本博客 只适用于 javaweb 之间的session共享  本博客不适用 同框架做session 共享  

同框架session 共享直接做 redis session就好了 没有必要这么复杂

一般 按照正常session 共享实现逻辑 使用 redis 做session 共享 ,如果要多服务的方式的话 一般 人会考虑 单点 登录 但是 我这里使用了 session 共享 可能跟别人不一样,因为当时的发生场景是  我在既定的时间内 去 花时间做 单点登录  或者其他的解决方案可能我的项目就无法上线 领导催 没办法

 那么我该如何快速的实现 session共享 ,无视 对方的权限框架 或者是没有框架  这里使用了一个东西 spring redis session  这里的spring redis session 跟别人不一样  不是网上那种官方的配置 (配置还是一样的...)

首先集成 spring redis sesion 具体的集成 方式这里就不展示了 网上百度 博客一大堆 这都不是重点  

重点是 要使用  spring redis session 不管你的权限框架是 shiro 还是 security 因为要实现session 共享 spring 已经帮你做好了 你没有必要自己去 存 , 这就是存的实现  所谓的共享 就是 把session 存在一个地方大家都去同一个地址获取

集成完成session共享之后 你登录在redis 里面应该会有下图

这里说明你的session 保存是成功的

我这里展示的是A框架登录的信息

按照正常的思维 我 A框架做的session 共享 B框架也做了session 共享 然后读同一个 redis 是不是就能共享session 了呢

答案是否定的 这个时候 那 我们用nginx 代理一下是不是就能共享session 呢 答案也是否定的 那么我们用 nginx 做共享 cookie 呢

答案也是否定的所以 能想到的 我都考虑了 不能想到的 就不想了反正我有邪道解决方案

回归正题

这里要修改的地方并不在A框架 因为 A框架是生产者

 为什么说是生产者 看到这里的 都明白就不啰嗦了

这里贴出主要spring 的代码

我们要想实现session共享 就要对它动刀子

/*
 * Copyright 2014-2018 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.session.web.http;

import java.io.IOException;
import java.time.Instant;
import java.util.List;
import java.util.UUID;

import javax.servlet.FilterChain;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import com.zax.common.Context;
import com.zax.filter.DispacherSessionImmpl;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.core.annotation.Order;
import org.springframework.session.Session;
import org.springframework.session.SessionRepository;
import org.springframework.util.StringUtils;

/**
 * Switches the {@link javax.servlet.http.HttpSession} implementation to be backed by a
 * {@link org.springframework.session.Session}.
 *
 * The {@link SessionRepositoryFilter} wraps the
 * {@link javax.servlet.http.HttpServletRequest} and overrides the methods to get an
 * {@link javax.servlet.http.HttpSession} to be backed by a
 * {@link org.springframework.session.Session} returned by the
 * {@link org.springframework.session.SessionRepository}.
 *
 * The {@link SessionRepositoryFilter} uses a {@link HttpSessionIdResolver} (default
 * {@link CookieHttpSessionIdResolver} to bridge logic between an
 * {@link javax.servlet.http.HttpSession} and the
 * {@link org.springframework.session.Session} abstraction. Specifically:
 *
 * <ul>
 * <li>The session id is looked up using
 * {@link HttpSessionIdResolver#resolveSessionIds(javax.servlet.http.HttpServletRequest)}
 * . The default is to look in a cookie named SESSION.</li>
 * <li>The session id of newly created {@link org.springframework.session.Session} is sent
 * to the client using
 * <li>The client is notified that the session id is no longer valid with
 * {@link HttpSessionIdResolver#expireSession(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)}
 * </li>
 * </ul>
 *
 * <p>
 * The SessionRepositoryFilter must be placed before any Filter that access the
 * HttpSession or that might commit the response to ensure the session is overridden and
 * persisted properly.
 * </p>
 *
 * @param <S> the {@link Session} type.
 * @since 1.0
 * @author Rob Winch
 * @author Vedran Pavic
 */
@Order(SessionRepositoryFilter.DEFAULT_ORDER)
public class SessionRepositoryFilter<S extends Session> extends OncePerRequestFilter {

    private static final String SESSION_LOGGER_NAME = SessionRepositoryFilter.class
            .getName().concat(".SESSION_LOGGER");

    private static final Log SESSION_LOGGER = LogFactory.getLog(SESSION_LOGGER_NAME);

    /**
     * The session repository request attribute name.
     */
    public static final String SESSION_REPOSITORY_ATTR = SessionRepository.class
            .getName();

    /**
     * Invalid session id (not backed by the session repository) request attribute name.
     */
    public static final String INVALID_SESSION_ID_ATTR = SESSION_REPOSITORY_ATTR
            + ".invalidSessionId";

    private static final String CURRENT_SESSION_ATTR = SESSION_REPOSITORY_ATTR
            + ".CURRENT_SESSION";

    /**
     * The default filter order.
     */
    public static final int DEFAULT_ORDER = Integer.MIN_VALUE + 50;

    private final SessionRepository<S> sessionRepository;

    private ServletContext servletContext;

    private HttpSessionIdResolver httpSessionIdResolver = new CookieHttpSessionIdResolver();

    /**
     * Creates a new instance.
     *
     * @param sessionRepository the <code>SessionRepository</code> to use. Cannot be null.
     */
    public SessionRepositoryFilter(SessionRepository<S> sessionRepository) {
        if (sessionRepository == null) {
            throw new IllegalArgumentException("sessionRepository cannot be null");
        }
        this.sessionRepository = sessionRepository;
    }

    /**
     * Sets the {@link HttpSessionIdResolver} to be used. The default is a
     * {@link CookieHttpSessionIdResolver}.
     *
     * @param httpSessionIdResolver the {@link HttpSessionIdResolver} to use. Cannot be
     * null.
     */
    public void setHttpSessionIdResolver(HttpSessionIdResolver httpSessionIdResolver) {
        if (httpSessionIdResolver == null) {
            throw new IllegalArgumentException("httpSessionIdResolver cannot be null");
        }
        this.httpSessionIdResolver = httpSessionIdResolver;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        request.setAttribute(SESSION_REPOSITORY_ATTR, this.sessionRepository);

        SessionRepositoryRequestWrapper wrappedRequest = new SessionRepositoryRequestWrapper(
                request, response, this.servletContext);
        SessionRepositoryResponseWrapper wrappedResponse = new SessionRepositoryResponseWrapper(
                wrappedRequest, response);

        try {
            filterChain.doFilter(wrappedRequest, wrappedResponse);
        }
        finally {
            wrappedRequest.commitSession();
        }
    }

    public void setServletContext(ServletContext servletContext) {
        this.servletContext = servletContext;
    }

    /**
     * Allows ensuring that the session is saved if the response is committed.
     *
     * @author Rob Winch
     * @since 1.0
     */
    private final class SessionRepositoryResponseWrapper
            extends OnCommittedResponseWrapper {

        private final SessionRepositoryRequestWrapper request;

        /**
         * Create a new {@link SessionRepositoryResponseWrapper}.
         * @param request the request to be wrapped
         * @param response the response to be wrapped
         */
        SessionRepositoryResponseWrapper(SessionRepositoryRequestWrapper request,
                                         HttpServletResponse response) {
            super(response);
            if (request == null) {
                throw new IllegalArgumentException("request cannot be null");
            }
            this.request = request;
        }

        @Override
        protected void onResponseCommitted() {
            this.request.commitSession();
        }
    }

    /**
     * A {@link javax.servlet.http.HttpServletRequest} that retrieves the
     * {@link javax.servlet.http.HttpSession} using a
     * {@link org.springframework.session.SessionRepository}.
     *
     * @author Rob Winch
     * @since 1.0
     */
    private final class SessionRepositoryRequestWrapper
            extends HttpServletRequestWrapper {

        private final HttpServletResponse response;

        private final ServletContext servletContext;

        private S requestedSession;

        private boolean requestedSessionCached;

        private Boolean requestedSessionIdValid;

        private boolean requestedSessionInvalidated;


        private HttpServletRequest request;
        private HttpSession session;

        private SessionRepositoryRequestWrapper(HttpServletRequest request,
                                                HttpServletResponse response, ServletContext servletContext) {
            super(request);
             this.request = request;
            this.response = response;
            this.servletContext = servletContext;
        }

        /**
         * Uses the {@link HttpSessionIdResolver} to write the session id to the response
         * and persist the Session.
         */
        private void commitSession() {
            HttpSessionWrapper wrappedSession = getCurrentSession();
            if (wrappedSession == null) {
                if (isInvalidateClientSession()) {
                    SessionRepositoryFilter.this.httpSessionIdResolver.expireSession(this,
                            this.response);
                }
            }
            else {
//                S session = wrappedSession.getSession();
//                clearRequestedSessionCache();
//                SessionRepositoryFilter.this.sessionRepository.save(session);
//                String sessionId = session.getId();
//                if (!isRequestedSessionIdValid()
//                        || !sessionId.equals(getRequestedSessionId())) {
//                    SessionRepositoryFilter.this.httpSessionIdResolver.setSessionId(this,
//                            this.response, sessionId);
//                }
            }
        }

        @SuppressWarnings("unchecked")
        private HttpSessionWrapper getCurrentSession() {
            return (HttpSessionWrapper) getAttribute(CURRENT_SESSION_ATTR);
        }

        private void setCurrentSession(HttpSessionWrapper currentSession) {
            if (currentSession == null) {
                removeAttribute(CURRENT_SESSION_ATTR);
            }
            else {
                setAttribute(CURRENT_SESSION_ATTR, currentSession);
            }
        }

        @Override
        @SuppressWarnings("unused")
        public String changeSessionId() {
            HttpSession session = getSession(false);

            if (session == null) {
                throw new IllegalStateException(
                        "Cannot change session ID. There is no session associated with this request.");
            }

            return getCurrentSession().getSession().changeSessionId();
        }

        @Override
        public boolean isRequestedSessionIdValid() {
            if (this.requestedSessionIdValid == null) {
                S requestedSession = getRequestedSession();
                if (requestedSession != null) {
                    requestedSession.setLastAccessedTime(Instant.now());
                }
                return isRequestedSessionIdValid(requestedSession);
            }

            return this.requestedSessionIdValid;
        }

        private boolean isRequestedSessionIdValid(S session) {
            if (this.requestedSessionIdValid == null) {
                this.requestedSessionIdValid = session != null;
            }
            return this.requestedSessionIdValid;
        }

        private boolean isInvalidateClientSession() {
            return getCurrentSession() == null && this.requestedSessionInvalidated;
        }

        @Override
        public HttpSessionWrapper getSession(boolean create) {

            HttpSessionWrapper currentSession = getCurrentSession();
            if (currentSession != null) {
                return currentSession;
            }
            S requestedSession = getRequestedSession();
            if (requestedSession != null) {
                if (getAttribute(INVALID_SESSION_ID_ATTR) == null) {
                    requestedSession.setLastAccessedTime(Instant.now());
                    this.requestedSessionIdValid = true;
                    currentSession = new HttpSessionWrapper(requestedSession, getServletContext());
                    currentSession.setNew(false);
                    setCurrentSession(currentSession);
                    return currentSession;
                }
            }
            else {
                // This is an invalid session id. No need to ask again if
                // request.getSession is invoked for the duration of this request
                if (SESSION_LOGGER.isDebugEnabled()) {
                    SESSION_LOGGER.debug(
                            "No session found by id: Caching result for getSession(false) for this HttpServletRequest.");
                }
                setAttribute(INVALID_SESSION_ID_ATTR, "true");
            }
            if (!create) {
                return null;
            }
            if (SESSION_LOGGER.isDebugEnabled()) {
                SESSION_LOGGER.debug(
                        "A new session was created. To help you troubleshoot where the session was created we provided a StackTrace (this is not an error). You can prevent this from appearing by disabling DEBUG logging for "
                                + SESSION_LOGGER_NAME,
                        new RuntimeException(
                                "For debugging purposes only (not an error)"));
            }
            S session = SessionRepositoryFilter.this.sessionRepository.findById(Context.getCookie(request, "SESSION"));
            if(null == session){
                return null;
            }
//            session.setLastAccessedTime(Instant.now());
            currentSession = new HttpSessionWrapper(session, getServletContext());
            setCurrentSession(currentSession);
            return currentSession;
        }

        @Override
        public ServletContext getServletContext() {
            if (this.servletContext != null) {
                return this.servletContext;
            }
            // Servlet 3.0+
            return super.getServletContext();
        }

        @Override
        public HttpSessionWrapper getSession() {
            return getSession(true);
        }

        @Override
        public String getRequestedSessionId() {
            S requestedSession = getRequestedSession();
            return (requestedSession != null ? requestedSession.getId() : null);
        }

        private S getRequestedSession() {
            if (!this.requestedSessionCached) {
                List<String> sessionIds = SessionRepositoryFilter.this.httpSessionIdResolver
                        .resolveSessionIds(this);
                for (String sessionId : sessionIds) {
                    S session = SessionRepositoryFilter.this.sessionRepository
                            .findById(sessionId);
                    if (session != null) {
                        this.requestedSession = session;
                        break;
                    }
                }
                this.requestedSessionCached = true;
            }
            return this.requestedSession;
        }

        private void clearRequestedSessionCache() {
            this.requestedSessionCached = false;
            this.requestedSession = null;
        }

        /**
         * Allows creating an HttpSession from a Session instance.
         *
         * @author Rob Winch
         * @since 1.0
         */
        private final class HttpSessionWrapper extends HttpSessionAdapter<S> {

            HttpSessionWrapper(S session, ServletContext servletContext) {
                super(session, servletContext);
            }

            @Override
            public void invalidate() {
                super.invalidate();
                SessionRepositoryRequestWrapper.this.requestedSessionInvalidated = true;
                setCurrentSession(null);
                clearRequestedSessionCache();
                SessionRepositoryFilter.this.sessionRepository.deleteById(getId());
            }
        }

    }

}

这里是主要操作代码片段

只需要将这里注释掉就好了

我来解释一下这个的意思

总体就是说 当A框架第一次请求B框架过来 其实A框架的session是存在的, 但是 当你B框架做 request.getSeesion操作的时候 spring session 过滤器 会拦截到你的请求 这个时候它会把 session 做提交操作 删除 之前的 sessionid 并且获取最新的sessionid 保存 这就是说 为什么我们在做session 共享的时候 B框架一旦使用 request.getSeesion 就是把之前的sessionid 删除的主要原因

首先我们要明白一点 B框架 不生产session  它只使用session  所以 删除操作不应该由B框架来完成

这里修改这个代码直接在项目根目录创建 org.springframework.session.web.http 这个包

然后在包下面新建类SessionRepositoryFilter 如果spring版本是5.0的话直接拷贝

这样的话 配合 nginx 的cookie 同步 和 redis session 共享 就能实现 跨框架 session 共享

到这里还不算完 你要获取 A框架过来的用户 session 信息 首先一点 A框架 B框架 架构不一样 序列化方式也不一样如图

 

这里表示 A框架的权限框架使用的是security 那么如果你的B框架是shiro怎么办

首先 把A框架的 User类拿过来 A框架的类放在什么包下面你就放在什么包下面 并且实现 序列化接口 为什么要实现序列化 可以去找找 redis 怎么存对象 这个时候B框架就有A框架的用户类  首先 存在 redis 的信息我们是能拿到的但是信息是序列化的 而且A框架的权限框架跟B不一样 那么我们就在B框架中导入A框架的 权限框架 core 包而且版本要跟A框架的core一致 只需要导入一个 因为在做序列化对象 

比如我这里A框架的security是3.1.3的版本 我就把这个版本拷贝到B框架里面就好了 为什么要这么做 去看看 这几个权限框架的序列化对象操作

这样的话当我在B框架中 

使用request.getSession

的时候就能获取到A框架的信息 配合 ningx 使用就能 实现跨框架的 session 共享

 

 

 

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值