欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringCloud開啟session共享并存儲(chǔ)到Redis的實(shí)現(xiàn)

 更新時(shí)間:2023年02月14日 10:17:08   作者:一枝花傲寒  
這篇文章主要介紹了SpringCloud開啟session共享并存儲(chǔ)到Redis的實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

備注:以下所有的gateway均指SpringCloud Gateway

一、原架構(gòu)

前端<->gateway<->console后端

原來session是在console-access中維護(hù)的,當(dāng)中間有了一層gateway之后,gateway會(huì)認(rèn)為session變了,從而將session的cookie信息重置,導(dǎo)致無法在前端的后續(xù)請(qǐng)求無法將cookie帶上來

如下圖所示的spring-web的代碼中這個(gè)state會(huì)變成State.NEW而非State.STARTED

在這種情況下,部署的時(shí)候只有跳過gateway才能正常進(jìn)行

即按照如下方式才能進(jìn)行session的判斷

前端<->console后端

二、調(diào)整架構(gòu)以及相應(yīng)的代碼

整個(gè)業(yè)務(wù)處理和原來的沒有任何改變

將session的判斷控制挪到gateway當(dāng)中

首先將console后端中登錄以及后續(xù)業(yè)務(wù)當(dāng)中涉及到session處理的部分都刪除

然后開始改造gateway

1、Redis和session的配置

gateway的pom.xml增加

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-data-redis</artifactId>
</dependency>

因?yàn)樾枰蕾嘡edis了,所以啟動(dòng)類當(dāng)中刪除RedisAutoConfiguration.class

Nacos或者配置文件增加redis配置

spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.username=redis7
spring.redis.password=XXX
spring.redis.database=10
spring.redis.pool.max-active=100
spring.redis.pool.max-wait=500
spring.redis.pool.max-idle=10
spring.redis.pool.min-idle=10
spring.redis.timeout=1000

2、增加配置類

/**
 * 指定saveMode為ALWAYS 功能和flushMode類似
 *
 * @author fengwei
 * @since 2022/11/8
 */

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpCookie;
import org.springframework.session.SaveMode;
import org.springframework.session.data.redis.config.annotation.web.server.EnableRedisWebSession;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.session.CookieWebSessionIdResolver;
import org.springframework.web.server.session.WebSessionIdResolver;

import java.util.Base64;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

@EnableRedisWebSession(saveMode = SaveMode.ALWAYS, maxInactiveIntervalInSeconds = 1200)
@Configuration
@Slf4j
public class RedisSessionConfig {
    /**
     * @return
     * @reference https://docs.spring.io/spring-session/reference/guides/boot-webflux-custom-cookie.html
     */
    @Bean
    public WebSessionIdResolver webSessionIdResolver() {
        CustomWebSessionIdResolver customWebSessionIdResolver = new CustomWebSessionIdResolver();
        //以下四項(xiàng)配置主要用于跨域調(diào)用讓客戶端處理cookie信息;若同域調(diào)用,下面四行可刪除
        customWebSessionIdResolver.addCookieInitializer((builder) -> builder.httpOnly(true));
        customWebSessionIdResolver.addCookieInitializer((builder) -> builder.path("/"));
        customWebSessionIdResolver.addCookieInitializer((builder) -> builder.sameSite("None"));
        customWebSessionIdResolver.addCookieInitializer((builder) -> builder.secure(true));
        return customWebSessionIdResolver;
    }

    private static class CustomWebSessionIdResolver extends CookieWebSessionIdResolver {
        // 重寫resolve方法 對(duì)SESSION進(jìn)行base64解碼
        @Override
        public List<String> resolveSessionIds(ServerWebExchange exchange) {
            MultiValueMap<String, HttpCookie> cookieMap = exchange.getRequest().getCookies();
            // 獲取SESSION
            List<HttpCookie> cookies = cookieMap.get(getCookieName());
            if (cookies == null) {
                return Collections.emptyList();
            }
            return cookies.stream().map(HttpCookie::getValue).map(this::base64Decode).collect(Collectors.toList());
        }

        private String base64Decode(String base64Value) {
            try {
                byte[] decodedCookieBytes = Base64.getDecoder().decode(base64Value);
                String decodedCookieString = new String(decodedCookieBytes);
                log.debug("base64Value:{}, decodedCookieString:{} ", base64Value, decodedCookieString);
                return decodedCookieString;
            } catch (Exception ex) {
                //如果轉(zhuǎn)不了base64,就認(rèn)為原始值就是返回的
                log.debug("Unable to Base64 decode value:{} ", base64Value);
                return base64Value;
            }
        }
    }

}

