自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Serverless 安全增強(qiáng)篇:整合 OAuth2 + Token 黑名單 + Redis 緩存機(jī)制

數(shù)據(jù)庫 Redis
隨著 Serverless 架構(gòu)的廣泛應(yīng)用,傳統(tǒng) Web 應(yīng)用中依賴 Session 的認(rèn)證模式面臨重大挑戰(zhàn)。本文將以 Spring Security 為核心,構(gòu)建一套無狀態(tài)、可擴(kuò)展、支持 OAuth2、JWT、Redis 黑名單與 Refresh Token 的安全認(rèn)證體系,適用于 Serverless 應(yīng)用場景。

隨著 Serverless 架構(gòu)的廣泛應(yīng)用,傳統(tǒng) Web 應(yīng)用中依賴 Session 的認(rèn)證模式面臨重大挑戰(zhàn)。本文將以 Spring Security 為核心,構(gòu)建一套無狀態(tài)、可擴(kuò)展、支持 OAuth2、JWT、Redis 黑名單與 Refresh Token 的安全認(rèn)證體系,適用于 Serverless 應(yīng)用場景。

Serverless 應(yīng)用的安全挑戰(zhàn)

Serverless 應(yīng)用的無狀態(tài)特性決定了其認(rèn)證模型不能依賴傳統(tǒng)的會話管理。核心挑戰(zhàn)包括:

  • 身份認(rèn)證用戶身份需要跨請求驗證,無 Session。
  • 權(quán)限校驗如何高效識別用戶角色與權(quán)限。
  • Token 生命周期管理訪問令牌的過期續(xù)簽、注銷。
  • 密鑰管理JWT 簽名密鑰的安全管理。

Spring Security + JWT 構(gòu)建輕量認(rèn)證模型

我們采用如下組件構(gòu)建無狀態(tài)認(rèn)證體系:

組件

作用

JWT

用戶身份令牌,無狀態(tài)傳遞

OAuth2

多客戶端支持與統(tǒng)一授權(quán)

Redis

黑名單 + RefreshToken 存儲

Spring Security

安全攔截器與權(quán)限控制

系統(tǒng)結(jié)構(gòu)設(shè)計圖

+-----------------------------+
|        前端調(diào)用接口         |
+-----------------------------+
             |
             v
+-----------------------------+
|   API網(wǎng)關(guān) / Serverless函數(shù)   |
+-----------------------------+
             |
             v
+-----------------------------+
|  Spring Security + Token攔截 |
+-----------------------------+
             |
             v
+------------+   Redis   +-------------+
| JWT Token校驗 | <----> | Token黑名單 |
+------------+           +-------------+
             |
             v
    +--------------------------+
    |     用戶業(yè)務(wù)邏輯處理      |
    +--------------------------+

關(guān)鍵模塊代碼實現(xiàn)

Spring Boot 啟動類

@SpringBootApplication
public class ServerlessSecurityApplication {
    public static void main(String[] args) {
        SpringApplication.run(ServerlessSecurityApplication.class, args);
    }
}

Security 配置類(無狀態(tài)、JWT、資源服務(wù)器)

@Configuration
@EnableWebSecurity
public class SecurityConfig {


    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        return http
                .csrf(csrf -> csrf.disable())
                .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .authorizeHttpRequests(auth -> auth
                        .requestMatchers(\"/api/public/**\", \"/api/token/refresh\").permitAll()
                        .anyRequest().authenticated())
                .oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()))
                .build();
    }
}

JWT 工具類

public class JwtUtils {


    private static final Key key = Keys.hmacShaKeyFor(\"0123456789abcdef0123456789abcdef\".getBytes());


    public static String generateAccessToken(String username, String roles, String jti) {
        return Jwts.builder()
                .setSubject(username)
                .setId(jti)
                .claim(\"roles\", roles)
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + 3600_000)) // 1小時
                .signWith(key)
                .compact();
    }


    public static String generateRefreshToken(String username, String jti) {
        return Jwts.builder()
                .setSubject(username)
                .setId(jti)
                .claim(\"type\", \"refresh\")
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + 7 * 24 * 3600_000)) // 7天
                .signWith(key)
                .compact();
    }


    public static Claims getClaims(String token) throws JwtException {
        return Jwts.parserBuilder()
                .setSigningKey(key)
                .build()
                .parseClaimsJws(token)
                .getBody();
    }
}

Redis Token 黑名單工具類

@Component
public class TokenBlacklistUtil {


    private final StringRedisTemplate redisTemplate;


    public TokenBlacklistUtil(StringRedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }


