diff --git a/pom.xml b/pom.xml index ac0ca32..6ec9144 100644 --- a/pom.xml +++ b/pom.xml @@ -41,18 +41,19 @@ com.baomidou mybatis-plus-boot-starter 3.5.2 - - - org.slf4j - * - - org.springframework.boot spring-boot-starter-data-redis + + + + cn.dev33 + sa-token-spring-boot-starter + 1.44.0 + org.springframework.session spring-session-data-redis diff --git a/src/main/java/com/yupi/springbootinit/common/ErrorCode.java b/src/main/java/com/yupi/springbootinit/common/ErrorCode.java index c60faad..e6e00d8 100644 --- a/src/main/java/com/yupi/springbootinit/common/ErrorCode.java +++ b/src/main/java/com/yupi/springbootinit/common/ErrorCode.java @@ -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, "禁止访问"), diff --git a/src/main/java/com/yupi/springbootinit/config/MyBatisPlusConfig.java b/src/main/java/com/yupi/springbootinit/config/MyBatisPlusConfig.java index 9c46153..d51bc49 100644 --- a/src/main/java/com/yupi/springbootinit/config/MyBatisPlusConfig.java +++ b/src/main/java/com/yupi/springbootinit/config/MyBatisPlusConfig.java @@ -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; + } + } \ No newline at end of file diff --git a/src/main/java/com/yupi/springbootinit/config/SaTokenConfigure.java b/src/main/java/com/yupi/springbootinit/config/SaTokenConfigure.java new file mode 100644 index 0000000..7f792b9 --- /dev/null +++ b/src/main/java/com/yupi/springbootinit/config/SaTokenConfigure.java @@ -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" + }; + } +} \ No newline at end of file diff --git a/src/main/java/com/yupi/springbootinit/controller/UserController.java b/src/main/java/com/yupi/springbootinit/controller/UserController.java new file mode 100644 index 0000000..8ec0965 --- /dev/null +++ b/src/main/java/com/yupi/springbootinit/controller/UserController.java @@ -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 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(); +// } +} diff --git a/src/main/java/com/yupi/springbootinit/mapper/SystemUsersMapper.java b/src/main/java/com/yupi/springbootinit/mapper/SystemUsersMapper.java new file mode 100644 index 0000000..ec20205 --- /dev/null +++ b/src/main/java/com/yupi/springbootinit/mapper/SystemUsersMapper.java @@ -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 { + +} \ No newline at end of file diff --git a/src/main/java/com/yupi/springbootinit/model/dto/user/SystemUsersDTO.java b/src/main/java/com/yupi/springbootinit/model/dto/user/SystemUsersDTO.java new file mode 100644 index 0000000..7948950 --- /dev/null +++ b/src/main/java/com/yupi/springbootinit/model/dto/user/SystemUsersDTO.java @@ -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; +} \ No newline at end of file diff --git a/src/main/java/com/yupi/springbootinit/model/entity/SystemUsers.java b/src/main/java/com/yupi/springbootinit/model/entity/SystemUsers.java new file mode 100644 index 0000000..454a856 --- /dev/null +++ b/src/main/java/com/yupi/springbootinit/model/entity/SystemUsers.java @@ -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; +} \ No newline at end of file diff --git a/src/main/java/com/yupi/springbootinit/model/enums/CommonStatusEnum.java b/src/main/java/com/yupi/springbootinit/model/enums/CommonStatusEnum.java new file mode 100644 index 0000000..c47028a --- /dev/null +++ b/src/main/java/com/yupi/springbootinit/model/enums/CommonStatusEnum.java @@ -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 { + + 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); + } + +} diff --git a/src/main/java/com/yupi/springbootinit/model/vo/user/SystemUsersVO.java b/src/main/java/com/yupi/springbootinit/model/vo/user/SystemUsersVO.java new file mode 100644 index 0000000..3306b0a --- /dev/null +++ b/src/main/java/com/yupi/springbootinit/model/vo/user/SystemUsersVO.java @@ -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; +} \ No newline at end of file diff --git a/src/main/java/com/yupi/springbootinit/service/SystemUsersService.java b/src/main/java/com/yupi/springbootinit/service/SystemUsersService.java new file mode 100644 index 0000000..b5cef36 --- /dev/null +++ b/src/main/java/com/yupi/springbootinit/service/SystemUsersService.java @@ -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 getUserByUserName(String username); + + boolean isPasswordMatch(String rawPassWord, String encodedPassword); +} diff --git a/src/main/java/com/yupi/springbootinit/service/impl/SystemUsersServiceImpl.java b/src/main/java/com/yupi/springbootinit/service/impl/SystemUsersServiceImpl.java new file mode 100644 index 0000000..37040a3 --- /dev/null +++ b/src/main/java/com/yupi/springbootinit/service/impl/SystemUsersServiceImpl.java @@ -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 implements SystemUsersService{ + + @Value("${md5.salt}") + private String MD5_SALT; + + @Override + public SystemUsers getUserByUserName(String username) { + QueryWrapper 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); + } +} diff --git a/src/main/java/com/yupi/springbootinit/utils/ArrayValuable.java b/src/main/java/com/yupi/springbootinit/utils/ArrayValuable.java new file mode 100644 index 0000000..10efadf --- /dev/null +++ b/src/main/java/com/yupi/springbootinit/utils/ArrayValuable.java @@ -0,0 +1,15 @@ +package com.yupi.springbootinit.utils; + +/** + * 可生成 T 数组的接口 + * + * @author HUIHUI + */ +public interface ArrayValuable { + + /** + * @return 数组 + */ + T[] array(); + +} \ No newline at end of file diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 1bba187..4d1c97f 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -89,4 +89,38 @@ knife4j: default: api-rule: package api-rule-resources: - - com.yupi.springbootinit.controller \ No newline at end of file + - 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 \ No newline at end of file diff --git a/src/main/resources/mapper/SystemUsersMapper.xml b/src/main/resources/mapper/SystemUsersMapper.xml new file mode 100644 index 0000000..b0cb41e --- /dev/null +++ b/src/main/resources/mapper/SystemUsersMapper.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 + + + + \ No newline at end of file