用户登陆模块

This commit is contained in:
筱锋xiao_lfeng 2023-12-30 17:19:21 +08:00
parent cc96bfe7fc
commit dd329ec53b
No known key found for this signature in database
GPG Key ID: F693AA12AABBFA87
17 changed files with 384 additions and 13 deletions

View File

@ -0,0 +1,73 @@
package org.xlf.function.resourcesdocking.aspect;
import jakarta.servlet.http.HttpServletRequest;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.xlf.function.resourcesdocking.common.util.ErrorCode;
import org.xlf.function.resourcesdocking.common.util.ResultUtil;
import java.util.Objects;
/**
* <h1>TimestampAspect 时间戳切面</h1>
* <hr/>
* 用于处理时间戳相关逻辑
*
* @since v1.0.0
* @version v1.0.0
*/
@Aspect
@Component
public class TimestampAspect {
/**
* <h2>authControllerAround 认证控制器切面</h2>
* <hr/>
* 用于认证控制器的切面
*
* @param pjp ProceedingJoinPoint对象
* @return {@link Object}
*/
@Around("execution(* org.xlf.function.resourcesdocking.controllers.AuthController.*(..))")
public Object authControllerAround(ProceedingJoinPoint pjp) throws Throwable {
// 获取HttpServletRequest对象
HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
// 时间戳检查
if (checkTimestamp(request)) {
// TODO: 2023/12/30 0001 后期固定业务日志处理
return pjp.proceed();
} else {
return ResultUtil.error(ErrorCode.TIMESTAMP_IS_NOT_IN_TIME);
}
}
/**
* <h2>checkTimestamp 检查时间戳</h2>
* <hr/>
* 用于检查时间戳是否合法合法时间范围正负 1
*
* @param request HttpServletRequest对象
* @return {@link Boolean}
*/
public Boolean checkTimestamp(@NotNull HttpServletRequest request) {
// 获取请求头中的时间戳
String getTimestamp = request.getHeader("Timestamp");
// 判断是否为空
if (getTimestamp == null || getTimestamp.isEmpty()) {
return false;
} else {
if (getTimestamp.length() == 10) {
getTimestamp += "000";
}
}
// 获取当前时间戳
long nowTimestamp = System.currentTimeMillis();
// 时间误差允许前后五秒钟
return nowTimestamp - Long.parseLong(getTimestamp) <= 1000 && nowTimestamp - Long.parseLong(getTimestamp) >= -1000;
}
}

View File

