案例一:github/03/security/demo04
# core模块将ValidateCodeException提取到exception文件夹
# core模块导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
# web模块配置数据源
spring:
# 数据源配置
datasource:
username: root
password: 123456
url: jdbc:mysql://127.0.0.1:3306/demo?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT
#mysql8版本以上驱动包指定新的驱动类
driver-class-name: com.mysql.cj.jdbc.Driver
# SpringSecurityConfig中添加如下
@Autowired
DataSource dataSource;
@Bean
public JdbcTokenRepositoryImpl jdbcTokenRepository() {
JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
jdbcTokenRepository.setDataSource(dataSource);
// 是否启动项目时自动创建表,true自动创建,如果数据库中已经生成了persistent_logins表,则需要设为false,否则会报错
jdbcTokenRepository.setCreateTableOnStartup(true);
return jdbcTokenRepository;
}
.and()
.rememberMe() // 记住功能配置
.tokenRepository(jdbcTokenRepository()) //保存登录信息
.tokenValiditySeconds(60*60*24*7) //记住我有效时长
# 创建对应数据库
demo
# 前端添加如下
<input name="remember-me" type="checkbox" id="remember">记住我
# 获取验证码
08:43:37.204 INFO 18196 --- [nio-8080-exec-1] c.y.s.a.core.ImageCodeValidateFilter : session中的验证码为:null
08:43:37.205 INFO 18196 --- [nio-8080-exec-1] c.y.s.a.core.ImageCodeValidateFilter : 登录时输入的验证码为:null
08:43:37.220 INFO 18196 --- [nio-8080-exec-1] c.y.s.controller.CustomLoginController : 生成的图形验证码是:ebc3
# 认证时
08:44:08.023 INFO 18196 --- [nio-8080-exec-6] c.y.s.a.core.ImageCodeValidateFilter : session中的验证码为:null
08:44:08.023 INFO 18196 --- [nio-8080-exec-6] c.y.s.a.core.ImageCodeValidateFilter : 登录时输入的验证码为:ebc3
08:44:08.023 INFO 18196 --- [nio-8080-exec-6] c.y.s.a.core.ImageCodeValidateFilter : session中的验证码为:null
08:44:08.023 INFO 18196 --- [nio-8080-exec-6] c.y.s.a.core.ImageCodeValidateFilter : 登录时输入的验证码为:ebc3
# 没有获取到session中的验证码
# core模块添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
# redis配置类
@Configuration
public class LettuceRedisConfig {
@Bean
public RedisTemplate<String, Serializable> redisTemplate(LettuceConnectionFactory connectionFactory) {
RedisTemplate<String, Serializable> redisTemplate = new RedisTemplate<>();
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.setConnectionFactory(connectionFactory);
return redisTemplate;
}
}
# redis工具类
@Component
public class RedisUtils {
@Resource
private RedisTemplate<String, String> redisTemplate;
/**
* 设置key-value
* @param key 键
* @param value 值
*/
public void set(String key, String value) {
redisTemplate.opsForValue().set(key, value);
}
/**
* 设置带生存时间的key-value
* @param key 键
* @param value 值
* @param timeout 生存时间
* @param unit 时间单位
*/
public void set(String key, String value, long timeout, TimeUnit unit) {
redisTemplate.opsForValue().set(key, value, timeout, unit);
}
/**
* 设置指定数据的生存时间。
* @param key 键
* @param time 生存时间(秒)
*/
public void expire(String key, long time) {
redisTemplate.expire(key, time, TimeUnit.SECONDS);
}
/**
* 根据key,获取值
* @param key 键
* @return 获取到的值
*/
public String get(String key) {
return String.valueOf(redisTemplate.opsForValue().get(key));
}
/**
* 删除指定信息。
* @param key 键
* @return 是否删除成功
*/
public boolean delete(String key) {
return redisTemplate.delete(key);
}
}
# 修改获取验证码的接口
@RequestMapping("/code/image")
public void imageCode(HttpServletRequest request, HttpServletResponse response) throws IOException {
// 1. 获取验证码字符串
String code = defaultKaptcha.createText();
logger.info("生成的图形验证码是:" + code);
// 2. 将验证码放到redis中
ValueOperations<String, String> operations = redisTemplate.opsForValue();
operations.set(SESSION_KEY , code);
// 3. 获取验证码图片
BufferedImage image = defaultKaptcha.createImage(code);
// 4. 将验证码图片把它写出去
ServletOutputStream out = response.getOutputStream();
ImageIO.write(image, "jpg", out);
}
# 修改过滤器中的逻辑
private void validate(HttpServletRequest request) {
// 先获取seesion中的验证码
// String sessionCode =
// (String)request.getSession().getAttribute(CustomLoginController.SESSION_KEY);
// 获取用户输入的验证码
String inpuCode = request.getParameter("code");
// 获取redis中的验证码
ValueOperations<String, String> operations = redisTemplate.opsForValue();
String redisCode = operations.get(SESSION_KEY);;
//logger.info("session中的验证码为:" + sessionCode);
logger.info("登录时输入的验证码为:" + inpuCode);
logger.info("redis中的验证码为:" + redisCode);
// 判断是否正确
if(StringUtils.isBlank(inpuCode)) {
throw new ValidateCodeException("验证码不能为空");
}
if(!inpuCode.equalsIgnoreCase(redisCode)) {
throw new ValidateCodeException("验证码输入错误");
}
}
# web模块配置yml
spring:
redis:
host: 127.0.0.1
port: 6379
# password: 没有不用写
lettuce:
# 连接池配置
pool:
# 连接池中的最小空闲连接,默认 0
min-idle: 0
# 连接池中的最大空闲连接,默认 8
max-idle: 8
# 连接池最大阻塞等待时间(使用负值表示没有限制),默认 -1ms
max-wait: -1ms
# 连接池最大连接数(使用负值表示没有限制),默认 8
max-active: 8
# 获取验证码
09:46:30.656 INFO 5924 --- [nio-8080-exec-1] c.y.s.controller.CustomLoginController : 生成的图形验证码是:5nbn
# 认证
09:46:53.144 INFO 5924 --- [nio-8080-exec-3] c.y.s.service.CustomUserDetailsService : 请求认证的用户名: admin
09:47:07.077 INFO 5924 --- [nio-8080-exec-4] c.y.s.a.core.ImageCodeValidateFilter : 登录时输入的验证码为:5nbn
09:47:07.078 INFO 5924 --- [nio-8080-exec-4] c.y.s.a.core.ImageCodeValidateFilter : redis中的验证码为:5nbn
- 认证
- 不能跳转到指定页面
案例二:github/03/security/demo05
# core模块将ValidateCodeException提取到exception文件夹
# core模块导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
# web模块配置数据源
spring:
# 数据源配置
datasource:
username: root
password: 123456
url: jdbc:mysql://127.0.0.1:3306/demo?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT
#mysql8版本以上驱动包指定新的驱动类
driver-class-name: com.mysql.cj.jdbc.Driver
# SpringSecurityConfig中添加如下
@Autowired
DataSource dataSource;
@Bean
public JdbcTokenRepositoryImpl jdbcTokenRepository() {
JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
jdbcTokenRepository.setDataSource(dataSource);
// 是否启动项目时自动创建表,true自动创建
jdbcTokenRepository.setCreateTableOnStartup(false);
return jdbcTokenRepository;
}
.and()
.rememberMe() // 记住功能配置
.tokenRepository(jdbcTokenRepository()) //保存登录信息
.tokenValiditySeconds(60*60*24*7) //记住我有效时长
# 创建对应数据库
demo
# 前端添加如下
<input name="remember-me" type="checkbox" id="remember">记住我
# 测试
GET http://localhost:8080/code/image HTTP/1.1
POST http://localhost:8080/login?username=admin&password=admin&code=x88f HTTP/1.1
# 测试通过