用户登陆功能实现,基本接口鉴权功能实现

This commit is contained in:
2025-06-12 13:31:52 +08:00
parent e8296042e3
commit 02eb5a7484
15 changed files with 510 additions and 14 deletions

13
pom.xml
View File

@@ -41,18 +41,19 @@
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.2</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- SA-Token -->
<!-- Sa-Token 权限认证在线文档https://sa-token.cc -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot-starter</artifactId>
<version>1.44.0</version>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>

View File

@@ -11,6 +11,8 @@ public enum ErrorCode {
SUCCESS(0, "ok"),
PARAMS_ERROR(40000, "请求参数错误"),
NOT_LOGIN_ERROR(40100, "未登录"),
USERNAME_OR_PASSWORD_ERROR(40200, "账号或密码错误"),
USER_DISABLE(40300, "用户被禁用"),
NO_AUTH_ERROR(40101, "无权限"),
NOT_FOUND_ERROR(40400, "请求数据不存在"),
FORBIDDEN_ERROR(40300, "禁止访问"),

View File

@@ -21,11 +21,12 @@ public class MyBatisPlusConfig {
*
* @return
*/
// @Bean
// public MybatisPlusInterceptor mybatisPlusInterceptor() {
// MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// // 分页插件
// interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
// return interceptor;
// }
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 分页插件
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}

View File

@@ -0,0 +1,39 @@
package com.yupi.springbootinit.config;
import cn.dev33.satoken.interceptor.SaInterceptor;
import cn.dev33.satoken.stp.StpUtil;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class SaTokenConfigure implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 注册Sa-Token的拦截器
registry.addInterceptor(new SaInterceptor(handle -> StpUtil.checkLogin()))
.addPathPatterns("/**")
.excludePathPatterns(getExcludePaths());
}
/**
* 获取需要放行的路径
*/
private String[] getExcludePaths() {
return new String[]{
// Swagger & Knife4j 相关
"/doc.html",
"/webjars/**",
"/swagger-resources/**",
"/v2/api-docs",
"/v3/api-docs",
"/v3/api-docs/**",
"/swagger-ui.html",
"/swagger-ui/**",
"/favicon.ico",
// 你的其他放行路径,例如登录接口
"/user/doLogin",
"/save_data/add_host"
};
}
}

View File

@@ -0,0 +1,59 @@
package com.yupi.springbootinit.controller;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import com.yupi.springbootinit.common.BaseResponse;
import com.yupi.springbootinit.common.ErrorCode;
import com.yupi.springbootinit.common.ResultUtils;
import com.yupi.springbootinit.exception.BusinessException;
import com.yupi.springbootinit.model.dto.user.SystemUsersDTO;
import com.yupi.springbootinit.model.entity.SystemUsers;
import com.yupi.springbootinit.model.enums.CommonStatusEnum;
import com.yupi.springbootinit.model.vo.user.SystemUsersVO;
import com.yupi.springbootinit.service.SystemUsersService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
/*
* @author: ziin
* @date: 2025/6/11 19:50
*/
@RestController
@RequestMapping("/user")
@Slf4j
@CrossOrigin
public class UserController {
@Resource
private SystemUsersService usersService;
// 测试登录,浏览器访问: http://localhost:8081/user/doLogin?username=zhang&password=123456
@PostMapping("doLogin")
public BaseResponse<SystemUsersVO> doLogin(@RequestBody SystemUsersDTO usersDTO) {
SystemUsers user = usersService.getUserByUserName(usersDTO.getUsername());
if (user == null) {
throw new BusinessException(ErrorCode.USERNAME_OR_PASSWORD_ERROR);
}
if (!usersService.isPasswordMatch(usersDTO.getPassword(), user.getPassword())) {
throw new BusinessException(ErrorCode.USERNAME_OR_PASSWORD_ERROR);
}
if (CommonStatusEnum.isDisable(user.getStatus())) {
throw new BusinessException(ErrorCode.USER_DISABLE);
}
SystemUsersVO systemUsersVO = new SystemUsersVO();
BeanUtil.copyProperties(user, systemUsersVO);
StpUtil.login(user.getId());
return ResultUtils.success(systemUsersVO);
}
// // 查询登录状态,浏览器访问: http://localhost:8081/user/isLogin
// @RequestMapping("isLogin")
// public String isLogin() {
// return "当前会话是否登录:" + StpUtil.isLogin();
// }
}

View File

