feat(user): 实现用户登录和身份验证功能

- 新增用户登录接口和相关逻辑
- 实现 token 生成和验证功能- 添加用户信息查询接口
- 集成拦截器进行身份验证
- 优化错误处理和提示信息
This commit is contained in:
LingandRX 2025-03-25 00:52:52 +08:00
parent 89bbb45c52
commit f7a4995c58
7 changed files with 148 additions and 4 deletions

View File

@ -0,0 +1,27 @@
package com.example.copykamanotes.config;
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;
import com.example.copykamanotes.interceptor.TokenInterceptor;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private TokenInterceptor tokenInterceptor;
/**
* 添加拦截器, 拦截所有请求除了登录和注册
* @param registry 拦截器注册器
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(tokenInterceptor)
.addPathPatterns("/api/**")
.excludePathPatterns("/api/users/login", "/api/users/register");
}
}

View File

@ -1,7 +1,9 @@
package com.example.copykamanotes.controller; package com.example.copykamanotes.controller;
import com.example.copykamanotes.model.base.ApiResponse; import com.example.copykamanotes.model.base.ApiResponse;
import com.example.copykamanotes.model.dto.user.LoginRequest;
import com.example.copykamanotes.model.dto.user.RegisterRequest; import com.example.copykamanotes.model.dto.user.RegisterRequest;
import com.example.copykamanotes.model.vo.user.LoginUserVO;
import com.example.copykamanotes.model.vo.user.RegisterVO; import com.example.copykamanotes.model.vo.user.RegisterVO;
import com.example.copykamanotes.service.UserService; import com.example.copykamanotes.service.UserService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -31,4 +33,18 @@ public class UserController {
public ApiResponse<String> hello() { public ApiResponse<String> hello() {
return ApiResponse.success("Hello World"); return ApiResponse.success("Hello World");
} }
@PostMapping("/users/login")
public ApiResponse<LoginUserVO> login(
@Valid
@RequestBody
LoginRequest loginRequest
) {
return userService.login(loginRequest);
}
@PostMapping("/users/whoami")
public ApiResponse<LoginUserVO> whoami() {
return userService.whoami();
}
} }

View File

@ -0,0 +1,44 @@
package com.example.copykamanotes.interceptor;
import com.example.copykamanotes.scope.RequestScopeData;
import com.example.copykamanotes.utils.JwtUtil;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
@Component
public class TokenInterceptor implements HandlerInterceptor {
@Autowired
private RequestScopeData requestScopeData;
@Autowired
private JwtUtil jwtUtil;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String token = request.getHeader("Authorization");
if (token == null) {
requestScopeData.setLogin(false);
requestScopeData.setUserId(null);
requestScopeData.setUserId(null);
return true;
}
token = token.replace("Bearer ", "");
if (!jwtUtil.validateToken(token)) {
Long userId = jwtUtil.getUserIdFromToken(token);
requestScopeData.setUserId(userId);
requestScopeData.setToken(token);
requestScopeData.setLogin(true);
} else {
requestScopeData.setLogin(false);
}
return HandlerInterceptor.super.preHandle(request, response, handler);
}
}

View File

@ -18,4 +18,6 @@ public interface UserMapper {
User findByEmail(@Param("email") String email); User findByEmail(@Param("email") String email);
int updateLastLoginAt(@Param("userId") Long userId); int updateLastLoginAt(@Param("userId") Long userId);
User findById(@Param("userId") Long userId);
} }

View File

@ -15,6 +15,7 @@ import com.example.copykamanotes.service.EmailService;
import com.example.copykamanotes.service.UserService; import com.example.copykamanotes.service.UserService;
import com.example.copykamanotes.utils.ApiResponseUtil; import com.example.copykamanotes.utils.ApiResponseUtil;
import com.example.copykamanotes.utils.JwtUtil; import com.example.copykamanotes.utils.JwtUtil;
import com.google.protobuf.Api;
import lombok.extern.log4j.Log4j2; import lombok.extern.log4j.Log4j2;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -86,18 +87,66 @@ public class UserServiceImpl implements UserService {
return ApiResponseUtil.success("注册成功", registerVO, token); return ApiResponseUtil.success("注册成功", registerVO, token);
} catch (Exception e) { } catch (Exception e) {
log.error("注册失败", e); log.error("注册失败", e);
return ApiResponseUtil.error("注册失败"); return ApiResponseUtil.error("注册失败,请稍后再试");
} }
} }
@Override @Override
public ApiResponse<LoginUserVO> login(LoginRequest loginRequest) { public ApiResponse<LoginUserVO> login(LoginRequest loginRequest) {
return null; User user = null;
if (loginRequest.getAccount() != null && !loginRequest.getAccount().isEmpty()) {
user = userMapper.findByAccount(loginRequest.getAccount());
} else if (loginRequest.getEmail() != null && !loginRequest.getEmail().isEmpty()) {
user = userMapper.findByEmail(loginRequest.getEmail());
} else {
return ApiResponseUtil.error("账号或邮箱不能为空");
}
if (user == null) {
return ApiResponseUtil.error("账号或邮箱不存在");
}
if (!passwordEncoder.matches(loginRequest.getPassword(), user.getPassword())) {
return ApiResponseUtil.error("密码错误");
}
String token = jwtUtil.generateToken(user.getUserId());
LoginUserVO loginUserVO = new LoginUserVO();
BeanUtils.copyProperties(user, loginUserVO);
userMapper.updateLastLoginAt(user.getUserId());
return ApiResponseUtil.success("登录成功", loginUserVO, token);
} }
@Override @Override
public ApiResponse<LoginUserVO> whoami() { public ApiResponse<LoginUserVO> whoami() {
return null; Long userId = requestScopeData.getUserId();
if (userId == null) {
return ApiResponseUtil.error("未登录");
}
try {
User user = userMapper.findById(userId);
if (user == null) {
return ApiResponseUtil.error("用户不存在");
}
String newToken = jwtUtil.generateToken(userId);
if (newToken == null) {
return ApiResponseUtil.error("token生成失败");
}
LoginUserVO loginUserVO = new LoginUserVO();
BeanUtils.copyProperties(user, loginUserVO);
return ApiResponseUtil.success("获取用户信息成功", loginUserVO, newToken);
} catch (Exception e) {
log.error("获取用户信息失败", e);
return ApiResponseUtil.error("获取用户信息失败");
}
} }
@Override @Override

View File

@ -45,7 +45,7 @@ public class JwtUtil {
public Long getUserIdFromToken(String token) { public Long getUserIdFromToken(String token) {
try { try {
Claims claims = Jwts.parser() Claims claims = Jwts.parser()
.setSigningKey(secret) .setSigningKey(SECRET_KEY)
.parseClaimsJws(token) .parseClaimsJws(token)
.getBody(); .getBody();
return Long.valueOf(claims.get("userId").toString()); return Long.valueOf(claims.get("userId").toString());

View File

@ -31,6 +31,12 @@
NOW()) NOW())
</insert> </insert>
<select id="findById" resultType="com.example.copykamanotes.model.entity.User">
select *
from user
where user_id = #{userId}
</select>
<select id="findByEmail" resultType="com.example.copykamanotes.model.entity.User"> <select id="findByEmail" resultType="com.example.copykamanotes.model.entity.User">
SELECT * SELECT *
FROM user FROM user