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

Redis實現(xiàn)會話管理和token認證的示例代碼

 更新時間:2025年04月22日 09:54:50   作者:昱晏  
會話管理和身份認證是實現(xiàn)用戶登錄、權限管理等功能的基礎,本文主就來介紹一下Redis實現(xiàn)會話管理和token認證的示例代碼,具有一定的參考價值,感興趣的可以了解一下

在現(xiàn)代Web應用中,會話管理身份認證是實現(xiàn)用戶登錄、權限管理等功能的基礎。傳統(tǒng)的會話管理通過服務器端保存會話信息來實現(xiàn),但隨著應用的擴展,尤其在分布式系統(tǒng)中,這種方式的局限性逐漸顯現(xiàn)。Redis作為分布式緩存系統(tǒng),具備高性能和高可用性,能夠很好地解決分布式環(huán)境下的會話管理和Token認證問題。

本教程將介紹如何基于Redis和Spring Boot 實現(xiàn)會話管理與Token認證,確保應用在高并發(fā)、分布式架構中具備良好的性能和擴展性。

一、使用場景

  • 分布式系統(tǒng):當系統(tǒng)部署在多個服務實例上時,服務器本地的Session無法跨實例共享,而Redis能作為集中式存儲,幫助管理所有實例的會話信息。
  • 無狀態(tài)認證:基于Token認證機制的實現(xiàn),特別是JWT(JSON Web Token),適用于用戶登錄后通過Token進行認證,避免在每次請求時重新查詢數(shù)據(jù)庫或讀取Session。
  • 高并發(fā)場景:在高并發(fā)的情況下,Redis的高吞吐量和低延遲能夠保證會話管理和認證機制的高效性。

二、原理解析

1. 會話管理

傳統(tǒng)的會話管理通過在服務器端保存用戶的會話狀態(tài)(Session),并通過客戶端(通常是瀏覽器)保存的Session ID與服務器進行匹配,來確定用戶身份。在分布式環(huán)境下,本地Session機制無法保證跨實例共享,而Redis作為集中式存儲,能夠提供跨服務實例的會話共享機制。

2. Token認證

Token認證,尤其是基于JWT的認證方式,是一種無狀態(tài)認證方案。與傳統(tǒng)的Session機制不同,JWT將用戶信息封裝在Token中,發(fā)送給客戶端,客戶端在后續(xù)請求中攜帶該Token進行認證,服務器通過驗證Token來確定用戶身份。Redis可以用作存儲Token的有效期或與其他用戶數(shù)據(jù)的映射。

3. Redis在會話管理和Token認證中的角色

  • 會話管理:將用戶的會話信息存儲在Redis中,保證分布式系統(tǒng)中不同實例對會話的共享訪問。
  • Token認證:存儲Token的有效性和用戶信息,或用于存儲黑名單Token(已失效或已注銷的Token)。

三、解決方案實現(xiàn)

1. 環(huán)境配置

首先,在pom.xml中添加Redis和Spring Security相關依賴:

<dependencies>
    <!-- Spring Boot Web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
    <!-- Redis -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>

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

    <!-- JWT Token -->
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt-api</artifactId>
        <version>0.11.2</version>
    </dependency>
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt-impl</artifactId>
        <version>0.11.2</version>
    </dependency>
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt-jackson</artifactId>
        <version>0.11.2</version>
    </dependency>
</dependencies>

application.yml中配置Redis:

spring:
  redis:
    host: localhost
    port: 6379
    timeout: 6000ms

2. Redis會話管理實現(xiàn)

在Spring Boot中,我們可以通過Redis來管理會話信息,下面的示例代碼展示如何使用Redis來存儲用戶會話信息。

配置Redis序列化器

為了使得對象能夠存儲在Redis中,我們需要配置Redis的序列化方式。

@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory);
        
        // 設置Key和Value的序列化器
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        
        return template;
    }
}

使用Redis存儲Session信息

我們可以在用戶登錄后將會話信息存入Redis中。

@Service
public class SessionService {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    public void saveSession(String sessionId, Object sessionData) {
        redisTemplate.opsForValue().set(sessionId, sessionData, 30, TimeUnit.MINUTES); // 會話有效期30分鐘
    }

    public Object getSession(String sessionId) {
        return redisTemplate.opsForValue().get(sessionId);
    }

    public void deleteSession(String sessionId) {
        redisTemplate.delete(sessionId);
    }
}

3. Token認證實現(xiàn)

JWT生成與解析

JWT是無狀態(tài)的認證方式,將用戶信息封裝在Token中,通過數(shù)字簽名保證Token的安全性。我們使用jjwt庫來生成和解析JWT。

JWT工具類

@Service
public class JwtTokenProvider {