3、應(yīng)答過濾器增加session設(shè)置

在ResponseLogFilter類中增加

/*如果是控制臺(tái)登錄,則從里面取出securityRandom存在websession里面*/
if (request.getPath().toString().startsWith("/console/access/user/login")) {
    JSONObject jsonObject = JSONObject.parseObject(finalResponseBody);
    if ("0000".equals(jsonObject.getString("result"))) {
        JSONObject jsonObjectData = (JSONObject) jsonObject.get("data");
        String securityRandom = (String) jsonObjectData.get("securityrandom");
        exchange.getSession().subscribe(webSession -> {
            webSession.getAttributes().put("securityrandom", securityRandom);
        });
        try {
            //給200毫秒讓進(jìn)行session設(shè)置
            Thread.sleep(200);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}

4、增加控制臺(tái)處理的過濾器ConsoleFilter

首選在配置文件或者Nacos增加配置項(xiàng)

#Y標(biāo)識(shí)需要檢查session;N表示不檢查session。開發(fā)的時(shí)候可以配置為N
websession.ifcheck=Y

過濾器ConsoleFilter

import com.alibaba.cloud.commons.lang.StringUtils;
import com.jieyi.util.OrderedConstant;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;

/**
 * 控制臺(tái)登錄的過濾器,主要是拿用戶憑證的securityRandom
 *
 * @author fengwei
 * @date 2022-11-8
 */
@Component
@Slf4j
public class ConsoleFilter implements GlobalFilter, Ordered {
    private static final List<String> WHITE_LIST = Arrays.asList("/console/access/user/getOtp/V1", "/console/access/user/login/V1");

    @Value("${websession.ifcheck}")
    private String websessionIfcheck;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String path = request.getPath().toString();


        //不校驗(yàn)session就直接通過了
        if (!"Y".equals(websessionIfcheck)) {
            return chain.filter(exchange);
        }
        //在url白名單中放行
        boolean isWhiteUrl = WHITE_LIST.stream().anyMatch(path::endsWith);
        if (isWhiteUrl) {
            return chain.filter(exchange);
        }

        if (path.startsWith("/console")) {
            return exchange.getSession().flatMap(webSession -> {
                String securityrandomInSession = webSession.getAttribute("securityrandom");
                log.info("securityrandomInSession:{}", securityrandomInSession);
                if (StringUtils.isEmpty(securityrandomInSession)) {
                    byte[] bytes = "{\"status\":\"401\",\"msg\":\"Not login or login timeout\"}".getBytes(StandardCharsets.UTF_8);
                    DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(bytes);
                    exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
                    return exchange.getResponse().writeWith(Flux.just(buffer));
                }
                return chain.filter(exchange);
            });

        } else {
            return chain.filter(exchange);
        }

    }

    @Override
    public int getOrder() {
        return OrderedConstant.LOGGING_FILTER;
    }
}

5、前端請(qǐng)求中增加(跨域時(shí))

withCredentials = true

只有增加這個(gè)請(qǐng)求才能攜帶和處理cookie

三、部署模式

1、同域

對(duì)于同域的部署http和https均可(當(dāng)然更建議https)

提供一個(gè)nginx同域部署的參考:

server {
  #console-samedomain-test
  listen 38093 ssl;
  proxy_set_header Host $host:38093;
  root html;
  index index.html index.htm;
  ssl_certificate      cert/server.crt;
  ssl_certificate_key  cert/server.key;
  ssl_session_timeout  5m;
  ssl_ciphers  ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
  ssl_prefer_server_ciphers  on;
  location / {
    proxy_pass http://127.0.0.1:30000/;
  }
  location /ccuconsole {
    proxy_pass http://127.0.0.1:5120/ccuconsole;
  }
}

該配置為https,走的38093端口

前端頁面訪問https://ip:38093/ccuconsole

所有的請(qǐng)求都通過該同域的ip和端口轉(zhuǎn)發(fā)到http://127.0.0.1:30000對(duì)應(yīng)的服務(wù)(確保該服務(wù)中不存在/ccuconsole開頭的路徑)中

2、跨域

對(duì)于跨域的部必須使用https(現(xiàn)在的瀏覽器版本的要求,瀏覽器已不再支持http的跨域了)

提供一個(gè)nginx跨域部署的參考:

server {
  #console-web-crossdomain-test
  listen 38091 ssl;
  proxy_set_header Host $host:38091;
  root html;
  index index.html index.htm;
  ssl_certificate      cert/server.crt;
  ssl_certificate_key  cert/server.key;
  ssl_session_timeout  5m;
  ssl_ciphers  ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
  ssl_prefer_server_ciphers  on;
  location /ccuconsole {
    proxy_pass http://127.0.0.1:5120/ccuconsole;
  }
}

server {
  #console-crossdomain-test
  listen 38092 ssl;
  proxy_set_header Host $host:38092;
  root html;
  index index.html index.htm;
  ssl_certificate      cert/server.crt;
  ssl_certificate_key  cert/server.key;
  ssl_session_timeout  5m;
  ssl_ciphers  ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
  ssl_prefer_server_ciphers  on;
  location / {
    proxy_pass http://127.0.0.1:30000/;
  }
}

前端頁面訪問https://ip:38091/ccuconsole

所有的請(qǐng)求都通過該同域的ip和38092轉(zhuǎn)發(fā)到http://127.0.0.1:30000對(duì)應(yīng)的服務(wù)(確保該服務(wù)中有無/ccuconsole開頭的路徑并不影響,但是為了可切換同域部署,不推薦存在/ccuconsole開頭的路徑)中

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java線程安全和鎖Synchronized知識(shí)點(diǎn)詳解

    Java線程安全和鎖Synchronized知識(shí)點(diǎn)詳解

    在本篇文章里小編給大家分享的是關(guān)于Java線程安全和鎖Synchronized相關(guān)知識(shí)點(diǎn),有需要的朋友們可以參考下。
    2019-08-08
  • java線程池工作隊(duì)列飽和策略代碼示例

    java線程池工作隊(duì)列飽和策略代碼示例

    這篇文章主要介紹了java線程池工作隊(duì)列飽和策略代碼示例,涉及線程池的簡(jiǎn)單介紹,工作隊(duì)列飽和策略的分析及代碼示例,具有一定參考價(jià)值,需要的朋友可以了解下。
    2017-11-11
  • 解析java中volatile關(guān)鍵字

    解析java中volatile關(guān)鍵字

    這篇文章主要為大家解析了java中volatile關(guān)鍵字,經(jīng)常有人把volatile關(guān)鍵字和synchronized或者lock混淆,本文就為大家好好區(qū)分,感興趣的小伙伴們可以參考一下
    2016-01-01
  • Spring Boot使用GridFS實(shí)現(xiàn)文件的上傳和下載方式

    Spring Boot使用GridFS實(shí)現(xiàn)文件的上傳和下載方式

    這篇文章主要介紹了Spring Boot使用GridFS實(shí)現(xiàn)文件的上傳和下載方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • Java實(shí)現(xiàn)全排列的三種算法詳解

    Java實(shí)現(xiàn)全排列的三種算法詳解

    從n個(gè)不同元素中任取m(m≤n)個(gè)元素,按照一定的順序排列起來,叫做從n個(gè)不同元素中取出m個(gè)元素的一個(gè)排列。當(dāng)m=n時(shí)所有的排列情況叫全排列。本文總結(jié)了Java實(shí)現(xiàn)全排列的三種算法,需要的可以參考下
    2022-06-06
  • Java設(shè)計(jì)模式之裝飾模式(Decorator模式)介紹

    Java設(shè)計(jì)模式之裝飾模式(Decorator模式)介紹

    這篇文章主要介紹了Java設(shè)計(jì)模式之裝飾模式(Decorator模式)介紹,本文講解了為什么使用Decorator、如何使用裝飾模式、Jive中的Decorator實(shí)現(xiàn)等內(nèi)容,需要的朋友可以參考下
    2015-03-03
  • Java Swing最詳細(xì)基礎(chǔ)知識(shí)總結(jié)

    Java Swing最詳細(xì)基礎(chǔ)知識(shí)總結(jié)

    這篇文章主要介紹了Java Swing最詳細(xì)基礎(chǔ)知識(shí)總結(jié),文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)Java Swing的小伙伴們有很好的幫助,需要的朋友可以參考下
    2021-05-05
  • 解決spring data redis的那些坑

    解決spring data redis的那些坑

    這篇文章主要介紹了spring data redis的那些坑,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • Java?GenericObjectPool?對(duì)象池化技術(shù)之SpringBoot?sftp?連接池工具類詳解

    Java?GenericObjectPool?對(duì)象池化技術(shù)之SpringBoot?sftp?連接池工具類詳解

    這篇文章主要介紹了Java?GenericObjectPool?對(duì)象池化技術(shù)之SpringBoot?sftp?連接池工具類詳解,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-04-04
  • Java21新特性Record?Patterns示例詳解

    Java21新特性Record?Patterns示例詳解

    這篇文章主要為大家介紹了Java21新特性Record?Patterns示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-09-09

最新評(píng)論