2 Commits

Author SHA1 Message Date
KilLze
60df001385 用户退出功能实现
用户退出将Redis的token自动添加到黑名单
2026-01-02 12:46:44 +08:00
KilLze
27c64b1106 优化喵 2026-01-02 11:56:21 +08:00
9 changed files with 61 additions and 10 deletions

View File

@@ -4,7 +4,6 @@ import com.bao.dating.common.Result;
import com.bao.dating.common.ResultCode; import com.bao.dating.common.ResultCode;
import com.bao.dating.pojo.entity.User; import com.bao.dating.pojo.entity.User;
import com.bao.dating.service.PostFavoriteService; import com.bao.dating.service.PostFavoriteService;
import com.bao.dating.service.PostService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;

View File

@@ -2,13 +2,11 @@ package com.bao.dating.controller;
import com.bao.dating.common.Result; import com.bao.dating.common.Result;
import com.bao.dating.common.ResultCode; import com.bao.dating.common.ResultCode;
import com.bao.dating.mapper.PostLikeMapper;
import com.bao.dating.service.PostLikeService; import com.bao.dating.service.PostLikeService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.util.Map; import java.util.Map;
import java.util.Objects;
@RestController @RestController
@RequestMapping("/posts") @RequestMapping("/posts")

View File

@@ -9,10 +9,13 @@ import com.bao.dating.pojo.dto.UserLoginDTO;
import com.bao.dating.pojo.vo.UserInfoVO; import com.bao.dating.pojo.vo.UserInfoVO;
import com.bao.dating.pojo.vo.UserLoginVO; import com.bao.dating.pojo.vo.UserLoginVO;
import com.bao.dating.service.UserService; import com.bao.dating.service.UserService;
import io.jsonwebtoken.Jwt;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
/** /**
* 用户接口 * 用户接口
* *
@@ -35,6 +38,17 @@ public class UserController {
return Result.success(ResultCode.SUCCESS, "登录成功", userloginVO); return Result.success(ResultCode.SUCCESS, "登录成功", userloginVO);
} }
/**
* 退出登录
* 从请求头中获取token并将其加入黑名单
*/
@PostMapping("/logout")
public Result<Void> logout(HttpServletRequest request) {
String token = request.getHeader("token");
userService.logout(token);
return Result.success(ResultCode.SUCCESS,"退出登录成功",null);
}
/** /**
* 获取用户信息 * 获取用户信息
* @return 用户信息 * @return 用户信息

View File

@@ -14,7 +14,6 @@ import org.springframework.web.method.annotation.MethodArgumentTypeMismatchExcep
import org.springframework.web.servlet.NoHandlerFoundException; import org.springframework.web.servlet.NoHandlerFoundException;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**

View File

@@ -57,6 +57,16 @@ public class TokenInterceptor implements HandlerInterceptor {
return false; return false;
} }
// 检查 token 是否在黑名单中
Object blacklistToken = redisTemplate.opsForValue().get("jwt:blacklist:" + token);
if (blacklistToken != null) {
log.error("Token已在黑名单中");
response.setStatus(401);
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write("登录已失效, 请重新登录");
return false;
}
// 解析 token // 解析 token
String userId = JwtUtil.getSubjectFromToken(token); String userId = JwtUtil.getSubjectFromToken(token);

View File

@@ -2,6 +2,7 @@ package com.bao.dating.pojo.dto;
import lombok.Data; import lombok.Data;
import java.io.Serializable;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List; import java.util.List;
@@ -11,7 +12,7 @@ import java.util.List;
* @author KilLze * @author KilLze
*/ */
@Data @Data
public class UserInfoUpdateDTO { public class UserInfoUpdateDTO implements Serializable {
private Long userId; private Long userId;
private String userName; private String userName;
private String nickname; private String nickname;

View File

@@ -1,6 +1,8 @@
package com.bao.dating.pojo.entity; package com.bao.dating.pojo.entity;
import lombok.Data; import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime; import java.time.LocalDateTime;
/** /**
@@ -8,7 +10,7 @@ import java.time.LocalDateTime;
* @author KilLze * @author KilLze
*/ */
@Data @Data
public class OperateLog { public class OperateLog implements Serializable {
/** ID */ /** ID */
private Long id; private Long id;
/** 操作人ID */ /** 操作人ID */

View File

@@ -18,6 +18,13 @@ public interface UserService {
*/ */
UserLoginVO userLogin(UserLoginDTO userLoginDTO); UserLoginVO userLogin(UserLoginDTO userLoginDTO);
/**
* 退出登录
* @param token 登录凭证
* @return 注册结果
*/
void logout(String token);
/** /**
* 查询个人信息 * 查询个人信息
* @param userId 动态ID * @param userId 动态ID

View File

@@ -17,6 +17,7 @@ import com.bao.dating.service.UserService;
import com.bao.dating.util.FileUtil; import com.bao.dating.util.FileUtil;
import com.bao.dating.util.JwtUtil; import com.bao.dating.util.JwtUtil;
import com.bao.dating.util.MD5Util; import com.bao.dating.util.MD5Util;
import io.jsonwebtoken.Claims;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.RedisTemplate;
@@ -25,10 +26,7 @@ import org.springframework.web.multipart.MultipartFile;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.ArrayList; import java.util.*;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
/** /**
@@ -99,6 +97,29 @@ public class UserServiceImpl implements UserService {
return userLoginVO; return userLoginVO;
} }
/**
* 退出登录
* @param token 登录凭证
*/
@Override
public void logout(String token) {
Claims claims = JwtUtil.getClaimsFromToken(token);
Date expiration = claims.getExpiration();
// 判断 token 是否已过期
long ttl = expiration.getTime() - System.currentTimeMillis();
// 如果 token 已过期,则不用处理
if (ttl <= 0) {
return;
}
String logoutKey = "jwt:blacklist:" + token;
redisTemplate.opsForValue().set(
logoutKey,
"logout",
ttl,
TimeUnit.MILLISECONDS);
}
/** /**
* 获取用户信息 * 获取用户信息
* *