成人免费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

2015-08-03 11:50:18

灌水動畫

2011-09-30 12:07:48

2024-02-20 08:56:50

JavaScript模塊打包器

2019-10-11 15:58:25

戴爾

2023-11-06 10:41:46

ChatGPT馬斯克

2025-04-07 07:45:00

AI模型神經網絡

2024-12-03 10:46:48

Spring優化開發

2009-06-23 18:01:45

Ajax框架源代碼

2018-08-31 08:42:48

LinuxUnix實用程序

2014-12-02 10:02:21

Android異步任務

2010-06-09 17:00:43

UML試題
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 免费久草 | 国产乱码精品一区二区三区五月婷 | 国产精品久久久久久久粉嫩 | 欧美片网站免费 | 欧美性生交大片免费 | 午夜精品导航 | 国产高清视频在线 | 国产一区免费 | 成人a网| 日韩精品一区二区三区中文字幕 | 精品福利一区 | 日本a∨精品中文字幕在线 亚洲91视频 | 毛片1 | 久久久久无码国产精品一区 | 欧美一区二区三区日韩 | 午夜视频精品 | 欧美1区2区 | 精品国产一区二区三区在线观看 | 免费在线观看一区二区三区 | www.五月天婷婷 | 中文字幕在线观看国产 | 色伊人网 | 福利久久 | 久久精品—区二区三区 | 国产精品久久久久久久久免费樱桃 | 一本综合久久 | 国内91在线 | 玩丰满女领导对白露脸hd | 人人做人人澡人人爽欧美 | 日韩国产免费 | 夜夜爽99久久国产综合精品女不卡 | 请别相信他免费喜剧电影在线观看 | 精品一区二区在线看 | 精品国产99| 亚洲欧美一区二区三区在线 | h视频在线观看免费 | ww亚洲ww亚在线观看 | 日韩电影在线一区 | 欧美日韩在线播放 | 一级毛片视频在线 | 日韩欧美三级 |