38,令牌主动失效redis
登录成功后,给浏览器响应令牌的同时,把该令牌存储到redis中
LoginInterceptor拦截器中,需要验证浏览器携带的令牌,并同时需要获取到redis中存储的与之相同的令牌
当用户修改密码成功后,删除redis中存储的旧令牌
1,引入redis依赖:
- <!--redis依赖-->
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-data-redis</artifactId>
- </dependency>
复制代码 2,yml配置
- spring:
- profiles:
- active: dev
- application:
- name: JinheiNew
- datasource:
- driver-class-name: com.mysql.cj.jdbc.Driver
- url: jdbc:mysql://localhost:3306/big_event?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&allowMultiQueries=true&useSSL=false&allowPublicKeyRetrieval=true
- username: root
- password: root
- # redis配置
- data:
- redis:
- host: localhost
- port: 6379
- connect-timeout: 5000
复制代码 3,C层使用:
- package com.jinhei.controller;
-
- import com.jinhei.pojp.Result;
- import com.jinhei.pojp.User;
- import com.jinhei.service.UserService;
- import com.jinhei.utils.JwtUtils;
- import com.jinhei.utils.Md5Util;
- import com.jinhei.utils.ThreadLocalUtil;
- import io.swagger.v3.oas.annotations.Operation;
- import io.swagger.v3.oas.annotations.tags.Tag;
- import jakarta.validation.constraints.Pattern;
- import lombok.extern.slf4j.Slf4j;
- import org.hibernate.validator.constraints.URL;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.data.redis.core.StringRedisTemplate;
- import org.springframework.data.redis.core.ValueOperations;
- import org.springframework.util.StringUtils;
- import org.springframework.validation.annotation.Validated;
- import org.springframework.web.bind.annotation.*;
-
- import java.util.HashMap;
- import java.util.Map;
- import java.util.concurrent.TimeUnit;
-
- /**
- * 用户相关接口
- */
- @Tag(name = "用户相关接口")
- @RestController
- @RequestMapping("/user")
- @Slf4j
- @Validated
- public class UserController {
- @Autowired
- private UserService userService;
- @Autowired
- private StringRedisTemplate stringRedisTemplate;
- /**
- * 用户注册
- */
- @Operation(summary = "创建用户",description = "根据姓名创建用户")
- @PostMapping("/register")
- public Result register(@Pattern(regexp = "^[a-zA-Z0-9_-]{4,20}$") String username,@Pattern(regexp = "^[a-zA-Z0-9_-]{6,20}$") String password) {
- log.info("用户注册:username={},password={}", username, password);
-
- // 查看用户是否存在
- User user = userService.findByUsername(username);
- // 注册用户
- if (user == null){
- userService.register(username, password);
- return Result.success();
- }else {
- return Result.error("用户已存在");
- }
- }
-
- /**
- * 用户登录
- */
- @PostMapping("/login")
- public Result login(@Pattern(regexp = "^[a-zA-Z0-9_-]{4,20}$") String username,@Pattern(regexp = "^[a-zA-Z0-9_-]{6,20}$") String password) {
- log.info("用户登录:username={},password={}", username, password);
- // 查看用户是否存在
- User user = userService.findByUsername(username);
- // 登录用户
- if (user == null){
- return Result.error("用户不存在");
- }
- if (Md5Util.getMD5String(password).equals(user.getPassword())){
- // 登录成功
- // 生成JWT令牌
- Map<String, Object> claims = new HashMap<>();
- claims.put("id", user.getId());
- claims.put("username", user.getUsername());
- String token = JwtUtils.generateJwt(claims);
- // 存储在redis中
- ValueOperations<String, String> operations = stringRedisTemplate.opsForValue();
- operations.set(token, token,2, TimeUnit.HOURS); // 2小时
- return Result.success(token);
- }
- return Result.error("密码错误");
- }
-
- /**
- * 获取用户信息
- */
- @GetMapping("/userInfo")
- public Result<User> userInfo(/*@RequestHeader(name = "Authorization") String token*/) {
- //根据用户名查询用户
- /* Map<String, Object> map = JwtUtils.parseJWT(token);
- String username = (String) map.get("username");*/
- Map<String, Object> map = ThreadLocalUtil.get();
- String username = (String) map.get("username");
- User user = userService.findByUsername(username);
- return Result.success(user);
- }
-
- /**
- * 修改用户信息
- */
- @PutMapping("/update")
- public Result update(@RequestBody @Validated User user) {
- userService.update(user);
- return Result.success();
- }
- /**
- * 修改用户头像
- */
- @PatchMapping("/updateAvatar")
- public Result updateAvatar(@RequestParam @URL String avatarUrl) {
- userService.updateAvatar(avatarUrl);
- return Result.success();
- }
- /**
- * 修改密码
- */
- @PatchMapping("/updatePwd")
- public Result updatePwd(@RequestBody Map<String, String> params,@RequestHeader(name = "Authorization") String token) {
- log.info("param信息{}", params);
- //1.校验参数
- 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("缺少必要的参数");
- }
-
- //原密码是否正确
- //调用userService根据用户名拿到原密码,再和old_pwd比对
- 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("原密码填写不正确");
- }
-
- //newPwd和rePwd是否一样
- if (!rePwd.equals(newPwd)){
- return Result.error("两次填写的新密码不一样");
- }
-
- //2.调用service完成密码更新
- userService.updatePwd(newPwd);
- //删除redis中对应的token
- ValueOperations<String, String> operations = stringRedisTemplate.opsForValue();
- operations.getOperations().delete(token);
- return Result.success();
- }
- }
复制代码 4,拦截器里面使用情况:
- package com.jinhei.interceptors;
- import com.jinhei.utils.JwtUtils;
- import com.jinhei.utils.ThreadLocalUtil;
- 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 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");
- // 验证token
- try {
- //从redis中获取相同的token
- ValueOperations<String, String> operations = stringRedisTemplate.opsForValue();
- String redisToken = operations.get(token);
- if (redisToken==null){
- //token已经失效了
- throw new RuntimeException(); // 抛出异常,给catch抓捕处理
- }
- Map<String, Object> claims = JwtUtils.parseJWT(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();
- }
- }
复制代码
|