@ -1,8 +1,10 @@
package org.xlf.function.resourcesdocking.common.util;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@Getter
@RequiredArgsConstructor
public enum ErrorCode {
/*
@ -11,19 +13,15 @@ public enum ErrorCode {
WRONG_PASSWORD("WrongPassword", 40000, "密码错误"),
USER_NOT_FOUND("UserNotFound", 40001, "用户不存在"),
USER_EXIST("UserExist", 40002, "用户已存在"),
USER_BAN("UserBan", 40003, "用户已被封禁"),
USER_VERIFY("UserVerify", 40004, "用户未通过验证"),
USER_NOT_LOGIN("UserNotLogin", 40005, "用户未登录"),
USER_NOT_PERMISSION("UserNotPermission", 40006, "用户无权限"),
USER_NOT_ACTIVE("UserNotActive", 40007, "用户未激活");
REQUEST_BODY_ERROR("RequestBodyError", 40003, "请求体错误"),
USER_VERIFY("UserVerify", 40100, "用户未通过验证"),
USER_BAN("UserBan", 40101, "用户已被封禁"),
USER_NOT_LOGIN("UserNotLogin", 40102, "用户未登录"),
USER_NOT_PERMISSION("UserNotPermission", 40103, "用户无权限"),
USER_NOT_ACTIVE("UserNotActive", 40104, "用户未激活"),
TIMESTAMP_IS_NOT_IN_TIME("TimestampIsNotInTime", 40300, "时间戳不在合法时间内");
private final String output;
private final Integer code;
private final String message;
ErrorCode(String output, Integer code, String message) {
this.output = output;
this.code = code;
this.message = message;
}
}

View File

@ -0,0 +1,33 @@
package org.xlf.function.resourcesdocking.common.util;
import org.jetbrains.annotations.NotNull;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import java.util.ArrayList;
/**
* <h1>Processing 处理工具类</h1>
* <hr/>
* 用于处理数据
*
* @version v1.0.0
* @since v1.0.0
*/
public class Processing {
/**
* <h2>getValidatedErrorList 获取验证错误信息列表</h2>
* <hr/>
* 用于获取验证错误信息列表
*
* @param bindingResult 错误信息
* @return {@link ArrayList<String>}
*/
public static @NotNull ArrayList<String> getValidatedErrorList(BindingResult bindingResult) {
ArrayList<String> arrayList = new ArrayList<>();
for (ObjectError objectError : bindingResult.getAllErrors()) {
arrayList.add(objectError.getDefaultMessage());
}
return arrayList;
}
}

View File

@ -76,6 +76,19 @@ public class ResultUtil {
return new BaseResponse(errorCode.getOutput(), errorCode.getCode(), errorCode.getMessage());
}
/**
* <h2>Error 错误响应结果</h2>
* <hr/>
* 用于封装错误响应结果
*
* @param errorCode 错误码
* @param data 响应数据
* @return BaseResponse
*/
public static @NotNull BaseResponse error(@NotNull ErrorCode errorCode, Object data) {
return new BaseResponse(errorCode.getOutput(), errorCode.getCode(), errorCode.getMessage(), data);
}
/**
* <h2>Error 错误响应结果</h2>
* <hr/>
@ -86,7 +99,7 @@ public class ResultUtil {
* @param message 响应信息
* @return BaseResponse
*/
public static @NotNull BaseResponse error(String output, Integer code, String message) {
return new BaseResponse(output, code, message);
public static @NotNull BaseResponse error(String output, Integer code, String message, Object data) {
return new BaseResponse(output, code, message, data);
}
}

View File

@ -0,0 +1,51 @@
package org.xlf.function.resourcesdocking.controllers;
import lombok.RequiredArgsConstructor;
import org.jetbrains.annotations.NotNull;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.xlf.function.resourcesdocking.common.util.BaseResponse;
import org.xlf.function.resourcesdocking.common.util.ErrorCode;
import org.xlf.function.resourcesdocking.common.util.Processing;
import org.xlf.function.resourcesdocking.common.util.ResultUtil;
import org.xlf.function.resourcesdocking.model.entity.AuthLoginEntity;
import org.xlf.function.resourcesdocking.services.AuthService;
/**
* <h1>AuthController 认证控制器</h1>
* <hr/>
* 用于处理认证相关请求
*
* @version v1.0.0
* @since v1.0.0
*/
@RestController
@RequestMapping("/user")
@RequiredArgsConstructor
public class AuthController {
/**
* 认证服务
*/
private final AuthService authService;
/**
* <h2>userSignIn 用户登录</h2>
* <hr/>
* 用于处理用户登录请求
*
* @return BaseResponse
*/
@GetMapping("/sign/in")
public BaseResponse userSignIn(@RequestBody @Validated AuthLoginEntity loginEntity, @NotNull BindingResult bindingResult) {
// 验证请求体
if (bindingResult.hasErrors()) {
return ResultUtil.error(ErrorCode.REQUEST_BODY_ERROR, Processing.getValidatedErrorList(bindingResult));
}
// 处理用户登录
return authService.userSignIn(loginEntity);
}
}

View File

@ -0,0 +1,20 @@
package org.xlf.function.resourcesdocking.mappers;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.xlf.function.resourcesdocking.model.UserDO;
@Mapper
public interface UserMapper {
@Select("SELECT * FROM srd_user WHERE username = #{username} LIMIT 1")
UserDO getUserByUsername(String username);
@Select("SELECT * FROM srd_user WHERE email = #{email} LIMIT 1")
UserDO getUserByEmail(String email);
@Select("SELECT * FROM srd_user WHERE id = #{id} LIMIT 1")
UserDO getUserById(Long id);
@Select("SELECT * FROM srd_user WHERE tel_country_area = #{country} AND tel = #{tel} LIMIT 1")
UserDO getUserByTelephone(String country, String tel);
}

View File

@ -0,0 +1,23 @@
package org.xlf.function.resourcesdocking.model.entity;
import jakarta.validation.constraints.NotBlank;
import lombok.Getter;
import lombok.Setter;
/**
* <h1>AuthLoginEntity 登录实体类</h1>
* <hr/>
* 用于封装登录信息
*
* @since v1.0.0
* @version v1.0.0
* @author 筱锋xiao_lfeng
*/
@Getter
@Setter
public class AuthLoginEntity {
@NotBlank(message = "用户名不能为空")
private String user;
@NotBlank(message = "密码不能为空")
private String password;
}

View File

@ -0,0 +1,74 @@
package org.xlf.function.resourcesdocking.repositories;
import lombok.RequiredArgsConstructor;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Repository;
import org.xlf.function.resourcesdocking.mappers.UserMapper;
import org.xlf.function.resourcesdocking.model.UserDO;
/**
* <h1>AuthDAO 认证数据访问对象</h1>
* <hr/>
* 用于访问认证相关数据
*
* @since v1.0.0
* @version v1.0.0
*/
@Repository
@RequiredArgsConstructor
public class AuthDAO {
/**
* <h2>userMapper 用户映射器</h2>
* <hr/>
* 用于访问用户相关数据
*/
private final UserMapper userMapper;
/**
* <h2>getUserByUsername 根据用户名获取用户信息</h2>
* <hr/>
* 用于根据用户名获取用户信息
*
* @param username 用户名
* @return {@link UserDO}
*/
public UserDO getUserByUsername(String username) {
return userMapper.getUserByUsername(username);
}
/**
* <h2>getUserByEmail 根据邮箱获取用户信息</h2>
* <hr/>
* 用于根据邮箱获取用户信息
*
* @param email 邮箱
* @return {@link UserDO}
*/
public UserDO getUserByEmail(String email) {
return userMapper.getUserByEmail(email);
}
/**
* <h2>getUserById 根据用户 ID 获取用户信息</h2>
* <hr/>
* 用于根据用户 ID 获取用户信息
*
* @param id 用户 ID
* @return {@link UserDO}
*/
public UserDO getUserById(Long id) {
return userMapper.getUserById(id);
}
/**
* <h2>getUserByTelephone 根据手机号获取用户信息</h2>
* <hr/>
* 用于根据手机号获取用户信息
*
* @param tel 手机号
* @return {@link UserDO}
*/
public UserDO getUserByTelephone(String @NotNull [] tel) {
return userMapper.getUserByTelephone(tel[0], tel[1]);
}
}

View File

@ -0,0 +1,25 @@
package org.xlf.function.resourcesdocking.services;
import org.xlf.function.resourcesdocking.common.util.BaseResponse;
import org.xlf.function.resourcesdocking.model.entity.AuthLoginEntity;
/**
* <h1>AuthService 认证服务接口</h1>
* <hr/>
* 用于处理认证相关请求
*
* @version v1.0.0
* @see org.xlf.function.resourcesdocking.services.impl.AuthServiceImpl
* @since v1.0.0
*/
public interface AuthService {
/**
* <h2>userSignIn 用户登录</h2>
* <hr/>
* 用于处理用户登录请求
*
* @param loginEntity 登录实体
* @return BaseResponse
*/
BaseResponse userSignIn(AuthLoginEntity loginEntity);
}

View File

@ -0,0 +1,61 @@
package org.xlf.function.resourcesdocking.services.impl;
import lombok.RequiredArgsConstructor;
import org.jetbrains.annotations.NotNull;
import org.mindrot.jbcrypt.BCrypt;
import org.springframework.stereotype.Service;
import org.xlf.function.resourcesdocking.common.util.BaseResponse;
import org.xlf.function.resourcesdocking.common.util.ErrorCode;
import org.xlf.function.resourcesdocking.common.util.ResultUtil;
import org.xlf.function.resourcesdocking.model.UserDO;
import org.xlf.function.resourcesdocking.model.entity.AuthLoginEntity;
import org.xlf.function.resourcesdocking.repositories.AuthDAO;
import org.xlf.function.resourcesdocking.services.AuthService;
import java.util.ArrayList;
import java.util.regex.Pattern;
/**
* <h1>AuthServiceImpl 认证服务实现类</h1>
* <hr/>
* 用于处理认证相关请求
*
* @since v1.0.0
* @version v1.0.0
*/
@Service
@RequiredArgsConstructor
public class AuthServiceImpl implements AuthService {
/**
* 认证数据访问对象
*/
private final AuthDAO authDAO;
@Override
public BaseResponse userSignIn(@NotNull AuthLoginEntity loginEntity) {
// 正则表达式检查用户数据
UserDO userDO;
if (Pattern.matches("^[a-zA-Z0-9_-]{3,40}$", loginEntity.getUser())) {
userDO = authDAO.getUserByUsername(loginEntity.getUser());
} else if (Pattern.matches("^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$", loginEntity.getUser())) {
userDO = authDAO.getUserByEmail(loginEntity.getUser());
} else if (Pattern.matches("^\\+[0-9]+ [0-9]+$", loginEntity.getUser())) {
// 拆分国区与手机号
String[] split = loginEntity.getUser().split(" ");
split[0] = new StringBuilder(split[0]).deleteCharAt(0).toString();
userDO = authDAO.getUserByTelephone(split);
} else {
return ResultUtil.error(ErrorCode.REQUEST_BODY_ERROR, new ArrayList<String>().add("用户名或邮箱或手机号格式错误"));
}
// 验证用户是否存在
if (userDO == null) {
return ResultUtil.error(ErrorCode.USER_NOT_FOUND);
}
// 验证密码是否正确
if (BCrypt.checkpw(loginEntity.getPassword(), userDO.getPassword())) {
return ResultUtil.success("Success", "登陆成功",userDO);
} else {
return ResultUtil.error(ErrorCode.WRONG_PASSWORD);
}
}
}