• 设为首页
  • 收藏本站
  • 积分充值
  • VIP赞助
  • 手机版
  • 微博
  • 微信
    微信公众号 添加方式:
    1:搜索微信号(888888
    2:扫描左侧二维码
  • 快捷导航
    福建二哥 门户 查看主题

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

    发布者: 土豆服务器 | 发布时间: 2025-6-19 12:36| 查看数: 36| 评论数: 0|帖子模式

    在现代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. 环境配置

    首先,在
    1. pom.xml
    复制代码
    中添加Redis和Spring Security相关依赖:
    1. <dependencies>
    2.     <!-- Spring Boot Web -->
    3.     <dependency>
    4.         <groupId>org.springframework.boot</groupId>
    5.         <artifactId>spring-boot-starter-web</artifactId>
    6.     </dependency>
    7.    
    8.     <!-- Redis -->
    9.     <dependency>
    10.         <groupId>org.springframework.boot</groupId>
    11.         <artifactId>spring-boot-starter-data-redis</artifactId>
    12.     </dependency>

    13.     <!-- Spring Security -->
    14.     <dependency>
    15.         <groupId>org.springframework.boot</groupId>
    16.         <artifactId>spring-boot-starter-security</artifactId>
    17.     </dependency>

    18.     <!-- JWT Token -->
    19.     <dependency>
    20.         <groupId>io.jsonwebtoken</groupId>
    21.         <artifactId>jjwt-api</artifactId>
    22.         <version>0.11.2</version>
    23.     </dependency>
    24.     <dependency>
    25.         <groupId>io.jsonwebtoken</groupId>
    26.         <artifactId>jjwt-impl</artifactId>
    27.         <version>0.11.2</version>
    28.     </dependency>
    29.     <dependency>
    30.         <groupId>io.jsonwebtoken</groupId>
    31.         <artifactId>jjwt-jackson</artifactId>
    32.         <version>0.11.2</version>
    33.     </dependency>
    34. </dependencies>
    复制代码
    1. application.yml
    复制代码
    中配置Redis:
    1. spring:
    2.   redis:
    3.     host: localhost
    4.     port: 6379
    5.     timeout: 6000ms
    复制代码
    2. Redis会话管理实现

    在Spring Boot中,我们可以通过Redis来管理会话信息,下面的示例代码展示如何使用Redis来存储用户会话信息。
    配置Redis序列化器
    为了使得对象能够存储在Redis中,我们需要配置Redis的序列化方式。
    1. @Configuration
    2. public class RedisConfig {

    3.     @Bean
    4.     public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
    5.         RedisTemplate<String, Object> template = new RedisTemplate<>();
    6.         template.setConnectionFactory(connectionFactory);
    7.         
    8.         // 设置Key和Value的序列化器
    9.         template.setKeySerializer(new StringRedisSerializer());
    10.         template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
    11.         
    12.         return template;
    13.     }
    14. }
    复制代码
    使用Redis存储Session信息
    我们可以在用户登录后将会话信息存入Redis中。
    1. @Service
    2. public class SessionService {

    3.     @Autowired
    4.     private RedisTemplate<String, Object> redisTemplate;

    5.     public void saveSession(String sessionId, Object sessionData) {
    6.         redisTemplate.opsForValue().set(sessionId, sessionData, 30, TimeUnit.MINUTES); // 会话有效期30分钟
    7.     }

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

    11.     public void deleteSession(String sessionId) {
    12.         redisTemplate.delete(sessionId);
    13.     }
    14. }
    复制代码
    3. Token认证实现

    JWT生成与解析
    JWT是无状态的认证方式,将用户信息封装在Token中,通过数字签名保证Token的安全性。我们使用
    1. jjwt
    复制代码
    库来生成和解析JWT。
    JWT工具类
    1. @Service
    2. public class JwtTokenProvider {

    3.     private static final String SECRET_KEY = "yourSecretKey";

    4.     // 生成Token
    5.     public String generateToken(String username) {
    6.         return Jwts.builder()
    7.                 .setSubject(username)
    8.                 .setIssuedAt(new Date())
    9.                 .setExpiration(new Date(System.currentTimeMillis() + 3600000)) // Token有效期1小时
    10.                 .signWith(SignatureAlgorithm.HS512, SECRET_KEY)
    11.                 .compact();
    12.     }

    13.     // 解析Token
    14.     public String getUsernameFromToken(String token) {
    15.         return Jwts.parser()
    16.                 .setSigningKey(SECRET_KEY)
    17.                 .parseClaimsJws(token)
    18.                 .getBody()
    19.                 .getSubject();
    20.     }

    21.     // 验证Token是否过期
    22.     public boolean isTokenExpired(String token) {
    23.         Date expiration = Jwts.parser()
    24.                 .setSigningKey(SECRET_KEY)
    25.                 .parseClaimsJws(token)
    26.                 .getBody()
    27.                 .getExpiration();
    28.         return expiration.before(new Date());
    29.     }
    30. }
    复制代码
    JWT拦截器实现
    为了在每次请求时验证Token的有效性,我们可以通过拦截器在请求到达控制器之前进行校验。
    1. @Component
    2. public class JwtAuthenticationFilter extends OncePerRequestFilter {

    3.     @Autowired
    4.     private JwtTokenProvider jwtTokenProvider;

    5.     @Override
    6.     protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
    7.         String token = getTokenFromRequest(request);
    8.         
    9.         if (token != null && !jwtTokenProvider.isTokenExpired(token)) {
    10.             String username = jwtTokenProvider.getUsernameFromToken(token);
    11.             // 在SecurityContext中设置认证信息
    12.             UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(username, null, new ArrayList<>());
    13.             SecurityContextHolder.getContext().setAuthentication(authentication);
    14.         }
    15.         
    16.         filterChain.doFilter(request, response);
    17.     }

    18.     private String getTokenFromRequest(HttpServletRequest request) {
    19.         String bearerToken = request.getHeader("Authorization");
    20.         if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
    21.             return bearerToken.substring(7);
    22.         }
    23.         return null;
    24.     }
    25. }
    复制代码
    将拦截器添加到Spring Security配置中
    我们需要将
    1. JwtAuthenticationFilter
    复制代码
    加入到Spring Security的过滤器链中。
    1. @Configuration
    2. @EnableWebSecurity
    3. public class SecurityConfig extends WebSecurityConfigurerAdapter {

    4.     @Autowired
    5.     private JwtAuthenticationFilter jwtAuthenticationFilter;

    6.     @Override
    7.     protected void configure(HttpSecurity http) throws Exception {
    8.         http
    9.             .csrf().disable()
    10.             .authorizeRequests()
    11.             .antMatchers("/login", "/register").permitAll()  // 登录、注册请求不需要认证
    12.             .anyRequest().authenticated()
    13.             .and()
    14.             .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
    15.     }
    16. }
    复制代码
    4. Token与Redis的结合

    为了进一步增强安全性,我们可以将生成的Token存储在Redis中,并设置一个过期时间。当Token失效或用户登出时,将其从Redis中移除。
    1. @Service
    2. public class TokenService {

    3.     @Autowired
    4.     private RedisTemplate<String, Object> redisTemplate;
    5.     @Autowired
    6.     private JwtTokenProvider jwtTokenProvider;

    7.     public String createToken(String username) {
    8.         String token = jwtTokenProvider.generateToken(username);
    9.         redisTemplate.opsForValue().set(username, token, 1, TimeUnit.HOURS);  // Token存储在Redis中,1小时过期
    10.         return token;
    11.     }

    12.     public boolean validateToken(String token) {
    13.         String username = jwt
    复制代码
    1.         String username = jwtTokenProvider.getUsernameFromToken(token);
    2.         String redisToken = (String) redisTemplate.opsForValue().get(username);
    3.         return token.equals(redisToken) &amp;&amp; !jwtTokenProvider.isTokenExpired(token);
    4.     }

    5.     public void invalidateToken(String username) {
    6.         redisTemplate.delete(username);  // 从Redis中移除Token
    7.     }
    8. }
    复制代码
    5. 登录接口实现

    用户登录成功后,生成Token并存储到Redis中,同时将Token返回给客户端。客户端在后续的请求中携带此Token。
    1. @RestController
    2. @RequestMapping("/auth")
    3. public class AuthController {

    4.     @Autowired
    5.     private TokenService tokenService;
    6.     @Autowired
    7.     private AuthenticationManager authenticationManager;

    8.     @PostMapping("/login")
    9.     public ResponseEntity<?> login(@RequestBody LoginRequest loginRequest) {
    10.         try {
    11.             // 认证用户
    12.             Authentication authentication = authenticationManager.authenticate(
    13.                 new UsernamePasswordAuthenticationToken(
    14.                     loginRequest.getUsername(), loginRequest.getPassword()));
    15.             
    16.             SecurityContextHolder.getContext().setAuthentication(authentication);
    17.             
    18.             // 生成Token并存储到Redis
    19.             String token = tokenService.createToken(loginRequest.getUsername());
    20.             
    21.             return ResponseEntity.ok(new JwtResponse(token));
    22.         } catch (AuthenticationException e) {
    23.             return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Authentication failed");
    24.         }
    25.     }

    26.     @PostMapping("/logout")
    27.     public ResponseEntity<?> logout(HttpServletRequest request) {
    28.         String token = getTokenFromRequest(request);
    29.         if (token != null) {
    30.             String username = jwtTokenProvider.getUsernameFromToken(token);
    31.             tokenService.invalidateToken(username);  // 从Redis中移除Token
    32.         }
    33.         return ResponseEntity.ok("Logout successful");
    34.     }

    35.     private String getTokenFromRequest(HttpServletRequest request) {
    36.         String bearerToken = request.getHeader("Authorization");
    37.         if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
    38.             return bearerToken.substring(7);
    39.         }
    40.         return null;
    41.     }
    42. }
    复制代码
    6. 请求流程示例


    • 用户登录:用户提供用户名和密码,通过
      1. /auth/login
      复制代码
      接口进行登录。成功后,服务器生成JWT Token并存入Redis,并返回给客户端。
    • Token携带请求:客户端在后续的请求中,将Token放在
      1. Authorization
      复制代码
      头部中,发送到服务器。服务器在收到请求后,通过JWT解析Token,验证有效性。
    • 登出操作:用户在登出时,前端请求
      1. /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认证内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

    来源:https://www.jb51.net/database/340107bj5.htm
    免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

    最新评论

    浏览过的版块

    QQ Archiver 手机版 小黑屋 福建二哥 ( 闽ICP备2022004717号|闽公网安备35052402000345号 )

    Powered by Discuz! X3.5 © 2001-2023

    快速回复 返回顶部 返回列表