成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

爆火!Spring Boot 3.4 @HttpExchange 強勢來襲,一套搞定遠程調用 + 登錄認證 + Token續簽

開發 前端
如果你正在構建一個現代化微服務系統,并希望拋棄冗余依賴、提升遠程調用體驗與認證安全性,不妨從本文架構出發,打造一套真正面向未來的通信體系。?

本篇文章不僅展示如何使用@HttpExchange優雅封裝遠程調用接口,還將結合 Spring Security、JWT、Redis 實現一體化登錄認證 + Token 續簽機制,并進一步集成:

  • ? Token 自動注入
  • ? 失敗自動重試
  • ? RefreshToken 自動續簽
  • ? Redis 緩存中間件管理 Token 生命周期 通過這些高級能力,你將看到一種真正“零侵入、強解耦、具備生產力”的服務通信與認證架構。

核心依賴配置(Spring Boot 3.4.2)

<dependencies>
<!-- Webflux:用于 HttpExchange + WebClient -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

<!-- Spring Security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>

<!-- JWT -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>

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

<!-- 緩存工具(可選) -->
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>
</dependencies>

application.yml 示例:

server:
port:8080

spring:
redis:
host: localhost
port:6379

jwt:
secret: icoderoad-secret
access-token-expire:600# 單位:秒
refresh-token-expire:1800# 單位:秒

JWT 工具類支持 AccessToken + RefreshToken:

@Component
public class JwtUtils {


    @Value("${jwt.secret}")
    private String secret;


    @Value("${jwt.access-token-expire}")
    private long accessExpire;


    @Value("${jwt.refresh-token-expire}")
    private long refreshExpire;


    // 生成 Token
    public String generateToken(String username, boolean isRefreshToken) {
        long expireTime = isRefreshToken ? refreshExpire : accessExpire;
        return Jwts.builder()
                .setSubject(username)
                .setExpiration(new Date(System.currentTimeMillis() + expireTime * 1000))
                .signWith(Keys.hmacShaKeyFor(secret.getBytes()))
                .compact();
    }


    public Claims parseToken(String token) throws JwtException {
        return Jwts.parserBuilder()
                .setSigningKey(secret.getBytes())
                .build()
                .parseClaimsJws(token)
                .getBody();
    }


    public boolean isTokenExpired(String token) {
        return parseToken(token).getExpiration().before(new Date());
    }


    public long getAccessExpireMillis() {
        return accessExpire * 1000;
    }
}

登錄接口返回 Access + Refresh 雙 Token:

@PostMapping("/login")
public ResponseEntity<?> login(@RequestBody LoginRequest request) {
    Authentication auth = authenticationManager.authenticate(
            new UsernamePasswordAuthenticationToken(request.getUsername(), request.getPassword()));


    String accessToken = jwtUtils.generateToken(request.getUsername(), false);
    String refreshToken = jwtUtils.generateToken(request.getUsername(), true);


    // 存入 Redis
    redisTemplate.opsForValue().set("access:" + accessToken, request.getUsername(),
            jwtUtils.getAccessExpireMillis(), TimeUnit.MILLISECONDS);
    redisTemplate.opsForValue().set("refresh:" + refreshToken, request.getUsername(),
            jwtUtils.getAccessExpireMillis() * 3, TimeUnit.MILLISECONDS);


    return ResponseEntity.ok(Map.of("accessToken", accessToken, "refreshToken", refreshToken));
}

Token 續簽邏輯(刷新接口):

@PostMapping("/refresh")
public ResponseEntity<?> refresh(@RequestBody Map<String, String> body) {
    String oldRefreshToken = body.get("refreshToken");
    try {
        Claims claims = jwtUtils.parseToken(oldRefreshToken);
        String username = claims.getSubject();


        // 校驗 Redis
        String redisUser = redisTemplate.opsForValue().get("refresh:" + oldRefreshToken);
        if (!username.equals(redisUser)) {
            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("無效的刷新Token");
        }


        // 新的 AccessToken
        String newAccessToken = jwtUtils.generateToken(username, false);
        redisTemplate.opsForValue().set("access:" + newAccessToken, username,
                jwtUtils.getAccessExpireMillis(), TimeUnit.MILLISECONDS);


        return ResponseEntity.ok(Map.of("accessToken", newAccessToken));
    } catch (JwtException e) {
        return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Token非法或已過期");
    }
}

@HttpExchange 自動傳遞 Token 并支持異常重試:

@Configuration
public class RemoteClientConfig {


    @Autowired
    private RedisTemplate<String, String> redisTemplate;


