Redisson 是架设在 Redis 基础上的一个 Java 驻内存数据网格(In-Memory Data Grid)。它充分的利用了 Redis 键值数据库提供的一系列优势,基于 Java 实用工具包中常用接口,为使用者提供了一系列具有分布式特性的常用工具类。
Redisson 采用了基于 NIO 的 Netty 框架,不仅能作为 Redis 底层驱动客户端,具备提供对 Redis 各种组态形式的连接功能,对 Redis 命令能以同步发送、异步形式发送、异步流形式发送或管道形式发送的功能。
本文使用 Redis 的 Redisson 客户端实现用户验证实例。
Redisson:https://redisson.org/
Redisson GitHub:https://github.com/redisson/redisson
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体系结构和开发环境配置 ”。
项目实例名称:SpringbootExample14
Spring Boot 版本:2.6.6
创建步骤:
(1) 创建 Maven 项目实例 SpringbootExample14;
(2) Spring Boot Web 配置;
具体操作请参考 “Spring 系列 (2) - 在 Spring Boot 项目里使用 Thymeleaf、JQuery+Bootstrap 和国际化” 里的项目实例 SpringbootExample02,文末包含如何使用 spring-boot-maven-plugin 插件运行打包的内容。
SpringbootExample14 和 SpringbootExample02 相比,SpringbootExample14 不导入 Thymeleaf 依赖包,也不配置 jQuery、Bootstrap、模版文件(templates/*.html)和国际化。
1) 修改 pom.xml,导入 Redisson 依赖包
1 <project ... > 2 ... 3 <dependencies> 4 ... 5 6 <dependency> 7 <groupId>org.redisson</groupId> 8 <artifactId>redisson-spring-boot-starter</artifactId> 9 <version>3.17.1</version> 10 </dependency> 11 12 ... 13 </dependencies> 14 15 ... 16 </project>
在IDE中项目列表 -> SpringbootExample14 -> 点击鼠标右键 -> Maven -> Reload Project
注:redisson 版本 3.17.1 对应的 redisson-spring-data 版本是 26,redisson-spring-data 版本和 Spring Boot 版本的对应关系:
redisson-spring-data 版本 | Spring Boot 版本 |
redisson-spring-data-16 | 1.3.y |
redisson-spring-data-17 | 1.4.y |
redisson-spring-data-18 | 1.5.y |
redisson-spring-data-2x | 2.x.y |
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.pool.max-active=10
spring.redis.pool.max-idle=10
spring.redis.pool.max-wait=-1
spring.redis.sentinel.master=
spring.redis.sentinel.nodes=
spring.redis.redisson.file=classpath:redisson.yml
注:max-wait 使用负值表示没有限制(或称无穷大)
3) 创建 src/main/resources/redisson.yml 文件
# 单节点配置 singleServerConfig: # 客户端名称 clientName: redisson-test # 节点地址 address: redis://127.0.0.1:6379 # 数据库编号 database: 0 # 密码 password: 123456 # 连接空闲超时,单位:毫秒 idleConnectionTimeout: 10000 # 连接超时,单位:毫秒 connectTimeout: 10000 # 命令等待超时,单位:毫秒 timeout: 3000 # 命令失败重试次数,如果尝试达到 retryAttempts(命令失败重试次数) 仍然不能将命令发送至某个指定的节点时,将抛出错误。 # 如果尝试在此限制之内发送成功,则开始启用 timeout(命令等待超时) 计时。 #retryAttempts: 3 # 命令重试发送时间间隔,单位:毫秒 #retryInterval: 1500 # 重新连接时间间隔,单位:毫秒 #reconnectionTimeout: 3000 # 执行失败最大次数 #failedAttempts: 3 # 单个连接最大订阅数量 #subscriptionsPerConnection: 5 # 发布和订阅连接的最小空闲连接数 #subscriptionConnectionMinimumIdleSize: 1 # 发布和订阅连接池大小 #subscriptionConnectionPoolSize: 50 # 最小空闲连接数 #connectionMinimumIdleSize: 32 # 连接池大小 #connectionPoolSize: 64 # DNS监测时间间隔,单位:毫秒 #dnsMonitoringInterval: 5000 # Netty线程池数量, 默认值: 当前处理核数量 * 2 #threads: 0 # Netty线程池数量, 默认值: 当前处理核数量 * 2 #nettyThreads: 0 # 编码 #codec: # class: org.redisson.codec.JsonJacksonCodec # 传输模式 #transportMode: NIO
4) 修改 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("redisson"); 20 return "Test Page: " + str; 21 } 22 23 }
5) 运行
(1) 创建 Redis KeyS
本文操作的 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 redisson "Redis Redisson Demo"
OK
(2) 测试
访问 http://localhost:9090/test,页面显示:
Test Page: Redis Redisson Demo
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中项目列表 -> SpringbootExample14-> 点击鼠标右键 -> 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 = stringRedisTemplate.opsForValue().get(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> SET user "user"
OK
(2) 测试
运行并访问 http://localhost:9090/test,自动跳转到 http://localhost:9090/login (Spring security 的默认页面),输入用户/密码: user/user,登录后跳转到 http://localhost:9090/test。
注:此时 application.properties 里设置的用户/密码(admin/123456)无法登录。