Springboot 系列 (15) - Springboot+Redis(四) | 使用 spring-boot-starter-data-redis 实现用户验证实例
Spring Boot 从 2.0 版本开始,spring-boot-starter-data-redis 将 Redis 的默认 Jedis 客户端替换成了 Lettuce 客户端。
Lettuce 是一个可扩展的线程安全 Redis 客户端,用于同步、异步和反应式使用。如果多个线程避免阻塞和事务性操作(如 BLPOP 和 MULTI/EXEC ),则它们可能共享一个连接。Lettuce 是基于 Netty 框架,支持高级 Redis 功能,如 Sentinel、群集、管道、自动重新连接和 Redis 数据模型。
本文使用 Redis 的 Lettuce 客户端(spring-boot-starter-data-redis)实现用户验证实例。
Lettuce:https://lettuce.io/
Lettuce GitHub:https://github.com/lettuce-io/lettuce-core
1. 开发环境
Windows版本:Windows 10 Home (20H2)
IntelliJ IDEA (https://www.jetbrains.com/idea/download/):Community Edition for Windows 2020.1.4
Apache Maven (https://maven.apache.org/):3.8.1
注:Spring 开发环境的搭建,可以参考 “ Spring基础知识(1)- Spring简介、Spring体系结构和开发环境配置 ”。
2. 创建 Spring Boot 基础项目
项目实例名称:SpringbootExample15
Spring Boot 版本:2.6.6
创建步骤:
(1) 创建 Maven 项目实例 SpringbootExample15;
(2) Spring Boot Web 配置;
具体操作请参考 “Springboot 系列 (2) - 在 Spring Boot 项目里使用 Thymeleaf、JQuery+Bootstrap 和国际化” 里的项目实例 SpringbootExample02,文末包含如何使用 spring-boot-maven-plugin 插件运行打包的内容。
SpringbootExample15 和 SpringbootExample02 相比,SpringbootExample15 不导入 Thymeleaf 依赖包,也不配置 jQuery、Bootstrap、模版文件(templates/*.html)和国际化。
3. 配置 spring-boot-starter-data-redis
1) 修改 pom.xml,导入 Lettuce 依赖包
1 <project ... > 2 ... 3 <dependencies> 4 ... 5 6 <dependency> 7 <groupId>org.springframework.boot</groupId> 8 <artifactId>spring-boot-starter-data-redis</artifactId> 9 </dependency> 10 11 ... 12 </dependencies> 13 14 ... 15 </project>
在IDE中项目列表 -> SpringbootExample15 -> 点击鼠标右键 -> Maven -> Reload Project
2) 修改 src/main/resources/application.properties 文件,添加如下配置
# redis
spring.redis.database=0
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.password=123456
spring.redis.timeout=5000
spring.redis.lettuce.pool.max-active=10
spring.redis.lettuce.pool.max-idle=10
spring.redis.lettuce.pool.max-wait=-1
spring.redis.lettuce.pool.min-idle=0
注:max-wait 使用负值表示没有限制(或称无穷大)
3) 修改 src/main/java/com/example/controller/IndexController.java 文件
1 package com.example.controller; 2 3 import org.springframework.beans.factory.annotation.Autowired; 4 import org.springframework.stereotype.Controller; 5 import org.springframework.web.bind.annotation.RequestMapping; 6 import org.springframework.web.bind.annotation.ResponseBody; 7 8 import org.springframework.data.redis.core.StringRedisTemplate; 9 10 @Controller 11 public class IndexController { 12 @Autowired 13 private StringRedisTemplate stringRedisTemplate; 14 15 @ResponseBody 16 @RequestMapping("/test") 17 public String test() { 18 19 String str = stringRedisTemplate.opsForValue().get("starter"); 20 return "Test Page: " + str; 21 } 22 23 }
4) 运行
(1) 创建 Redis Key
本文操作的 Redis Server 运行在本地,即 127.0.0.1 或 localhost。
启动一个 cmd 窗口,运行如下命令。
C:\> redis-cli.exe -h 127.0.0.1 -p 6379
127.0.0.1:6379> AUTH "123456"
OK
127.0.0.1:6379> SET starter "Redis starter-data-redis Demo"
OK
(2) 测试
访问 http://localhost:9090/test,页面显示:
Test Page: Redis starter-data-redis Demo
4. 配置 Security
1) 修改 pom.xml,导入 Security 依赖包
1 <project ... > 2 ... 3 <dependencies> 4 ... 5 6 <!-- Spring security --> 7 <dependency> 8 <groupId>org.springframework.boot</groupId> 9 <artifactId>spring-boot-starter-security</artifactId> 10 </dependency> 11 12 ... 13 </dependencies> 14 15 ... 16 </project>
在IDE中项目列表 -> SpringbootExample15 -> 点击鼠标右键 -> Maven -> Reload Project
2) 修改 src/main/resources/application.properties 文件,添加如下配置
# security
spring.security.user.name=admin
spring.security.user.password=123456
spring.security.user.roles=admin
运行并访问 http://localhost:9090/test,自动跳转到 http://localhost:9090/login (Spring security 的默认页面),输入上面的用户名和密码登录,登录后跳转到 http://localhost:9090/test。
3) 创建 src/main/java/com/example/service/RedisUserDetailsService.java 文件
1 package com.example.service; 2 3 import java.util.List; 4 import java.util.ArrayList; 5 6 import org.springframework.beans.factory.annotation.Autowired; 7 import org.springframework.context.annotation.Configuration; 8 import org.springframework.security.core.userdetails.User; 9 import org.springframework.security.core.userdetails.UserDetails; 10 import org.springframework.security.core.userdetails.UserDetailsService; 11 import org.springframework.security.core.userdetails.UsernameNotFoundException; 12 import org.springframework.security.core.GrantedAuthority; 13 14 import org.springframework.data.redis.core.StringRedisTemplate; 15 16 @Configuration 17 public class RedisUserDetailsService implements UserDetailsService { 18 @Autowired 19 private StringRedisTemplate stringRedisTemplate; 20 21 @Override 22 public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { 23 24 String password = (String)stringRedisTemplate.opsForHash().get("users", username); 25 System.out.println("loadUserByUsername() -> username = " + username + ", password = " + password); 26 27 List<GrantedAuthority> authorities = new ArrayList<>(); 28 29 User userDetails= new User(username, password, authorities); 30 return userDetails; 31 } 32 }
4) 创建 src/main/java/com/example/config/WebSecurityConfig.java 文件
1 package com.example.config; 2 3 import org.springframework.context.annotation.Bean; 4 import org.springframework.beans.factory.annotation.Autowired; 5 import org.springframework.context.annotation.Configuration; 6 import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 7 import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 8 //import org.springframework.security.core.userdetails.UserDetailsService; 9 import com.example.service.RedisUserDetailsService; 10 import org.springframework.security.crypto.password.NoOpPasswordEncoder; 11 import org.springframework.security.crypto.password.PasswordEncoder; 12 13 @Configuration 14 public class WebSecurityConfig extends WebSecurityConfigurerAdapter { 15 @Autowired 16 //private UserDetailsService userDetailsService; 17 private RedisUserDetailsService redisUserDetailsService; 18 19 @Override 20 protected void configure(AuthenticationManagerBuilder auth) throws Exception { 21 //auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); 22 auth.userDetailsService(redisUserDetailsService).passwordEncoder(passwordEncoder()); 23 } 24 25 @Bean 26 public PasswordEncoder passwordEncoder(){ 27 return NoOpPasswordEncoder.getInstance(); 28 } 29 }
5) 运行
(1) 创建 Redis Key
启动一个 cmd 窗口,运行如下命令。
C:\> redis-cli.exe -h 127.0.0.1 -p 6379
127.0.0.1:6379> AUTH "123456"
OK
127.0.0.1:6379> HSET users admin2 "admin2" user2 "user2"
OK
(2) 测试
运行并访问 http://localhost:9090/test,自动跳转到 http://localhost:9090/login (Spring security 的默认页面),输入用户/密码: admin2/admin2 或 user2/user2,登录后跳转到 http://localhost:9090/test。
注:此时 application.properties 里设置的用户/密码(admin/123456)无法登录。