From 155c336835b64be5b5b6c9fa8fd4ca1390420f8b Mon Sep 17 00:00:00 2001 From: 2991692032 Date: Mon, 24 Mar 2025 23:57:34 +0800 Subject: [PATCH] =?UTF-8?q?jwt=E5=AE=9E=E7=8E=B0token?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- unilife-server/pom.xml | 7 ++- .../java/com/unilife/config/WebMvcConfig.java | 29 ++++++++++ .../unilife/controller/UserController.java | 33 ++++++++++-- .../unilife/interceptor/JwtInterceptor.java | 54 +++++++++++++++++++ .../java/com/unilife/model/dto/LoginDTO.java | 11 ++-- .../com/unilife/model/dto/RegisterDTO.java | 19 +++++++ .../main/java/com/unilife/model/vo/LogVO.java | 27 ---------- .../java/com/unilife/model/vo/LoginVO.java | 18 ++++--- .../{dto/LogDTO.java => vo/RegisterVO.java} | 13 ++--- .../java/com/unilife/service/UserService.java | 8 ++- .../unilife/service/impl/UserServiceImpl.java | 37 ++++++------- .../java/com/unilife/utils/BaseContext.java | 19 +++++++ .../main/java/com/unilife/utils/JwtUtil.java | 45 ++++++++++++++++ .../src/main/resources/application.yml | 7 ++- 14 files changed, 249 insertions(+), 78 deletions(-) create mode 100644 unilife-server/src/main/java/com/unilife/config/WebMvcConfig.java create mode 100644 unilife-server/src/main/java/com/unilife/interceptor/JwtInterceptor.java create mode 100644 unilife-server/src/main/java/com/unilife/model/dto/RegisterDTO.java delete mode 100644 unilife-server/src/main/java/com/unilife/model/vo/LogVO.java rename unilife-server/src/main/java/com/unilife/model/{dto/LogDTO.java => vo/RegisterVO.java} (50%) create mode 100644 unilife-server/src/main/java/com/unilife/utils/BaseContext.java create mode 100644 unilife-server/src/main/java/com/unilife/utils/JwtUtil.java diff --git a/unilife-server/pom.xml b/unilife-server/pom.xml index 254efa2..b970ace 100644 --- a/unilife-server/pom.xml +++ b/unilife-server/pom.xml @@ -49,7 +49,12 @@ hutool-all 5.8.16 - + + + io.jsonwebtoken + jjwt + 0.9.1 + org.springframework.boot diff --git a/unilife-server/src/main/java/com/unilife/config/WebMvcConfig.java b/unilife-server/src/main/java/com/unilife/config/WebMvcConfig.java new file mode 100644 index 0000000..a4d0d0b --- /dev/null +++ b/unilife-server/src/main/java/com/unilife/config/WebMvcConfig.java @@ -0,0 +1,29 @@ +package com.unilife.config; + +import com.unilife.interceptor.JwtInterceptor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@Configuration +public class WebMvcConfig implements WebMvcConfigurer { + @Autowired + private JwtInterceptor jwtInterceptor; + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(jwtInterceptor).addPathPatterns("/**") + .excludePathPatterns( + "/users/login", + "/users/register", + "/users/code", + "/users/login/code", + "/swagger-resources/**", + "/v2/api-docs/**", + "/doc.html", + "/webjars/**" + ); + } + +} diff --git a/unilife-server/src/main/java/com/unilife/controller/UserController.java b/unilife-server/src/main/java/com/unilife/controller/UserController.java index 0a28a1e..61ecf94 100644 --- a/unilife-server/src/main/java/com/unilife/controller/UserController.java +++ b/unilife-server/src/main/java/com/unilife/controller/UserController.java @@ -2,19 +2,26 @@ package com.unilife.controller; import com.unilife.common.result.Result; import com.unilife.model.dto.EmailDTO; -import com.unilife.model.dto.LogDTO; import com.unilife.model.dto.LoginDTO; import com.unilife.model.dto.LoginEmailDTO; +import com.unilife.model.dto.RegisterDTO; +import com.unilife.model.vo.LoginVO; +import com.unilife.model.vo.RegisterVO; import com.unilife.service.UserService; +import com.unilife.utils.BaseContext; +import com.unilife.utils.JwtUtil; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import java.time.Duration; + @Api(tags = "用户管理") @RestController @@ -24,16 +31,34 @@ public class UserController { @Autowired private UserService userService; + @Autowired + private JwtUtil jwtUtil; + @Autowired + private StringRedisTemplate stringRedisTemplate; @ApiOperation(value = "用户注册") @PostMapping("register") - public Result register(@RequestBody LoginDTO loginDTO) { - return userService.register(loginDTO); + public Result register(@RequestBody RegisterDTO registerDTO) { + return userService.register(registerDTO); } @ApiOperation(value = "用户登录") @PostMapping("login") - public Result login(@RequestBody LogDTO logDTO) { return userService.login(logDTO); } + public Result login(@RequestBody LoginDTO loginDTO) { + Result login = userService.login(loginDTO); + //登陆成功后生成jwt令牌 + LoginVO vo=(LoginVO) login.getData(); + if (vo == null) { + return login; + } + Long id = vo.getId(); + String token = jwtUtil.generateToken(id); + vo.setToken(token); + + //Threadlocal保存当前用户id + BaseContext.setId(id); + return Result.success(vo); + } @ApiOperation(value = "获取邮箱验证码") @PostMapping("code") diff --git a/unilife-server/src/main/java/com/unilife/interceptor/JwtInterceptor.java b/unilife-server/src/main/java/com/unilife/interceptor/JwtInterceptor.java new file mode 100644 index 0000000..33bcea9 --- /dev/null +++ b/unilife-server/src/main/java/com/unilife/interceptor/JwtInterceptor.java @@ -0,0 +1,54 @@ +package com.unilife.interceptor; + +import cn.hutool.core.util.StrUtil; +import com.unilife.utils.BaseContext; +import com.unilife.utils.JwtUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Component; +import org.springframework.web.servlet.HandlerInterceptor; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +@Component +@Slf4j +public class JwtInterceptor implements HandlerInterceptor { + @Autowired + private JwtUtil jwtUtil; + + @Autowired + private StringRedisTemplate stringRedisTemplate; + + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + + log.info("JwtInterceptor preHandle"); + String token = request.getHeader("Authorization"); + + if(StrUtil.isBlank(token)){ + response.setStatus(401); + return false; + } + + boolean verified = jwtUtil.verifyToken(token); + if (!verified) { + response.setStatus(401); + return false; + } + + //从token中获取userid并存入threadlocal + Long userId = jwtUtil.getUserIdFromToken(token); + BaseContext.setId(userId); + + + return true; + } + + @Override + public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { + BaseContext.removeId(); + } +} diff --git a/unilife-server/src/main/java/com/unilife/model/dto/LoginDTO.java b/unilife-server/src/main/java/com/unilife/model/dto/LoginDTO.java index 7643b0b..57755af 100644 --- a/unilife-server/src/main/java/com/unilife/model/dto/LoginDTO.java +++ b/unilife-server/src/main/java/com/unilife/model/dto/LoginDTO.java @@ -1,19 +1,14 @@ package com.unilife.model.dto; -//这个是注册的DTO +//这个才是登录的DTO + import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data -@AllArgsConstructor @NoArgsConstructor +@AllArgsConstructor public class LoginDTO { - private String username; private String email; private String password; - private String nickname; - private String studentId; - private String department; - private String major; - private String grade; } diff --git a/unilife-server/src/main/java/com/unilife/model/dto/RegisterDTO.java b/unilife-server/src/main/java/com/unilife/model/dto/RegisterDTO.java new file mode 100644 index 0000000..dc85e7a --- /dev/null +++ b/unilife-server/src/main/java/com/unilife/model/dto/RegisterDTO.java @@ -0,0 +1,19 @@ +package com.unilife.model.dto; +//这个是注册的DTO +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class RegisterDTO { + private String username; + private String email; + private String password; + private String nickname; + private String studentId; + private String department; + private String major; + private String grade; +} diff --git a/unilife-server/src/main/java/com/unilife/model/vo/LogVO.java b/unilife-server/src/main/java/com/unilife/model/vo/LogVO.java deleted file mode 100644 index 38d0da7..0000000 --- a/unilife-server/src/main/java/com/unilife/model/vo/LogVO.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.unilife.model.vo; - -import com.unilife.model.entity.User; -import lombok.Data; - -@Data -public class LogVO { - private Integer id; - private String username; - private String nickname; - private String avatar; - private Byte role; - private Byte isVerified; - private Byte status; - - public LogVO(Integer id,String username,String nickname,String avatar,Byte role,Byte isVerified,Byte status) - { - this.id = id; - this.username = username; - this.nickname = nickname; - this.avatar = avatar; - this.role = role; - this.isVerified = isVerified; - } - -} - diff --git a/unilife-server/src/main/java/com/unilife/model/vo/LoginVO.java b/unilife-server/src/main/java/com/unilife/model/vo/LoginVO.java index 4f87b54..e2d0470 100644 --- a/unilife-server/src/main/java/com/unilife/model/vo/LoginVO.java +++ b/unilife-server/src/main/java/com/unilife/model/vo/LoginVO.java @@ -1,17 +1,21 @@ package com.unilife.model.vo; +import lombok.AllArgsConstructor; import lombok.Data; +import lombok.NoArgsConstructor; @Data +@AllArgsConstructor +@NoArgsConstructor public class LoginVO { - private Integer id; + private Long id; private String username; private String nickname; + private String avatar; + private Byte role; + private Byte isVerified; + private Byte status; + private String token; - public LoginVO(Integer id, String username, String nickname) - { - this.id = id; - this.username = username; - this.nickname = nickname; - } } + diff --git a/unilife-server/src/main/java/com/unilife/model/dto/LogDTO.java b/unilife-server/src/main/java/com/unilife/model/vo/RegisterVO.java similarity index 50% rename from unilife-server/src/main/java/com/unilife/model/dto/LogDTO.java rename to unilife-server/src/main/java/com/unilife/model/vo/RegisterVO.java index 68e2c5a..2ea5a26 100644 --- a/unilife-server/src/main/java/com/unilife/model/dto/LogDTO.java +++ b/unilife-server/src/main/java/com/unilife/model/vo/RegisterVO.java @@ -1,14 +1,15 @@ -package com.unilife.model.dto; -//这个才是登录的DTO +package com.unilife.model.vo; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data -@NoArgsConstructor @AllArgsConstructor -public class LogDTO { - private String email; - private String password; +@NoArgsConstructor +public class RegisterVO { + private Long id; + private String username; + private String nickname; + } diff --git a/unilife-server/src/main/java/com/unilife/service/UserService.java b/unilife-server/src/main/java/com/unilife/service/UserService.java index fece724..5cc3fc4 100644 --- a/unilife-server/src/main/java/com/unilife/service/UserService.java +++ b/unilife-server/src/main/java/com/unilife/service/UserService.java @@ -1,18 +1,16 @@ package com.unilife.service; import com.unilife.common.result.Result; -import com.unilife.model.dto.LogDTO; import com.unilife.model.dto.LoginDTO; import com.unilife.model.dto.LoginEmailDTO; +import com.unilife.model.dto.RegisterDTO; public interface UserService { - Result register(LoginDTO loginDTO); - Result login(LogDTO logDTO); + Result register(RegisterDTO registerDTO); + Result login(LoginDTO loginDTO); Result sendVerificationCode(String email); Result loginWithEmail(LoginEmailDTO loginEmailDTO); - - } diff --git a/unilife-server/src/main/java/com/unilife/service/impl/UserServiceImpl.java b/unilife-server/src/main/java/com/unilife/service/impl/UserServiceImpl.java index 29ca4ad..9b0cd6f 100644 --- a/unilife-server/src/main/java/com/unilife/service/impl/UserServiceImpl.java +++ b/unilife-server/src/main/java/com/unilife/service/impl/UserServiceImpl.java @@ -2,17 +2,17 @@ package com.unilife.service.impl; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.util.RandomUtil; -import cn.hutool.core.util.StrUtil; import com.unilife.common.constant.RedisConstant; import com.unilife.common.result.Result; import com.unilife.mapper.UserMapper; -import com.unilife.model.dto.LogDTO; import com.unilife.model.dto.LoginDTO; import com.unilife.model.dto.LoginEmailDTO; +import com.unilife.model.dto.RegisterDTO; import com.unilife.model.entity.User; -import com.unilife.model.vo.LogVO; import com.unilife.model.vo.LoginVO; +import com.unilife.model.vo.RegisterVO; import com.unilife.service.UserService; +import com.unilife.utils.JwtUtil; import com.unilife.utils.RegexUtils; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; @@ -27,7 +27,6 @@ import javax.mail.MessagingException; import javax.mail.internet.MimeMessage; import java.time.Duration; -import java.time.LocalDateTime; import java.util.HashMap; import java.util.Map; @@ -52,37 +51,38 @@ public class UserServiceImpl implements UserService { final int CODE_EXPIRE_MINUTES = 10; final int LIMIT_SECONDS=60; - + @Autowired + private JwtUtil jwtUtil; @Override - public Result register(LoginDTO loginDTO) { - if(loginDTO.getEmail().equals("") || loginDTO.getPassword().equals("")) { + public Result register(RegisterDTO registerDTO) { + if(registerDTO.getEmail().isEmpty() || registerDTO.getPassword().isEmpty()) { return Result.error(400,"邮箱或密码不能为空"); } User user = new User(); - BeanUtil.copyProperties(loginDTO,user); + BeanUtil.copyProperties(registerDTO,user); userMapper.insert(user); - LoginVO loginVO = new LoginVO(Math.toIntExact(user.getId()),user.getUsername(),user.getNickname()); - return Result.success(loginVO); + RegisterVO registerVO = new RegisterVO(user.getId(),user.getUsername(),user.getNickname()); + return Result.success(registerVO); } @Override - public Result login(LogDTO logDTO) { + public Result login(LoginDTO loginDTO) { User user = new User(); - BeanUtil.copyProperties(logDTO,user);//将登录的前端传来的消息拷贝给这个user + BeanUtil.copyProperties(loginDTO,user);//将登录的前端传来的消息拷贝给这个user User getuser = userMapper.FindByEmail(user.getEmail(),user.getPassword()); if(getuser == null) { - return Result.error(logDTO,"用户不存在,登录失败!"); + return Result.error(loginDTO,"用户不存在,登录失败!"); } if(!user.getPassword().equals(getuser.getPassword())) { - return Result.error(logDTO,"密码错误,登录失败!"); + return Result.error(loginDTO,"密码错误,登录失败!"); } - LogVO logVO = new LogVO(Math.toIntExact(getuser.getId()), getuser.getUsername(), getuser.getNickname(), - getuser.getAvatar(), getuser.getRole(), getuser.getIsVerified(), getuser.getStatus()); - return Result.success(logVO); + LoginVO loginVO=new LoginVO(); + BeanUtil.copyProperties(getuser,loginVO); + return Result.success(loginVO); } @Override @@ -178,12 +178,13 @@ public class UserServiceImpl implements UserService { } //6.生成登录凭证 - //TODO + String token=jwtUtil.generateToken(user.getId()); // 8. 返回用户信息和登录凭证 Map userInfo = new HashMap<>(); //HashMap userInfo.put("token", token); userInfo.put("user", user); + userInfo.put("token", token); return Result.success(userInfo); } diff --git a/unilife-server/src/main/java/com/unilife/utils/BaseContext.java b/unilife-server/src/main/java/com/unilife/utils/BaseContext.java new file mode 100644 index 0000000..dbfed21 --- /dev/null +++ b/unilife-server/src/main/java/com/unilife/utils/BaseContext.java @@ -0,0 +1,19 @@ +package com.unilife.utils; + +public class BaseContext { + + public static ThreadLocal threadLocal = new ThreadLocal<>(); + + public static void setId(Long id) { + threadLocal.set(id); + } + + public static Long getId() { + return threadLocal.get(); + } + + public static void removeId() { + threadLocal.remove(); + } + +} diff --git a/unilife-server/src/main/java/com/unilife/utils/JwtUtil.java b/unilife-server/src/main/java/com/unilife/utils/JwtUtil.java new file mode 100644 index 0000000..6d3974d --- /dev/null +++ b/unilife-server/src/main/java/com/unilife/utils/JwtUtil.java @@ -0,0 +1,45 @@ +package com.unilife.utils; + +import cn.hutool.core.date.DateTime; +import cn.hutool.jwt.JWTUtil; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.Map; + +@Component +public class JwtUtil { + @Value("${jwt.secret}") + private String secret; + + @Value("${jwt.expiration}") + public long expiration; + + public String generateToken(Long id) { + DateTime now = DateTime.now(); + DateTime expireTime = new DateTime(now.getTime() + expiration * 1000); + + Map payload = new HashMap<>(); + payload.put("userId", id); + payload.put("created",now.getTime()); + return JWTUtil.createToken(payload,secret.getBytes()); + } + + public boolean verifyToken(String token) { + try{ + JWTUtil.verify(token,secret.getBytes()); + return true; + }catch (Exception e){ + return false; + } + } + public Long getUserIdFromToken(String token) { + try { + return (Long)JWTUtil.parseToken(token).getPayload("userId"); + }catch (Exception e){ + return null; + } + } + +} diff --git a/unilife-server/src/main/resources/application.yml b/unilife-server/src/main/resources/application.yml index 3986424..5d0dc2f 100644 --- a/unilife-server/src/main/resources/application.yml +++ b/unilife-server/src/main/resources/application.yml @@ -2,7 +2,7 @@ server: port: 8084 spring: datasource: - url: jdbc:mysql://localhost:3306/UniLife?useSSL=false&serverTimezone=UTC&characterEncoding=UTF-8 + url: jdbc:mysql://localhost:3306/UniLife?allowPublicKeyRetrieval=true&useSSL=false&serverTimezone=UTC&characterEncoding=UTF-8 username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver @@ -47,4 +47,7 @@ mybatis: map-underscore-to-camel-case: true logging: level: - com.unilife: debug \ No newline at end of file + com.unilife: debug +jwt: + secret: qwertyuiopasdfghjklzxcvbnm + expiration: 86400 \ No newline at end of file