SpringBoot集成Redis
- 导入依赖
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>3.2.5</version>
</dependency>
- 在yml中配置redis连接信息
spring:
data:
redis:
host: 127.0.0.1
port: 6379
connect-timeout: 1000
- 调用
StringRedisTemplate
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import walker.pojo.Result;
@RestController
public class RedisTest {
@Autowired(required = true)
private StringRedisTemplate redisTemplate;
@GetMapping("/rd")
public Result get() {
redisTemplate.opsForValue().set("h", "xxxxx");
return Result.success(redisTemplate.opsForValue().get("h"));
}
}
验证方法
1、访问controller
2、打开redis-cli.exe
> get h
获得正确值则连接成功
令牌主动失效机制
- 登录成功后,给浏览器响应令牌的同时,把该令牌存储到redis中
@PostMapping("/login")
public Result<String> login(@Pattern(regexp = "^\\S{5,16}$") String username, @Pattern(regexp = "^\\S{5,16}$")String password) {
// 根据用户名查询用户
User loginUser = userService.findByUserName(username);
// 判断用户是否存在
if (loginUser == null) {
return Result.error("用户名错误!");
}
// 密码是否正确
if (Md5Util.getMD5String(password).equals(loginUser.getPassword())) {
Map<String, Object> claims = new HashMap<>();
claims.put("id", loginUser.getId());
claims.put("username", loginUser.getUsername());
String token = JwtUtil.genToken(claims);
// 把token存储到redis中
ValueOperations<String, String> ops = stringRedisTemplate.opsForValue();
// token过期时间: new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 12)
ops.set(token, token,12, TimeUnit.HOURS);
return Result.success(token);
}
return Result.error("密码错误!");
}
- LoginInterceptor拦截器中,需要验证浏览器携带的令牌,并且同时需要获取到redis中存储的与之相同的令牌
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import walker.utils.JwtUtil;
import walker.utils.ThreadLocalUtil;
import java.util.Map;
@Component
public class LoginInterceptor implements HandlerInterceptor {
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 令牌验证
String token = request.getHeader("Authorization");
try {
// 从redis中获取相同的token
ValueOperations<String, String> ops = stringRedisTemplate.opsForValue();
String redisToken = ops.get(token);
if (redisToken == null) {
// token失效
throw new RuntimeException();
}
Map<String, Object> claims = JwtUtil.parseToken(token);
// 把业务数据存储到ThreadLocal中
ThreadLocalUtil.set(claims);
// 放行
return true;
}catch (Exception e){
// http响应状态码为401
response.setStatus(401);
// 不放行
return false;
}
}
// 防止内存泄漏
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// 清空ThreadLocal中的数据
ThreadLocalUtil.remove();
}
}
- 当用户修改密码成功后,删除redis中存储的旧令牌
怎么获得原来的token呢? - 因为更新密码需要请求头携带token,所以在代码里加上@RequestHeader(name = "Authorization") String token
这个参数就可以得到token
@PatchMapping("/updatePwd")
public Result updatePwd(@RequestBody Map<String,String> params, @RequestHeader(name = "Authorization") String token) {
// 校验参数
String oldPwd = params.get("old_pwd");
String newPwd = params.get("new_pwd");
String rePwd = params.get("re_pwd");
if (!StringUtils.hasLength(oldPwd) || !StringUtils.hasLength(newPwd) || !StringUtils.hasLength(rePwd)) {
return Result.error("缺少必要参数!");
}
// 原密码是否正确
Map<String, Object> map = ThreadLocalUtil.get();
String username = (String)map.get("username");
User loginUser = userService.findByUserName(username);
if (!loginUser.getPassword().equals(Md5Util.getMD5String(oldPwd))) {
return Result.error("原密码填写错误!");
}
// 新密码和确认新密码是否正确
if (!newPwd.equals(rePwd)) {
return Result.error("两次填写的新密码不一样!");
}
Integer id = loginUser.getId();
userService.updatePwd(Md5Util.getMD5String(newPwd), id);
// 这里是密码更新了,所以token也要更新
// 删除redis中对应的token
ValueOperations<String, String> ops = stringRedisTemplate.opsForValue();
ops.getOperations().delete(token);
return Result.success();
}