@@ -0,0 +1,20 @@
package com.yupi.springbootinit.mapper;
/*
* @author: ziin
* @date: 2025/6/11 20:13
*/
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.yupi.springbootinit.model.entity.SystemUsers;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;
public interface SystemUsersMapper extends BaseMapper<SystemUsers> {
}

View File

@@ -0,0 +1,32 @@
package com.yupi.springbootinit.model.dto.user;
import lombok.Data;
import java.util.Date;
/*
* @author: ziin
* @date: 2025/6/11 20:13
*/
/**
* 用户信息表
*/
@Data
public class SystemUsersDTO {
/**
* 用户账号
*/
private String username;
/**
* 密码
*/
private String password;
/**
* 租户编号
*/
private Long tenantId;
}

View File

@@ -0,0 +1,124 @@
package com.yupi.springbootinit.model.entity;
import java.util.Date;
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;
/*
* @author: ziin
* @date: 2025/6/11 20:13
*/
/**
* 用户信息表
*/
@Data
public class SystemUsers {
/**
* 用户ID
*/
private Long id;
/**
* 用户账号
*/
private String username;
/**
* 密码
*/
private String password;
/**
* 用户昵称
*/
private String nickname;
/**
* 备注
*/
private String remark;
/**
* 部门ID
*/
@TableField("dept_id")
private Long deptId;
/**
* 岗位编号数组
*/
@TableField("post_ids")
private String postIds;
/**
* 用户邮箱
*/
private String email;
/**
* 手机号码
*/
private String mobile;
/**
* 用户性别
*/
private Byte sex;
/**
* 头像地址
*/
private String avatar;
/**
* 帐号状态0正常 1停用
*/
private Byte status;
/**
* 最后登录IP
*/
@TableField("login_ip")
private String loginIp;
/**
* 最后登录时间
*/
@TableField("login_date")
private Date loginDate;
/**
* 创建者
*/
private String creator;
/**
* 创建时间
*/
@TableField("create_time")
private Date createTime;
/**
* 更新者
*/
private String updater;
/**
* 更新时间
*/
@TableField("update_time")
private Date updateTime;
/**
* 是否删除
*/
private Boolean deleted;
/**
* 租户编号
*/
@TableField("tenant_id")
private Long tenantId;
}

View File

@@ -0,0 +1,47 @@
package com.yupi.springbootinit.model.enums;
import cn.hutool.core.util.ObjUtil;
import com.yupi.springbootinit.utils.ArrayValuable;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
/**
* 通用状态枚举
*
* @author 芋道源码
*/
@Getter
@AllArgsConstructor
public enum CommonStatusEnum implements ArrayValuable<Integer> {
ENABLE(0, "开启"),
DISABLE(1, "关闭");
public static final Integer[] ARRAYS = Arrays.stream(values()).map(CommonStatusEnum::getStatus).toArray(Integer[]::new);
/**
* 状态值
*/
private final Integer status;
/**
* 状态名
*/
private final String name;
@Override
public Integer[] array() {
return ARRAYS;
}
public static boolean isEnable(Integer status) {
return ObjUtil.equal(ENABLE.status, status);
}
public static boolean isDisable(Byte status) {
return ObjUtil.equal(DISABLE.status, status);
}
}

View File

@@ -0,0 +1,26 @@
package com.yupi.springbootinit.model.vo.user;
import lombok.Data;
import java.util.Date;
/*
* @author: ziin
* @date: 2025/6/11 20:13
*/
/**
* 用户信息表
*/
@Data
public class SystemUsersVO {
/**
* 用户ID
*/
private Long id;
/**
* 租户编号
*/
private Long tenantId;
}

View File

@@ -0,0 +1,16 @@
package com.yupi.springbootinit.service;
/*
* @author: ziin
* @date: 2025/6/11 20:13
*/
import com.baomidou.mybatisplus.extension.service.IService;
import com.yupi.springbootinit.model.entity.SystemUsers;
public interface SystemUsersService extends IService<SystemUsers> {
SystemUsers getUserByUserName(String username);
boolean isPasswordMatch(String rawPassWord, String encodedPassword);
}

View File

