Redis实现会话管理和token认证的示例代码

 更新时间:2025年04月22日 09:54:50   作者:昱晏  
会话管理和身份认证是实现用户登录、权限管理等功能的基础,本文主就来介绍一下Redis实现会话管理和token认证的示例代码,具有一定的参考价值,感兴趣的可以了解一下

在现代Web应用中,会话管理身份认证是实现用户登录、权限管理等功能的基础。传统的会话管理通过服务器端保存会话信息来实现,但随着应用的扩展,尤其在分布式系统中,这种方式的局限性逐渐显现。Redis作为分布式缓存系统,具备高性能和高可用性,能够很好地解决分布式环境下的会话管理和Token认证问题。

本教程将介绍如何基于Redis和Spring Boot 实现会话管理与Token认证,确保应用在高并发、分布式架构中具备良好的性能和扩展性。

一、使用场景

  • 分布式系统:当系统部署在多个服务实例上时,服务器本地的Session无法跨实例共享,而Redis能作为集中式存储,帮助管理所有实例的会话信息。
  • 无状态认证:基于Token认证机制的实现,特别是JWT(JSON Web Token),适用于用户登录后通过Token进行认证,避免在每次请求时重新查询数据库或读取Session。
  • 高并发场景:在高并发的情况下,Redis的高吞吐量和低延迟能够保证会话管理和认证机制的高效性。

二、原理解析

1. 会话管理

传统的会话管理通过在服务器端保存用户的会话状态(Session),并通过客户端(通常是浏览器)保存的Session ID与服务器进行匹配,来确定用户身份。在分布式环境下,本地Session机制无法保证跨实例共享,而Redis作为集中式存储,能够提供跨服务实例的会话共享机制。

2. Token认证

Token认证,尤其是基于JWT的认证方式,是一种无状态认证方案。与传统的Session机制不同,JWT将用户信息封装在Token中,发送给客户端,客户端在后续请求中携带该Token进行认证,服务器通过验证Token来确定用户身份。Redis可以用作存储Token的有效期或与其他用户数据的映射。

3. Redis在会话管理和Token认证中的角色

  • 会话管理:将用户的会话信息存储在Redis中,保证分布式系统中不同实例对会话的共享访问。
  • Token认证:存储Token的有效性和用户信息,或用于存储黑名单Token(已失效或已注销的Token)。

三、解决方案实现

1. 环境配置

首先,在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会话管理实现

在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认证实现

JWT生成与解析

JWT是无状态的认证方式,将用户信息封装在Token中,通过数字签名保证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拦截器实现

为了在每次请求时验证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. 登录接口实现

用户登录成功后,生成Token并存储到Redis中,同时将Token返回给客户端。客户端在后续的请求中携带此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携带请求:客户端在后续的请求中,将Token放在Authorization头部中,发送到服务器。服务器在收到请求后,通过JWT解析Token,验证有效性。
  • 登出操作:用户在登出时,前端请求/auth/logout接口,服务器将用户的Token从Redis中移除,Token失效。

四、Redis会话管理与Token认证效果

  • 高效性能:Redis的高并发读写能力保证了在高并发场景下的会话存储与Token验证的高效性。
  • 分布式支持:使用Redis作为集中存储,可以确保在多实例或分布式部署环境中共享会话数据,避免本地Session的局限性。
  • 安全性增强:通过Redis存储Token以及Token的有效期控制,可以快速实现Token的失效处理,增强了安全性。

五、总结

Redis不仅能解决分布式环境下会话共享的问题,也能通过高效存储和快速读取实现了Token认证的高性能处理。在Spring Boot 中,使用Redis与JWT结合的方案为分布式架构提供了强大的认证与授权支持。

到此这篇关于Redis实现会话管理和token认证的示例代码的文章就介绍到这了,更多相关Redis 会话管理和token认证内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 详解Redis实现分布式锁的原理

    详解Redis实现分布式锁的原理

    分布式锁,即分布式系统中的锁,在单体应用中我们通过锁解决的是控制共享资源访问的问题,而分布式锁,就是解决了分布式系统中控制共享资源访问的问题,本文讲给大家详细介绍一下Redis实现分布式锁的原理,需要的朋友可以参考下
    2023-09-09
  • Redis解决缓存雪崩、穿透和击穿的问题(Redis使用必看)

    Redis解决缓存雪崩、穿透和击穿的问题(Redis使用必看)

    这篇文章主要给大家介绍了Redis解决缓存雪崩、缓存穿透、缓存击穿的解决方案,文中有详细的图文介绍,具有一定的参考价值,需要的朋友可以参考下
    2023-08-08
  • redis使用skiplist跳表的原因解析

    redis使用skiplist跳表的原因解析

    经常会有人问这个问题,redis中为什么要使用跳表?这个问题,redis作者已经给出过明确答案,今天通过本文再给大家讲解下这个问题,对redis skiplist跳表知识感兴趣的朋友一起看看吧
    2022-10-10
  • Redis之缓存击穿、穿透、雪崩问题及处理

    Redis之缓存击穿、穿透、雪崩问题及处理

    文章详细介绍了缓存击穿、缓存穿透和缓存雪崩的概念、触发条件、典型场景、可能后果及解决策略,强调了缓存设计中需考虑的多个方面,包括缓存策略、系统一致性、异常处理和优化措施,通过合理设置TTL、使用分布式锁、预热缓存、逻辑过期刷新、布隆过滤器等多种方法
    2026-04-04
  • Redis教程之代理ip池设计方法详解

    Redis教程之代理ip池设计方法详解

    这篇文章主要介绍了Redis实现代理ip池的设计方法,文中给出了详细的介绍与示例代码,相信对大家的理解和学习具有一定的参考借鉴价值,有需要的朋友们下面来一起看看吧。
    2017-01-01
  • Redis+拦截器实现接口防刷

    Redis+拦截器实现接口防刷

    接口防刷有很多种实现思路,例如:拦截器/AOP+Redis、拦截器/AOP+本地缓存、前端限制等等很多种实现思路,本文主要来讲一下 拦截器+Redis 的实现方式,需要的可以参考下
    2023-08-08
  • 基于Redis+Lua脚本的分布式全局令牌桶限流方案

    基于Redis+Lua脚本的分布式全局令牌桶限流方案

    这篇文章主要介绍了如何采用Redis和Lua脚本实现分布式全局令牌桶限流,解决多实例部署、并发超卖及限流一致性问题,保障高并发场景下流量控制与系统稳定性,需要的朋友可以参考下
    2026-05-05
  • redis 消息队列完成秒杀过期订单处理方法(一)

    redis 消息队列完成秒杀过期订单处理方法(一)

    这篇文章主要介绍了redis 消息队列完成秒杀过期订单处理方法,包括redis 消息通知处理代金券过期问题–失效问题的分析,本文给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧
    2024-07-07
  • Redis高效率原因及数据结构分析

    Redis高效率原因及数据结构分析

    这篇文章主要为大家详细的介绍了Redis高效的原因以及分析了Redis高效的数据结构,有需要的朋友可以借鉴参考下,希望能够有所帮助
    2021-09-09
  • Redis下载与安装全过程(Windows版)

    Redis下载与安装全过程(Windows版)

    这篇文章详细介绍了如何在Windows系统上安装和配置Redis,包括下载、安装步骤、配置服务、启动和停止服务以及基本测试方法,同时,还解决了一些常见的连接问题,如外部服务器连接失败
    2026-02-02

最新评论