diff --git a/blog/src/main/java/liuyuyang/net/interceptor/JwtTokenAdminInterceptor.java b/blog/src/main/java/liuyuyang/net/interceptor/JwtTokenAdminInterceptor.java index 1c043f5..f8be382 100644 --- a/blog/src/main/java/liuyuyang/net/interceptor/JwtTokenAdminInterceptor.java +++ b/blog/src/main/java/liuyuyang/net/interceptor/JwtTokenAdminInterceptor.java @@ -1,19 +1,24 @@ package liuyuyang.net.interceptor; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import io.jsonwebtoken.Claims; import liuyuyang.net.annotation.NoTokenRequired; import liuyuyang.net.execption.CustomException; +import liuyuyang.net.mapper.UserTokenMapper; +import liuyuyang.net.model.UserToken; import liuyuyang.net.properties.JwtProperties; import liuyuyang.net.utils.JwtUtils; import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; +import org.jetbrains.annotations.NotNull; import org.springframework.stereotype.Component; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.HandlerInterceptor; +import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.lang.reflect.Method; +import java.util.List; /** * jwt令牌校验的拦截器 @@ -21,20 +26,12 @@ @Component @Slf4j public class JwtTokenAdminInterceptor implements HandlerInterceptor { - - @Autowired + @Resource private JwtProperties jwtProperties; + @Resource + private UserTokenMapper userTokenMapper; - /** - * 校验jwt - * - * @param request - * @param response - * @param handler - * @return - * @throws Exception - */ - public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { + public boolean preHandle(HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull Object handler) { // 从请求头中获取令牌 String token = request.getHeader(jwtProperties.getTokenName()); @@ -61,23 +58,30 @@ public boolean preHandle(HttpServletRequest request, HttpServletResponse respons if (token != null) { if (token.startsWith("Bearer ")) token = token.substring(7); JwtUtils.parseJWT(jwtProperties.getSecretKey(), token); - return true; - } else { - return true; } + return true; } // 处理Authorization的Bearer if (token.startsWith("Bearer ")) token = token.substring(7); - Claims claims = JwtUtils.parseJWT(jwtProperties.getSecretKey(), token); - // 放行 - return true; + LambdaQueryWrapper userTokenLambdaQueryWrapper = new LambdaQueryWrapper<>(); + userTokenLambdaQueryWrapper.eq(UserToken::getToken, token); + List userTokens = userTokenMapper.selectList(userTokenLambdaQueryWrapper); + + // 如果跟之前的token相匹配则进一步判断token是否有效 + if (userTokens != null && !userTokens.isEmpty()) { + Claims claims = JwtUtils.parseJWT(jwtProperties.getSecretKey(), token); + return true; + } else { + throw new CustomException(401, "该账号已在另一台设备登录"); + } } catch (Exception ex) { System.out.println("校验失败:" + ex); // 校验失败,响应401状态码 response.setStatus(401); - throw new CustomException(401, "身份验证失败:无效或过期的token"); + String message = ex.getMessage() != null ? ex.getMessage() : "无效或过期的token"; + throw new CustomException(401, message); } } } diff --git a/blog/src/main/java/liuyuyang/net/mapper/UserTokenMapper.java b/blog/src/main/java/liuyuyang/net/mapper/UserTokenMapper.java new file mode 100644 index 0000000..5f07d03 --- /dev/null +++ b/blog/src/main/java/liuyuyang/net/mapper/UserTokenMapper.java @@ -0,0 +1,10 @@ +package liuyuyang.net.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import liuyuyang.net.model.UserToken; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface UserTokenMapper extends BaseMapper { + +} diff --git a/blog/src/main/java/liuyuyang/net/service/impl/UserServiceImpl.java b/blog/src/main/java/liuyuyang/net/service/impl/UserServiceImpl.java index fd9832f..becfc1d 100644 --- a/blog/src/main/java/liuyuyang/net/service/impl/UserServiceImpl.java +++ b/blog/src/main/java/liuyuyang/net/service/impl/UserServiceImpl.java @@ -1,5 +1,6 @@ package liuyuyang.net.service.impl; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; @@ -10,6 +11,7 @@ import liuyuyang.net.execption.CustomException; import liuyuyang.net.mapper.RoleMapper; import liuyuyang.net.mapper.UserMapper; +import liuyuyang.net.mapper.UserTokenMapper; import liuyuyang.net.model.*; import liuyuyang.net.properties.JwtProperties; import liuyuyang.net.service.UserService; @@ -43,6 +45,8 @@ public class UserServiceImpl extends ServiceImpl implements Us private UserMapper userMapper; @Resource private RoleMapper roleMapper; + @Resource + private UserTokenMapper userTokenMapper; @Override public void add(UserDTO user) { @@ -122,28 +126,32 @@ public Page paging(UserFilterVo filterVo, PageVo pageVo) { } @Override - public Map login(UserLoginDTO user) { + public Map login(UserLoginDTO userDTO) { QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.eq("username", user.getUsername()); - queryWrapper.eq("password", DigestUtils.md5DigestAsHex(user.getPassword().getBytes())); - - User data = userMapper.selectOne(queryWrapper); - - if (data == null) throw new CustomException(400, "用户名或密码错误"); - - data.setPassword("只有聪明的人才能看到密码"); + queryWrapper.eq("username", userDTO.getUsername()); + queryWrapper.eq("password", DigestUtils.md5DigestAsHex(userDTO.getPassword().getBytes())); - Role role = roleMapper.selectById(data.getRoleId()); + User user = userMapper.selectOne(queryWrapper); + if (user == null) throw new CustomException(400, "用户名或密码错误"); + user.setPassword("只有聪明的人才能看到密码"); - Map claims = new HashMap<>(); - claims.put("user", data); - claims.put("role", role); - String token = JwtUtils.createJWT(jwtProperties.getSecretKey(), jwtProperties.getTtl(), claims); + Role role = roleMapper.selectById(user.getRoleId()); Map result = new HashMap<>(); - result.put("token", token); - result.put("user", data); + result.put("user", user); result.put("role", role); + String token = JwtUtils.createJWT(jwtProperties.getSecretKey(), jwtProperties.getTtl(), result); + result.put("token", token); + + // 先删除用户的token + LambdaQueryWrapper userLambdaQueryWrapper = new LambdaQueryWrapper<>(); + userLambdaQueryWrapper.eq(UserToken::getUid,user.getId()); + userTokenMapper.delete(userLambdaQueryWrapper); + // 再存储用户的token + UserToken userToken = new UserToken(); + userToken.setUid(user.getId()); + userToken.setToken(token); + userTokenMapper.insert(userToken); return result; } @@ -166,7 +174,6 @@ public void editPass(EditPassDTO data) { @Override public void check(String token) { - // boolean isCheck = yuYangUtils.isAdmin(token); boolean isCheck = yuYangUtils.check(token); if (!isCheck) { diff --git a/model/src/main/java/liuyuyang/net/model/UserToken.java b/model/src/main/java/liuyuyang/net/model/UserToken.java new file mode 100644 index 0000000..c066213 --- /dev/null +++ b/model/src/main/java/liuyuyang/net/model/UserToken.java @@ -0,0 +1,21 @@ +package liuyuyang.net.model; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +@Data +@TableName("user_token") +public class UserToken { + @TableId(type = IdType.AUTO) + @ApiModelProperty(value = "ID") + private Integer id; + + @ApiModelProperty(value = "用户ID", example = "1", required = true) + private Integer uid; + + @ApiModelProperty(value = "用户token", example = "dadaffasfefewfwf.wefwfwfwwzfwe.zfwfwefZFfw", required = true) + private String token; +}