From b0cf0b54ab125913d1deaab15aeb0a049fc78658 Mon Sep 17 00:00:00 2001 From: zhangsan <646228430@qq.com> Date: Tue, 4 Mar 2025 16:37:25 +0800 Subject: [PATCH] =?UTF-8?q?3.4=20=E7=94=A8=E6=88=B7=E7=99=BB=E5=BD=95?= =?UTF-8?q?=E3=80=81=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../annotation/AuthCheck.java | 16 +++ .../constant/UserConstant.java | 31 ++++++ .../controller/UserController.java | 42 +++++++- .../model/dto/UserLoginRequest.java | 24 +++++ .../model/vo/LoginUserVO.java | 60 ++++++++++++ .../service/UserService.java | 43 +++++++- .../service/impl/UserServiceImpl.java | 98 ++++++++++++++++++- src/main/resources/application.yml | 1 + src/main/resources/mapper/UserMapper.xml | 27 +++++ 9 files changed, 333 insertions(+), 9 deletions(-) create mode 100644 src/main/java/edu/whut/smilepicturebackend/annotation/AuthCheck.java create mode 100644 src/main/java/edu/whut/smilepicturebackend/constant/UserConstant.java create mode 100644 src/main/java/edu/whut/smilepicturebackend/model/dto/UserLoginRequest.java create mode 100644 src/main/java/edu/whut/smilepicturebackend/model/vo/LoginUserVO.java create mode 100644 src/main/resources/mapper/UserMapper.xml diff --git a/src/main/java/edu/whut/smilepicturebackend/annotation/AuthCheck.java b/src/main/java/edu/whut/smilepicturebackend/annotation/AuthCheck.java new file mode 100644 index 0000000..b069017 --- /dev/null +++ b/src/main/java/edu/whut/smilepicturebackend/annotation/AuthCheck.java @@ -0,0 +1,16 @@ +package edu.whut.smilepicturebackend.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface AuthCheck { + + /** + * 必须具有某个角色 + **/ + String mustRole() default ""; +} diff --git a/src/main/java/edu/whut/smilepicturebackend/constant/UserConstant.java b/src/main/java/edu/whut/smilepicturebackend/constant/UserConstant.java new file mode 100644 index 0000000..362cef7 --- /dev/null +++ b/src/main/java/edu/whut/smilepicturebackend/constant/UserConstant.java @@ -0,0 +1,31 @@ +package edu.whut.smilepicturebackend.constant; + +/** + * 用户常量 + */ +public interface UserConstant { + + /** + * 用户登录态键 + */ + String USER_LOGIN_STATE = "user_login"; + + // region 权限 + + /** + * 默认角色 + */ + String DEFAULT_ROLE = "user"; + + /** + * 管理员角色 + */ + String VIP_ROLE = "vip"; + + /** + * 管理员角色 + */ + String ADMIN_ROLE = "admin"; + + // endregion +} diff --git a/src/main/java/edu/whut/smilepicturebackend/controller/UserController.java b/src/main/java/edu/whut/smilepicturebackend/controller/UserController.java index 5fc3493..2c87a94 100644 --- a/src/main/java/edu/whut/smilepicturebackend/controller/UserController.java +++ b/src/main/java/edu/whut/smilepicturebackend/controller/UserController.java @@ -4,13 +4,15 @@ import edu.whut.smilepicturebackend.common.BaseResponse; import edu.whut.smilepicturebackend.common.ResultUtils; import edu.whut.smilepicturebackend.exception.ErrorCode; import edu.whut.smilepicturebackend.exception.ThrowUtils; +import edu.whut.smilepicturebackend.model.dto.UserLoginRequest; import edu.whut.smilepicturebackend.model.dto.UserRegisterRequest; +import edu.whut.smilepicturebackend.model.entity.User; +import edu.whut.smilepicturebackend.model.vo.LoginUserVO; import edu.whut.smilepicturebackend.service.UserService; import lombok.RequiredArgsConstructor; -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 org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletRequest; @RestController @@ -31,4 +33,36 @@ public class UserController { long result = userService.userRegister(userAccount, userPassword, checkPassword); return ResultUtils.success(result); } + + /** + * 用户登录 + */ + //TODO:目前是存在session中,待改为token JWT + @PostMapping("/login") + public BaseResponse userLogin(@RequestBody UserLoginRequest userLoginRequest, HttpServletRequest request) { + ThrowUtils.throwIf(userLoginRequest == null, ErrorCode.PARAMS_ERROR); + String userAccount = userLoginRequest.getUserAccount(); + String userPassword = userLoginRequest.getUserPassword(); + LoginUserVO loginUserVO = userService.userLogin(userAccount, userPassword, request); + return ResultUtils.success(loginUserVO); + } + + /** + * 获取当前登录用户 + */ + @GetMapping("/get/login") + public BaseResponse getLoginUser(HttpServletRequest request) { + User loginUser = userService.getLoginUser(request); + return ResultUtils.success(userService.getLoginUserVO(loginUser)); + } + + /** + * 用户注销 + */ + @PostMapping("/logout") + public BaseResponse userLogout(HttpServletRequest request) { + ThrowUtils.throwIf(request == null, ErrorCode.PARAMS_ERROR); + boolean result = userService.userLogout(request); + return ResultUtils.success(result); + } } diff --git a/src/main/java/edu/whut/smilepicturebackend/model/dto/UserLoginRequest.java b/src/main/java/edu/whut/smilepicturebackend/model/dto/UserLoginRequest.java new file mode 100644 index 0000000..7788626 --- /dev/null +++ b/src/main/java/edu/whut/smilepicturebackend/model/dto/UserLoginRequest.java @@ -0,0 +1,24 @@ +package edu.whut.smilepicturebackend.model.dto; + +import lombok.Data; + +import java.io.Serializable; + +/** + * 用户登录请求 + */ +@Data +public class UserLoginRequest implements Serializable { + + private static final long serialVersionUID = 8735650154179439661L; + + /** + * 账号 + */ + private String userAccount; + + /** + * 密码 + */ + private String userPassword; +} diff --git a/src/main/java/edu/whut/smilepicturebackend/model/vo/LoginUserVO.java b/src/main/java/edu/whut/smilepicturebackend/model/vo/LoginUserVO.java new file mode 100644 index 0000000..9eae86a --- /dev/null +++ b/src/main/java/edu/whut/smilepicturebackend/model/vo/LoginUserVO.java @@ -0,0 +1,60 @@ +package edu.whut.smilepicturebackend.model.vo; + +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + +/** + * 已登录用户视图(脱敏) isDelete和password没返回 + */ +@Data +public class LoginUserVO implements Serializable { + + /** + * id + */ + private Long id; + + /** + * 账号 + */ + private String userAccount; + + /** + * 用户昵称 + */ + private String userName; + + /** + * 用户头像 + */ + private String userAvatar; + + /** + * 用户简介 + */ + private String userProfile; + + /** + * 用户角色:user/admin + */ + private String userRole; + + /** + * 编辑时间 + */ + private Date editTime; + + /** + * 创建时间 + */ + private Date createTime; + + /** + * 更新时间 + */ + private Date updateTime; + + private static final long serialVersionUID = 1L; +} \ No newline at end of file diff --git a/src/main/java/edu/whut/smilepicturebackend/service/UserService.java b/src/main/java/edu/whut/smilepicturebackend/service/UserService.java index 84adb1b..faf927c 100644 --- a/src/main/java/edu/whut/smilepicturebackend/service/UserService.java +++ b/src/main/java/edu/whut/smilepicturebackend/service/UserService.java @@ -2,6 +2,9 @@ package edu.whut.smilepicturebackend.service; import com.baomidou.mybatisplus.extension.service.IService; import edu.whut.smilepicturebackend.model.entity.User; +import edu.whut.smilepicturebackend.model.vo.LoginUserVO; + +import javax.servlet.http.HttpServletRequest; /** * @author 张三 @@ -25,6 +28,44 @@ public interface UserService extends IService { * @return */ - + /** + * 获取加密后的密码 + * + * @param userPassword + * @return + */ String getEncryptPassword(String userPassword); + + /** + * 用户登录 + * + * @param userAccount 用户账户 + * @param userPassword 用户密码 + * @return 脱敏后的用户信息 + */ + LoginUserVO userLogin(String userAccount, String userPassword, HttpServletRequest request); + + /** + * 获得脱敏后的登录用户信息 + * + * @param user + * @return + */ + LoginUserVO getLoginUserVO(User user); + + /** + * 获取当前登录用户 + * + * @param request + * @return + */ + User getLoginUser(HttpServletRequest request); + + /** + * 退出登录 + * + * @param request + * @return + */ + boolean userLogout(HttpServletRequest request); } diff --git a/src/main/java/edu/whut/smilepicturebackend/service/impl/UserServiceImpl.java b/src/main/java/edu/whut/smilepicturebackend/service/impl/UserServiceImpl.java index 443b1ad..890cd41 100644 --- a/src/main/java/edu/whut/smilepicturebackend/service/impl/UserServiceImpl.java +++ b/src/main/java/edu/whut/smilepicturebackend/service/impl/UserServiceImpl.java @@ -1,23 +1,32 @@ package edu.whut.smilepicturebackend.service.impl; +import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.util.StrUtil; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import edu.whut.smilepicturebackend.constant.UserConstant; import edu.whut.smilepicturebackend.exception.BusinessException; import edu.whut.smilepicturebackend.exception.ErrorCode; import edu.whut.smilepicturebackend.model.entity.User; import edu.whut.smilepicturebackend.model.enums.UserRoleEnum; +import edu.whut.smilepicturebackend.model.vo.LoginUserVO; import edu.whut.smilepicturebackend.service.UserService; import edu.whut.smilepicturebackend.mapper.UserMapper; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.stereotype.Service; +import javax.servlet.http.HttpServletRequest; + + /** * @author 张三 * @description 针对表【user(用户)】的数据库操作Service实现 * @createDate 2025-06-05 17:43:52 */ @Service +@Slf4j @RequiredArgsConstructor public class UserServiceImpl extends ServiceImpl implements UserService{ @@ -46,9 +55,9 @@ public class UserServiceImpl extends ServiceImpl throw new BusinessException(ErrorCode.PARAMS_ERROR, "两次输入的密码不一致"); } // 2. 检查用户账号是否和数据库中已有的重复 - QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.eq("userAccount", userAccount); - long count = this.baseMapper.selectCount(queryWrapper); + LambdaQueryWrapper lambda = Wrappers.lambdaQuery(); + lambda.eq(User::getUserAccount, userAccount); + long count = this.baseMapper.selectCount(lambda); if (count > 0) { throw new BusinessException(ErrorCode.PARAMS_ERROR, "账号重复"); } @@ -79,6 +88,87 @@ public class UserServiceImpl extends ServiceImpl // final String SALT = "smile12306"; // return DigestUtils.md5DigestAsHex((SALT + userPassword).getBytes()); } + + @Override + public LoginUserVO userLogin(String userAccount, String userPassword, HttpServletRequest request) { + // 1. 校验 + if (StrUtil.hasBlank(userAccount, userPassword)) { + throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数为空"); + } + if (userAccount.length() < 4) { + throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户账号错误"); + } + if (userPassword.length() < 8) { + throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户密码错误"); + } + // 2. 对用户传递的密码进行加密 + String encryptPassword = getEncryptPassword(userPassword); + // 3. 查询数据库中的用户是否存在 + LambdaQueryWrapper lambda = new LambdaQueryWrapper<>(); + lambda + .eq(User::getUserAccount, userAccount) + .eq(User::getUserPassword, encryptPassword); + User user = this.baseMapper.selectOne(lambda); + // 不存在,抛异常 + if (user == null) { + log.info("user login failed, userAccount cannot match userPassword"); + throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户不存在或者密码错误"); + } + // 4. 保存用户的登录态 + request.getSession().setAttribute(UserConstant.USER_LOGIN_STATE, user); + return this.getLoginUserVO(user); + + } + /** + * 获取脱敏类的用户信息 + * + * @param user 用户 + * @return 脱敏后的用户信息 + */ + @Override + public LoginUserVO getLoginUserVO(User user) { + if (user == null) { + return null; + } + LoginUserVO loginUserVO = new LoginUserVO(); + BeanUtil.copyProperties(user, loginUserVO); + return loginUserVO; + } + + @Override + public User getLoginUser(HttpServletRequest request) { + // 判断是否已经登录 + Object userObj = request.getSession().getAttribute(UserConstant.USER_LOGIN_STATE); + User currentUser = (User) userObj; + if (currentUser == null || currentUser.getId() == null) { + throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR); + } + // 从数据库中查询(追求性能的话可以注释,直接返回上述结果) + Long userId = currentUser.getId(); + currentUser = this.getById(userId); + if (currentUser == null) { + throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR); + } + return currentUser; + } + + /** + * 退出登录 + * + * @param request + * @return + */ + @Override + public boolean userLogout(HttpServletRequest request) { + // 判断是否已经登录 + Object userObj = request.getSession().getAttribute(UserConstant.USER_LOGIN_STATE); + if (userObj == null) { + throw new BusinessException(ErrorCode.OPERATION_ERROR, "未登录"); + } + // 移除登录态 + request.getSession().removeAttribute(UserConstant.USER_LOGIN_STATE); + return true; + } } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index d83ed6d..cd1ec9f 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -14,6 +14,7 @@ spring: password: 123456 mybatis-plus: + type-aliases-package: edu.whut.smilepicturebackend.model.entity configuration: # MyBatis 配置 map-underscore-to-camel-case: true #是否开启驼峰转换 diff --git a/src/main/resources/mapper/UserMapper.xml b/src/main/resources/mapper/UserMapper.xml new file mode 100644 index 0000000..f7cf210 --- /dev/null +++ b/src/main/resources/mapper/UserMapper.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + id,user_account,user_password, + user_name,user_avatar,user_profile, + user_role,edit_time,create_time, + update_time,is_delete + +