    @Bean
    public RemoteService remoteService(JwtUtils jwtUtils) {
        WebClient webClient = WebClient.builder()
                .baseUrl("http://localhost:8888")
                .defaultHeader(HttpHeaders.AUTHORIZATION, "Bearer " + fetchTokenFromRedis())
                .defaultStatusHandler(HttpStatusCode::isError, clientResponse -> {
                    return Mono.error(new RuntimeException("遠程服務異常"));
                })
                .filter(retryFilter())
                .build();


        WebClientAdapter adapter = WebClientAdapter.create(webClient);
        HttpServiceProxyFactory factory = HttpServiceProxyFactory.builderFor(adapter).build();
        return factory.createClient(RemoteService.class);
    }


    private String fetchTokenFromRedis() {
        Set<String> keys = redisTemplate.keys("access:*");
        return keys != null && !keys.isEmpty() ? keys.iterator().next().substring(7) : "";
    }


    private ExchangeFilterFunction retryFilter() {
        return ExchangeFilterFunction.ofResponseProcessor(response -> {
            if (response.statusCode().is5xxServerError()) {
                return Mono.error(new IllegalStateException("服務不可用"));
            }
            return Mono.just(response);
        });
    }
}

總結

在本文中,我們基于 Spring Boot 3.4,構建了一個功能完整的遠程服務通信與認證體系:

  • 使用@HttpExchange實現了極簡、聲明式的 HTTP 接口定義;
  • 借助 Spring WebClient 實現了底層 HTTP 請求執行;
  • 通過 Spring Security + JWT + Redis 構建了完整的登錄認證、Token 續簽與緩存管理機制;
  • 實現了 RefreshToken 自動續簽機制,提升了系統的安全性與用戶體驗;
  • 支持 Token 自動透傳、異常重試、參數對象映射等高級特性;

這一整套架構的優勢在于:

  1. 輕量純凈無需 Feign 等三方依賴,原生 Spring 實現;
  2. 擴展性強支持異步響應、參數自動注入、個性化異常處理;
  3. 認證鏈路可控可追溯Token 生命周期完全掌握在自己手中;
  4. 性能可期Token 與用戶狀態存于 Redis,讀寫高效,支撐高并發訪問場景。

如果你正在構建一個現代化微服務系統,并希望拋棄冗余依賴、提升遠程調用體驗與認證安全性,不妨從本文架構出發,打造一套真正面向未來的通信體系。

責任編輯:武曉燕 來源: 路條編程
相關推薦

2021-05-27 07:12:19

單點登錄系統

2010-12-24 11:27:13

華為HCNE認證

2025-04-27 03:00:00

Spring集成測試

2025-02-17 00:00:45

接口支付寶沙箱

2020-01-02 16:30:02

Spring BootJava異步請求

2020-03-19 12:15:09

2025-02-17 07:48:45

2025-04-08 08:01:31

2011-09-30 12:07:48

2015-08-03 11:50:18

灌水動畫

2024-02-20 08:56:50

JavaScript模塊打包器

2023-11-06 10:41:46

ChatGPT馬斯克

2019-10-11 15:58:25

戴爾

2025-04-07 07:45:00

AI模型神經網絡

2022-06-06 08:42:04

spring-boo開發接口防盜刷

2024-05-31 14:04:18

2009-06-23 18:01:45

Ajax框架源代碼

2018-08-31 08:42:48

LinuxUnix實用程序

2014-12-02 10:02:21

Android異步任務
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 中文字幕精品一区二区三区精品 | 国产午夜精品一区二区三区在线观看 | 国产欧美日韩一区二区三区 | 成人在线视频网 | 91九色婷婷 | 国产精品日韩一区二区 | 国产精品成人一区二区 | 国产欧美日韩 | 国产精品综合网 | 国产精品成人一区二区三区 | 亚洲黄色在线免费观看 | 国产精品久久久久久久久久久久久久 | 成人av一区二区三区 | 人妖videosex高潮另类 | 久久久精品一区二区三区四季av | 久久久久国产一区二区三区四区 | 精品国产一区二区三区久久久久久 | 国产一区二区电影 | 日本aⅴ中文字幕 | 精品麻豆剧传媒av国产九九九 | 欧美亚州 | 青青草综合网 | 国产福利精品一区 | 中文字幕一区二区三区四区不卡 | 国产精品亚洲一区二区三区在线 | 人人干在线视频 | 伊人久久精品一区二区三区 | 久久精品一区 | 精品国产乱码久久久久久a丨 | a视频在线观看 | 久久综合久久综合久久综合 | 国产高清精品一区二区三区 | 久久久久久亚洲精品 | 国产激情偷乱视频一区二区三区 | 国产农村妇女毛片精品久久麻豆 | 色综合色综合色综合 | 日韩欧美在线播放 | 天天色天天射天天干 | 祝你幸福电影在线观看 | 国产美女自拍视频 | 色播久久 |