3.4 用户登录、校验

This commit is contained in:
zhangsan 2025-03-04 16:37:25 +08:00
parent 3ff8188dd8
commit b0cf0b54ab
9 changed files with 333 additions and 9 deletions

View File

@ -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 "";
}

View File

@ -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
}

View File

@ -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<LoginUserVO> 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<LoginUserVO> getLoginUser(HttpServletRequest request) {
User loginUser = userService.getLoginUser(request);
return ResultUtils.success(userService.getLoginUserVO(loginUser));
}
/**
* 用户注销
*/
@PostMapping("/logout")
public BaseResponse<Boolean> userLogout(HttpServletRequest request) {
ThrowUtils.throwIf(request == null, ErrorCode.PARAMS_ERROR);
boolean result = userService.userLogout(request);
return ResultUtils.success(result);
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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<User> {
* @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);
}

View File

@ -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<UserMapper, User>
implements UserService{
@ -46,9 +55,9 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User>
throw new BusinessException(ErrorCode.PARAMS_ERROR, "两次输入的密码不一致");
}
// 2. 检查用户账号是否和数据库中已有的重复
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("userAccount", userAccount);
long count = this.baseMapper.selectCount(queryWrapper);
LambdaQueryWrapper<User> 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<UserMapper, User>
// 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<User> 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;
}
}

View File

@ -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 #是否开启驼峰转换

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="edu.whut.smilepicturebackend.mapper.UserMapper">
<resultMap id="BaseResultMap" type="edu.whut.smilepicturebackend.model.entity.User">
<id property="id" column="id" jdbcType="BIGINT"/>
<result property="userAccount" column="user_account" jdbcType="VARCHAR"/>
<result property="userPassword" column="user_password" jdbcType="VARCHAR"/>
<result property="userName" column="user_name" jdbcType="VARCHAR"/>
<result property="userAvatar" column="user_avatar" jdbcType="VARCHAR"/>
<result property="userProfile" column="user_profile" jdbcType="VARCHAR"/>
<result property="userRole" column="user_role" jdbcType="VARCHAR"/>
<result property="editTime" column="edit_time" jdbcType="TIMESTAMP"/>
<result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
<result property="updateTime" column="update_time" jdbcType="TIMESTAMP"/>
<result property="isDelete" column="is_delete" jdbcType="TINYINT"/>
</resultMap>
<sql id="Base_Column_List">
id,user_account,user_password,
user_name,user_avatar,user_profile,
user_role,edit_time,create_time,
update_time,is_delete
</sql>
</mapper>