feat(user): 实现用户登录和身份验证功能
- 新增用户登录接口和相关逻辑 - 实现 token 生成和验证功能- 添加用户信息查询接口 - 集成拦截器进行身份验证 - 优化错误处理和提示信息
This commit is contained in:
parent
89bbb45c52
commit
f7a4995c58
@ -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");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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());
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user