    private static final String SECRET_KEY = "yourSecretKey";

    // 生成Token
    public String generateToken(String username) {
        return Jwts.builder()
                .setSubject(username)
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + 3600000)) // Token有效期1小時
                .signWith(SignatureAlgorithm.HS512, SECRET_KEY)
                .compact();
    }

    // 解析Token
    public String getUsernameFromToken(String token) {
        return Jwts.parser()
                .setSigningKey(SECRET_KEY)
                .parseClaimsJws(token)
                .getBody()
                .getSubject();
    }

    // 驗證Token是否過期
    public boolean isTokenExpired(String token) {
        Date expiration = Jwts.parser()
                .setSigningKey(SECRET_KEY)
                .parseClaimsJws(token)
                .getBody()
                .getExpiration();
        return expiration.before(new Date());
    }
}

JWT攔截器實現(xiàn)

為了在每次請求時驗證Token的有效性,我們可以通過攔截器在請求到達控制器之前進行校驗。

@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {

    @Autowired
    private JwtTokenProvider jwtTokenProvider;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String token = getTokenFromRequest(request);
        
        if (token != null && !jwtTokenProvider.isTokenExpired(token)) {
            String username = jwtTokenProvider.getUsernameFromToken(token);
            // 在SecurityContext中設置認證信息
            UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(username, null, new ArrayList<>());
            SecurityContextHolder.getContext().setAuthentication(authentication);
        }
        
        filterChain.doFilter(request, response);
    }

    private String getTokenFromRequest(HttpServletRequest request) {
        String bearerToken = request.getHeader("Authorization");
        if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
            return bearerToken.substring(7);
        }
        return null;
    }
}

將攔截器添加到Spring Security配置中

我們需要將JwtAuthenticationFilter加入到Spring Security的過濾器鏈中。

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private JwtAuthenticationFilter jwtAuthenticationFilter;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .csrf().disable()
            .authorizeRequests()
            .antMatchers("/login", "/register").permitAll()  // 登錄、注冊請求不需要認證
            .anyRequest().authenticated()
            .and()
            .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
    }
}

4. Token與Redis的結合

為了進一步增強安全性,我們可以將生成的Token存儲在Redis中,并設置一個過期時間。當Token失效或用戶登出時,將其從Redis中移除。

@Service
public class TokenService {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    @Autowired
    private JwtTokenProvider jwtTokenProvider;

    public String createToken(String username) {
        String token = jwtTokenProvider.generateToken(username);
        redisTemplate.opsForValue().set(username, token, 1, TimeUnit.HOURS);  // Token存儲在Redis中,1小時過期
        return token;
    }

    public boolean validateToken(String token) {
        String username = jwt
        String username = jwtTokenProvider.getUsernameFromToken(token);
        String redisToken = (String) redisTemplate.opsForValue().get(username);
        return token.equals(redisToken) &amp;&amp; !jwtTokenProvider.isTokenExpired(token);
    }

    public void invalidateToken(String username) {
        redisTemplate.delete(username);  // 從Redis中移除Token
    }
}

5. 登錄接口實現(xiàn)

用戶登錄成功后,生成Token并存儲到Redis中,同時將Token返回給客戶端??蛻舳嗽诤罄m(xù)的請求中攜帶此Token。

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

    @Autowired
    private TokenService tokenService;
    @Autowired
    private AuthenticationManager authenticationManager;

    @PostMapping("/login")
    public ResponseEntity<?> login(@RequestBody LoginRequest loginRequest) {
        try {
            // 認證用戶
            Authentication authentication = authenticationManager.authenticate(
                new UsernamePasswordAuthenticationToken(
                    loginRequest.getUsername(), loginRequest.getPassword()));
            
            SecurityContextHolder.getContext().setAuthentication(authentication);
            
            // 生成Token并存儲到Redis
            String token = tokenService.createToken(loginRequest.getUsername());
            
            return ResponseEntity.ok(new JwtResponse(token));
        } catch (AuthenticationException e) {
            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Authentication failed");
        }
    }

    @PostMapping("/logout")
    public ResponseEntity<?> logout(HttpServletRequest request) {
        String token = getTokenFromRequest(request);
        if (token != null) {
            String username = jwtTokenProvider.getUsernameFromToken(token);
            tokenService.invalidateToken(username);  // 從Redis中移除Token
        }
        return ResponseEntity.ok("Logout successful");
    }

    private String getTokenFromRequest(HttpServletRequest request) {
        String bearerToken = request.getHeader("Authorization");
        if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
            return bearerToken.substring(7);
        }
        return null;
    }
}

