【SpringBoot实战】SpringBoot与Redis

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();
	}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值