    public void blacklistToken(String jti, long ttlSeconds) {
        redisTemplate.opsForValue().set(\"blacklist:\" + jti, \"1\", ttlSeconds, TimeUnit.SECONDS);
    }


    public boolean isTokenBlacklisted(String jti) {
        return redisTemplate.hasKey(\"blacklist:\" + jti);
    }
}

RefreshToken 存儲與刷新接口

@RestController
@RequestMapping(\"/api/token\")
public class TokenController {


    @Autowired
    private StringRedisTemplate redisTemplate;


    @PostMapping(\"/refresh\")
    public ResponseEntity<?> refresh(@RequestParam String refreshToken) {
        Claims claims = JwtUtils.getClaims(refreshToken);
        String jti = claims.getId();
        String username = claims.getSubject();


        // 校驗類型與黑名單
        if (!\"refresh\".equals(claims.get(\"type\"))) {
            return ResponseEntity.badRequest().body(\"非法 token 類型\");
        }


        if (!Boolean.TRUE.equals(redisTemplate.hasKey(\"refresh:\" + jti))) {
            return ResponseEntity.status(401).body(\"refreshToken 已失效\");
        }


        // 生成新 token
        String newJti = UUID.randomUUID().toString();
        String newAccessToken = JwtUtils.generateAccessToken(username, \"USER\", newJti);


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

登錄、退出控制器(模擬)

@RestController
@RequestMapping(\"/api/auth\")
public class AuthController {


    @Autowired
    private StringRedisTemplate redisTemplate;


    @Autowired
    private TokenBlacklistUtil blacklistUtil;


    @PostMapping(\"/login\")
    public Map<String, String> login(@RequestParam String username) {
        String jti = UUID.randomUUID().toString();
        String accessToken = JwtUtils.generateAccessToken(username, \"USER\", jti);
        String refreshToken = JwtUtils.generateRefreshToken(username, jti);


        // 保存 refreshToken 到 redis
        redisTemplate.opsForValue().set(\"refresh:\" + jti, username, 7, TimeUnit.DAYS);


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


    @PostMapping(\"/logout\")
    public ResponseEntity<Void> logout(@RequestHeader(\"Authorization\") String authHeader) {
        String token = authHeader.replace(\"Bearer \", \"\");
        Claims claims = JwtUtils.getClaims(token);
        String jti = claims.getId();
        long remaining = (claims.getExpiration().getTime() - System.currentTimeMillis()) / 1000;
        blacklistUtil.blacklistToken(jti, remaining);


        // 同時清除 refreshToken
        redisTemplate.delete(\"refresh:\" + jti);
        return ResponseEntity.ok().build();
    }
}

application.yml 配置

spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          issuer-uri: https://auth.icoderoad.com/oauth2
          jwk-set-uri: https://auth.icoderoad.com/oauth2/jwks
  redis:
    host: localhost
    port: 6379

總結(jié)

無狀態(tài) Serverless 環(huán)境下,Spring Security 可通過 JWT、OAuth2 與 Redis 輕松實現(xiàn)高效認(rèn)證體系:

  • 不依賴 Session
  • 支持訪問控制 + 黑名單管理
  • Refresh Token 保證登錄體驗
  • Redis 做 Token 生命周期緩存

今天就講到這里,如果有問題需要咨詢,大家可以直接留言或掃下方二維碼來知識星球找我,我們會盡力為你解答。

責(zé)任編輯:武曉燕 來源: 路條編程
相關(guān)推薦

2011-06-02 10:52:11

Android BroadCast 黑名單

2011-01-21 17:53:44

Zimbra

2023-08-29 08:00:38

2023-08-31 08:34:07

Users對象序列化

2015-06-04 11:11:15

2013-08-27 10:56:24

2018-03-12 10:45:41

2021-08-02 12:50:45

sessiontokenJava

2022-04-11 07:34:46

OAuth2UAA節(jié)點

2010-11-11 13:20:41

2010-05-24 13:36:11

2011-07-28 11:10:58

2011-03-18 13:14:01

2018-06-10 09:04:28

2009-10-29 08:39:14

Windows 7系統(tǒng)激活

2019-07-29 08:41:33

算法黑名單ip

2020-07-15 20:32:45

fail2banFirewallD系統(tǒng)運維

2020-01-10 15:42:13

SpringBootRedis數(shù)據(jù)庫

2012-11-23 10:15:06

2023-10-16 08:14:21

AI安全數(shù)據(jù)
點贊
收藏

51CTO技術(shù)棧公眾號