6. 請求流程示例

  • 用戶登錄:用戶提供用戶名和密碼,通過/auth/login接口進行登錄。成功后,服務器生成JWT Token并存入Redis,并返回給客戶端。
  • Token攜帶請求:客戶端在后續(xù)的請求中,將Token放在Authorization頭部中,發(fā)送到服務器。服務器在收到請求后,通過JWT解析Token,驗證有效性。
  • 登出操作:用戶在登出時,前端請求/auth/logout接口,服務器將用戶的Token從Redis中移除,Token失效。

四、Redis會話管理與Token認證效果

  • 高效性能:Redis的高并發(fā)讀寫能力保證了在高并發(fā)場景下的會話存儲與Token驗證的高效性。
  • 分布式支持:使用Redis作為集中存儲,可以確保在多實例或分布式部署環(huán)境中共享會話數(shù)據(jù),避免本地Session的局限性。
  • 安全性增強:通過Redis存儲Token以及Token的有效期控制,可以快速實現(xiàn)Token的失效處理,增強了安全性。

五、總結

Redis不僅能解決分布式環(huán)境下會話共享的問題,也能通過高效存儲和快速讀取實現(xiàn)了Token認證的高性能處理。在Spring Boot 中,使用Redis與JWT結合的方案為分布式架構提供了強大的認證與授權支持。

到此這篇關于Redis實現(xiàn)會話管理和token認證的示例代碼的文章就介紹到這了,更多相關Redis 會話管理和token認證內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • 淺談Redis的幾個過期策略

    淺談Redis的幾個過期策略

    在使用redis時,一般會設置一個過期時間,當然也有不設置過期時間的,也就是永久不過期。當設置了過期時間,redis是如何判斷是否過期,以及根據(jù)什么策略來進行刪除的。
    2021-05-05
  • Redis關于內(nèi)存碎片的解決方法

    Redis關于內(nèi)存碎片的解決方法

    今天生產(chǎn)機報內(nèi)存爆滿異常被叫過去查看問題,通過各種排除最終定位到了Redis的內(nèi)存碎片的問題,這篇博客將詳細介紹Redis內(nèi)存碎片問題并給出最佳實踐解決此問題,需要的朋友可以參考下
    2024-07-07
  • Redis實現(xiàn)高并發(fā)計數(shù)器

    Redis實現(xiàn)高并發(fā)計數(shù)器

    這篇文章主要為大家詳細介紹了Redis實現(xiàn)高并發(fā)計數(shù)器,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-10-10
  • redis-cli登錄遠程redis服務并批量導入數(shù)據(jù)

    redis-cli登錄遠程redis服務并批量導入數(shù)據(jù)

    本文主要介紹了redis-cli登錄遠程redis服務并批量導入數(shù)據(jù),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-10-10
  • Redis中散列類型的常用命令小結

    Redis中散列類型的常用命令小結

    散列類型的鍵值其實也是一種字典解耦,其存儲了字段和字段值的映射,但字段值只能是字符串,不支持其他數(shù)據(jù)類型,所以說散列類型不能嵌套其他的數(shù)據(jù)類型。下面就來詳細介紹下Redis中散列類型的常用命令,有需要的可以參考學習。
    2016-09-09
  • Redis實現(xiàn)附近商鋪的項目實戰(zhàn)

    Redis實現(xiàn)附近商鋪的項目實戰(zhàn)

    本文主要介紹了Redis實現(xiàn)附近商鋪的項目實戰(zhàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-01-01
  • 基于redis實現(xiàn)token驗證用戶是否登陸

    基于redis實現(xiàn)token驗證用戶是否登陸

    這篇文章主要為大家詳細介紹了基于redis實現(xiàn)token驗證用戶是否登陸,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-08-08
  • redis requires ruby version2.2.2的解決方案

    redis requires ruby version2.2.2的解決方案

    本文主要介紹了redis requires ruby version2.2.2的解決方案,文中通過示例代碼介紹的非常詳細,需要的朋友們下面隨著小編來一起學習學習吧
    2021-07-07
  • Redis安全策略詳解

    Redis安全策略詳解

    緩存穿透是指當用戶在查詢一條數(shù)據(jù)的時候,而此時數(shù)據(jù)庫和緩存卻沒有關于這條數(shù)據(jù)的任何記錄,而這條數(shù)據(jù)在緩存中沒找到就會向數(shù)據(jù)庫請求獲取數(shù)據(jù)。用戶拿不到數(shù)據(jù)時,就會一直發(fā)請求,查詢數(shù)據(jù)庫,這樣會對數(shù)據(jù)庫的訪問造成很大的壓力
    2022-07-07
  • Redis 哨兵機制及配置實現(xiàn)

    Redis 哨兵機制及配置實現(xiàn)

    本文主要介紹了Redis 哨兵機制及配置實現(xiàn),文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-03-03

最新評論