@@ -0,0 +1,39 @@
package com.yupi.springbootinit.service.impl;
import cn.hutool.crypto.SecureUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yupi.springbootinit.model.entity.SystemUsers;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;
import com.yupi.springbootinit.mapper.SystemUsersMapper;
import com.yupi.springbootinit.service.SystemUsersService;
import javax.annotation.Resource;
/*
* @author: ziin
* @date: 2025/6/11 20:13
*/
@Service
public class SystemUsersServiceImpl extends ServiceImpl<SystemUsersMapper,SystemUsers> implements SystemUsersService{
@Value("${md5.salt}")
private String MD5_SALT;
@Override
public SystemUsers getUserByUserName(String username) {
QueryWrapper <SystemUsers> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("username",username);
return baseMapper.selectOne(queryWrapper);
}
@Override
public boolean isPasswordMatch(String rawPassword, String encodedPassword) {
String s = SecureUtil.md5(MD5_SALT + rawPassword);
return s.equals(encodedPassword);
}
}

View File

@@ -0,0 +1,15 @@
package com.yupi.springbootinit.utils;
/**
* 可生成 T 数组的接口
*
* @author HUIHUI
*/
public interface ArrayValuable<T> {
/**
* @return 数组
*/
T[] array();
}

View File

@@ -89,4 +89,38 @@ knife4j:
default:
api-rule: package
api-rule-resources:
- com.yupi.springbootinit.controller
- com.yupi.springbootinit.controller
############## Sa-Token 配置 (文档: https://sa-token.cc) ##############
sa-token:
# token 名称(同时也是 cookie 名称)
token-name: vvtoken
# token 有效期(单位:秒) 默认30天-1 代表永久有效
timeout: 2592000
# token 最低活跃频率(单位:秒),如果 token 超过此时间没有访问系统就会被冻结,默认-1 代表不限制,永不冻结
active-timeout: -1
# 是否允许同一账号多地同时登录 (为 true 时允许一起登录, 为 false 时新登录挤掉旧登录)
is-concurrent: false
# 在多人登录同一账号时,是否共用一个 token (为 true 时所有登录共用一个 token, 为 false 时每次登录新建一个 token
is-share: false
# token 风格默认可取值uuid、simple-uuid、random-32、random-64、random-128、tik
token-style: uuid
# 是否输出操作日志
is-log: true
# security配置如果使用了Spring security或者satoken需要添加排除路径
security:
# 排除路径
excludes:
- /*.html
- /**/*.html
- /**/*.css
- /**/*.js
- /favicon.ico
- /error/**
#swagger文档和knife4j的路径
- /v3/api-docs/**
- /doc.html/**
md5:
salt: (-FhqvXO,wMz

View File

@@ -0,0 +1,41 @@
<?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="com.yupi.springbootinit.mapper.SystemUsersMapper">
<resultMap id="BaseResultMap" type="com.yupi.springbootinit.model.entity.SystemUsers">
<!--@mbg.generated-->
<!--@Table system_users-->
<id column="id" jdbcType="BIGINT" property="id" />
<result column="username" jdbcType="VARCHAR" property="username" />
<result column="password" jdbcType="VARCHAR" property="password" />
<result column="nickname" jdbcType="VARCHAR" property="nickname" />
<result column="remark" jdbcType="VARCHAR" property="remark" />
<result column="dept_id" jdbcType="BIGINT" property="deptId" />
<result column="post_ids" jdbcType="VARCHAR" property="postIds" />
<result column="email" jdbcType="VARCHAR" property="email" />
<result column="mobile" jdbcType="VARCHAR" property="mobile" />
<result column="sex" jdbcType="TINYINT" property="sex" />
<result column="avatar" jdbcType="VARCHAR" property="avatar" />
<result column="status" jdbcType="TINYINT" property="status" />
<result column="login_ip" jdbcType="VARCHAR" property="loginIp" />
<result column="login_date" jdbcType="TIMESTAMP" property="loginDate" />
<result column="creator" jdbcType="VARCHAR" property="creator" />
<result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
<result column="updater" jdbcType="VARCHAR" property="updater" />
<result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
<result column="deleted" jdbcType="BIT" property="deleted" />
<result column="tenant_id" jdbcType="BIGINT" property="tenantId" />
</resultMap>
<sql id="Base_Column_List">
<!--@mbg.generated-->
id, username, `password`, nickname, remark, dept_id, post_ids, email, mobile, sex,
avatar, `status`, login_ip, login_date, creator, create_time, updater, update_time,
deleted, tenant_id
</sql>
<select id="selectUsername" resultType="int">
select
<include refid="Base_Column_List">
</include>
from system_users where username = #{userName,jdbcType=VARCHAR}
</select>
</mapper>