Compare commits

...

4 Commits

Author SHA1 Message Date
mashuai 4404af2fb7 漏洞修复 2025-04-29 10:36:15 +08:00
mashuai 724ad87df9 漏洞修复 2025-04-28 11:05:01 +08:00
mashuai 7582561540 bug修复 2025-04-17 10:41:02 +08:00
syruan fca4dd6f0c 南网版本代码同步 2025-02-13 16:03:04 +08:00
20 changed files with 340 additions and 15 deletions

View File

@ -26,6 +26,9 @@ import com.bonus.sgzb.common.security.utils.SecurityUtils;
import com.bonus.sgzb.system.api.model.LoginUser;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* token 控制
@ -107,14 +110,58 @@ public class TokenController {
}
@PostMapping("checkCode")
public R<?> checkCode(@RequestBody LoginBody form) {
public R<?> checkCode(@RequestBody LoginBody form, HttpServletRequest request) {
String ip = request.getRemoteAddr();
String ipKey = "ip_" + ip;
// 获取当前IP的请求次数默认为0
int requestCount = 0;
try {
String countStr = redisService.getCacheObject(ipKey);
if (countStr != null) {
requestCount = Integer.parseInt(countStr);
}
} catch (NumberFormatException e) {
log.error("Failed to parse request count for IP: {}", ip, e);
return R.fail(null, "系统错误,请稍后再试");
}
// 检查请求次数是否超过限制
if (requestCount >= 3) {
return R.fail(null, "您的请求过于频繁,请稍后再试");
}
// 增加请求次数并设置过期时间
redisService.setCacheObject(ipKey, String.valueOf(requestCount + 1), 60L, TimeUnit.MINUTES);
// 使用ScheduledExecutorService替代Timer避免资源泄漏
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.schedule(() -> {
try {
String currentCountStr = redisService.getCacheObject(ipKey);
if (currentCountStr != null) {
int currentCount = Integer.parseInt(currentCountStr);
if (currentCount > 0) {
redisService.setCacheObject(ipKey, String.valueOf(currentCount - 1));
}
}
} catch (NumberFormatException e) {
log.error("Failed to decrement request count for IP: {}", ip, e);
}
}, 60, TimeUnit.SECONDS);
// 验证码校验
if (StringUtils.isBlank(form.getPhone()) || StringUtils.isBlank(form.getCode())) {
return R.fail(null, "手机号或验证码不能为空");
}
// 校验验证码
LoginUser loginUser = sysLoginService.loginCode(form.getPhone(), form.getCode());
if (StringUtils.isNotNull(loginUser)) {
loginUser.setLoginMethod("mobile");
// 创建token
Map<String, Object> tokenMap = tokenService.createToken(loginUser);
return R.ok(tokenService.createToken(loginUser));
return R.ok(tokenMap);
} else {
return R.fail(null, "验证码错误");
}

View File

@ -123,7 +123,7 @@ public class SysLoginService {
if (StringUtils.isNull(userResult) || StringUtils.isNull(userResult.getData())) {
recordLogService.recordLogininfor(phone, Constants.LOGIN_FAIL, "登录手机号不存在");
throw new ServiceException("登录手机号" + phone + " 不存在");
throw new ServiceException("登录信息" + phone + " 错误");
}
if (R.FAIL == userResult.getCode()) {

View File

@ -0,0 +1,40 @@
# Spring
spring:
cloud:
nacos:
discovery:
# 服务注册地址
server-addr: 127.0.0.1:8848
namespace: sgzb_nwjj
config:
# 配置中心地址
server-addr: 127.0.0.1:8848
namespace: sgzb_nwjj
# 配置文件格式
file-extension: yml
# 共享配置
shared-configs:
- application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
onlineApprove: /lbcloud-oauth/oauth/token
wechatAppId: crhmaxnE
wechatAppsecret: 3893e6ed90d325f00e34583dd970a56580c05549
getNowPersonDetailData: /lbcloud-user/user/queryLoginUserInfo
baseUrl: https://test-sso.csgmall.com.cn
appAppsecret: d8e6db9fa9bb09da0e270fa739233c823bf9c5f0
personEasyList: /lbcloud-user/api/user/queryAndPaging/basicInfo
h5Appsecret: 3c4a67b7f6a268b4202a5328e6a1726979d5903b
h5AppId: G3NksDH2
appsecret: 596e4863c8d112842ce820c130b236001297ea73
appId: akvVFYgy
appAppId: u8LLfynf
getPersonDetailData: /lbcloud-user/api/user/queryById
registerPhone: /lbcloud-user/api/user/registrationByPhone
userBindUrl: /lbcloud-authority/api/RoleClient/bindDefaultSystemRole
verifyPhoneCode: /lbcloud-mbroker/api/broker/simpleVerificationCode
# 禁用Actuator端点的未经身份验证的访问
management:
endpoint:
env:
enabled: false

View File

@ -9,4 +9,4 @@ spring:
name: sgzb-auth
profiles:
# 环境配置
active: sgzb_cq_local
active: sgzb_nw_dev

View File

@ -37,7 +37,7 @@
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>4.6.16</version>
<version>5.8.24</version>
</dependency>
<dependency>
<groupId>com.alibaba.fastjson2</groupId>

View File

@ -94,6 +94,14 @@
<artifactId>jasypt-spring-boot-starter</artifactId>
<version>3.0.2</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
</dependency>
</dependencies>

View File

@ -0,0 +1,31 @@
package com.bonus.sgzb.gateway.config;
/**
* @author : syruan
* @version : 1.0
* @PackagePath: com.bonus.sgzb.gateway.config
* @CreateTime: 2025-02-12 16:28
* @Description: swagger配置类
*/
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.web.server.SecurityWebFilterChain;
import static org.springframework.security.config.Customizer.withDefaults;
@EnableWebFluxSecurity
public class Swagger2SecurityConfig {
@Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
return http
.authorizeExchange(exchanges -> exchanges
.pathMatchers("/swagger-ui/**", "/v2/api-docs/**").authenticated()
.anyExchange().permitAll()
)
.httpBasic(withDefaults())
.csrf().disable()
.build();
}
}

View File

@ -0,0 +1,70 @@
# Spring
spring:
servlet:
multipart:
max-request-size: 50MB
max-file-size: 30MB
cloud:
loadbalancer:
# 关闭Ribbon的负载均衡器
ribbon:
enabled: false
# 开启Nacos的负载均衡器
nacos:
enabled: true
nacos:
discovery:
# 服务注册地址
server-addr: 127.0.0.1:8848
namespace: sgzb_nwjj
config:
# 配置中心地址
server-addr: 127.0.0.1:8848
namespace: sgzb_nwjj
# 配置文件格式
file-extension: yml
# 共享配置
shared-configs:
- application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
#腾讯云sms
tencent:
sms:
#api秘钥标识
accessKeyId: AKIDrreCVaRKDtMcgfU5QW9iEfv67tMfldJn
#api秘钥
accessKeySecret: OXUgeMo0yhBRTGo6sVu3yiFX4rQtAzc3
#请求域名
endpoint: sms.tencentcloudapi.com
#所属区域
region: ap-guangzhou
#腾讯云申请应用id
sdkAppId: 1400494336
#签名
smsSign: 南方电网互联网
#云平台模板id 2116937-验收通知 2115503-登录验证
templateId: 2116937,2115503
# 腾讯云cos
cos:
file:
# 存储桶所在地域
region: ap-guangzhou
# 存储桶所在地域
bucketregion: ap-guangzhou
# 存储桶名称
bucketname: prod-rental-1301524038
# API账号
secretid: AKIDrreCVaRKDtMcgfU5QW9iEfv67tMfldJn
# API密钥
secretkey: OXUgeMo0yhBRTGo6sVu3yiFX4rQtAzc3
# 禁用Actuator端点的未经身份验证的访问
management:
endpoint:
env:
enabled: false

View File

@ -9,4 +9,4 @@ spring:
name: sgzb-gateway
profiles:
# 环境配置
active: sgzb_cq_local
active: sgzb_nw_dev

View File

@ -6,6 +6,7 @@ import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import com.bonus.sgzb.common.security.utils.SecurityUtils;
import com.bonus.sgzb.gen.domain.GenTable;
import com.bonus.sgzb.gen.domain.GenTableColumn;
import org.apache.commons.io.IOUtils;
@ -88,9 +89,14 @@ public class GenController extends BaseController
/**
* 查询数据表字段列表
*/
@RequiresPermissions("tool:gen:query")
@GetMapping(value = "/column/{tableId}")
public TableDataInfo columnList(Long tableId)
{
// 只有管理员才能操作
if (!isAdmin()) {
throw new RuntimeException("没有权限操作");
}
TableDataInfo dataInfo = new TableDataInfo();
List<GenTableColumn> list = genTableColumnService.selectGenTableColumnListByTableId(tableId);
dataInfo.setRows(list);
@ -98,6 +104,14 @@ public class GenController extends BaseController
return dataInfo;
}
/**
* 判断是否管理员
* @return
*/
private boolean isAdmin() {
return SecurityUtils.isAdmin(SecurityUtils.getUserId());
}
/**
* 导入表结构保存
*/

View File

@ -38,15 +38,30 @@
<artifactId>commons-compress</artifactId>
<version>1.26.0</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.4</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
<version>2.0.4</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
<version>2.0.4</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.2.13</version>
<version>1.3.15</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.13</version>
<version>1.3.15</version>
</dependency>
<!-- <dependency>
<groupId>org.slf4j</groupId>
@ -136,7 +151,7 @@
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.16</version>
<version>5.8.24</version>
<scope>compile</scope>
</dependency>

View File

@ -25,6 +25,7 @@ public class SgzbMaterialApplication
{
public static void main(String[] args)
{
System.setProperty("org.springframework.boot.logging.LoggingSystem", "none");
SpringApplication.run(SgzbMaterialApplication.class, args);
System.out.println("(♥◠‿◠)ノ゙ 机具管理模块启动成功 ლ(´ڡ`ლ)゙ \n" +
" .-------. ____ __ \n" +

View File

@ -1,5 +1,6 @@
package com.bonus.sgzb.base.controller;
import cn.hutool.core.io.file.FileNameUtil;
import com.bonus.sgzb.base.domain.MaPartType;
import com.bonus.sgzb.base.domain.MapType;
import com.bonus.sgzb.base.service.ExcelService;
@ -108,12 +109,22 @@ public class MaPartTypeController extends BaseController {
}
// 获取文件名
String fileName = file.getOriginalFilename();
// 检查文件扩展名
String fileFormat = FileNameUtil.extName(file.getResource().getFile());
if (fileFormat == null || fileFormat.toLowerCase().endsWith("jsp") || fileFormat.toLowerCase().endsWith("xml")) {
return AjaxResult.error("文件异常,禁止上传");
}
// 生成新的文件名使用当前时间戳
String newFileName = "gz" + System.currentTimeMillis() + "." + fileFormat;
Path filePath;
// 定义文件路径
if (isLinux){
filePath = Paths.get(Constants.UPLOAD_DIR, fileName);
filePath = Paths.get(Constants.UPLOAD_DIR, newFileName);
}else {
filePath = Paths.get(Constants.UPLOAD_DIR_WIN, fileName);
filePath = Paths.get(Constants.UPLOAD_DIR_WIN, newFileName);
}
// 保存文件

View File

@ -5,4 +5,4 @@ spring:
name: sgzb-material
profiles:
# 环境配置
active: sgzb_cq_local
active: sgzb_nw_dev

View File

@ -21,7 +21,7 @@
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.16</version>
<version>5.8.24</version>
</dependency>
<!-- SpringCloud Alibaba Nacos -->

View File

@ -2,6 +2,7 @@ package com.bonus.sgzb.system.controller;
import com.bonus.sgzb.common.core.utils.StringHelper;
import com.bonus.sgzb.common.core.web.domain.AjaxResult;
import com.bonus.sgzb.common.security.annotation.RequiresPermissions;
import com.bonus.sgzb.system.domain.FileInfo;
import com.bonus.sgzb.system.service.SysFileService;
import io.swagger.annotations.ApiOperation;
@ -57,11 +58,14 @@ public class SysFileController {
@ApiOperation(value = "模板", httpMethod = "GET")
@GetMapping("download")
@RequiresPermissions("system:file:download") // 权限标识符
public void download(HttpServletRequest request, HttpServletResponse response, String filename) {
InputStream inputStream = null;
ServletOutputStream servletOutputStream = null;
try {
String path = "download/" + filename;
// 防止路径被绕过目录穿越
path = path.replaceAll("\\.\\.", "").replaceAll("\\.", "").replaceAll("/", "");
org.springframework.core.io.Resource resource = resourceLoader.getResource("classpath:" + path);
response.setContentType("application/vnd.ms-excel");
response.addHeader("Cache-Control", "no-cache, no-store, must-revalidate");

View File

@ -3,12 +3,16 @@ package com.bonus.sgzb.system.service.impl;
import cn.hutool.http.HttpRequest;
import com.alibaba.druid.util.StringUtils;
import com.alibaba.fastjson.JSONObject;
import com.bonus.sgzb.common.core.constant.SecurityConstants;
import com.bonus.sgzb.common.core.constant.UserConstants;
import com.bonus.sgzb.common.core.domain.R;
import com.bonus.sgzb.common.core.exception.ServiceException;
import com.bonus.sgzb.common.core.utils.GlobalConstants;
import com.bonus.sgzb.common.core.web.domain.AjaxResult;
import com.bonus.sgzb.common.redis.service.RedisService;
import com.bonus.sgzb.system.api.RemoteUserService;
import com.bonus.sgzb.system.api.domain.SysUser;
import com.bonus.sgzb.system.api.model.LoginUser;
import com.bonus.sgzb.system.config.TencentSmsConfig;
import com.bonus.sgzb.system.mapper.SysUserMapper;
import com.bonus.sgzb.system.service.ISysSmsService;
@ -27,6 +31,7 @@ import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Random;
import java.util.concurrent.TimeUnit;
@ -45,12 +50,16 @@ public class SysSmsServiceImpl implements ISysSmsService {
@Resource
private RedisService redisService;
@Resource
private SysUserMapper sysUserMapper;
@Resource
private TencentSmsConfig tencentSmsConfig;
@Resource
private RemoteUserService remoteUserService;
/**
* 短信URL
@ -79,6 +88,12 @@ public class SysSmsServiceImpl implements ISysSmsService {
} catch (Exception e) {
return AjaxResult.error("发送失败:" + e.getMessage());
}*/
// 查询用户信息
R<LoginUser> userResult = remoteUserService.getUserInfoByPhone(phone, SecurityConstants.INNER);
if (Objects.isNull(userResult) || Objects.isNull(userResult.getData())) {
return AjaxResult.error("手机号码不正确");
}
return sendMsgByPhone(phone, msg);
}

View File

@ -0,0 +1,70 @@
# Spring
spring:
servlet:
multipart:
max-request-size: 50MB
max-file-size: 30MB
cloud:
loadbalancer:
# 关闭Ribbon的负载均衡器
ribbon:
enabled: false
# 开启Nacos的负载均衡器
nacos:
enabled: true
nacos:
discovery:
# 服务注册地址
server-addr: 127.0.0.1:8848
namespace: sgzb_nwjj
config:
# 配置中心地址
server-addr: 127.0.0.1:8848
namespace: sgzb_nwjj
# 配置文件格式
file-extension: yml
# 共享配置
shared-configs:
- application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
#腾讯云sms
tencent:
sms:
#api秘钥标识
accessKeyId: AKIDrreCVaRKDtMcgfU5QW9iEfv67tMfldJn
#api秘钥
accessKeySecret: OXUgeMo0yhBRTGo6sVu3yiFX4rQtAzc3
#请求域名
endpoint: sms.tencentcloudapi.com
#所属区域
region: ap-guangzhou
#腾讯云申请应用id
sdkAppId: 1400494336
#签名
smsSign: 南方电网互联网
#云平台模板id 2116937-验收通知 2115503-登录验证
templateId: 2116937,2115503
# 腾讯云cos
cos:
file:
# 存储桶所在地域
region: ap-guangzhou
# 存储桶所在地域
bucketregion: ap-guangzhou
# 存储桶名称
bucketname: prod-rental-1301524038
# API账号
secretid: AKIDrreCVaRKDtMcgfU5QW9iEfv67tMfldJn
# API密钥
secretkey: OXUgeMo0yhBRTGo6sVu3yiFX4rQtAzc3
# 禁用Actuator端点的未经身份验证的访问
management:
endpoint:
env:
enabled: false

View File

@ -9,4 +9,4 @@ spring:
name: sgzb-system
profiles:
# 环境配置
active: sgzb_cq_local
active: sgzb_nw_dev

View File

@ -544,7 +544,6 @@ create table sys_config (
) engine=innodb auto_increment=100 comment = '参数配置表';
insert into sys_config values(1, '主框架页-默认皮肤样式名称', 'sys.index.skinName', 'skin-blue', 'Y', 'admin', sysdate(), '', null, '蓝色 skin-blue、绿色 skin-green、紫色 skin-purple、红色 skin-red、黄色 skin-yellow' );
insert into sys_config values(2, '用户管理-账号初始密码', 'sys.user.initPassword', '123456', 'Y', 'admin', sysdate(), '', null, '初始化密码 123456' );
insert into sys_config values(3, '主框架页-侧边栏主题', 'sys.index.sideTheme', 'theme-dark', 'Y', 'admin', sysdate(), '', null, '深色主题theme-dark浅色主题theme-light' );
insert into sys_config values(4, '账号自助-是否开启用户注册功能', 'sys.account.registerUser', 'false', 'Y', 'admin', sysdate(), '', null, '是否开启注册用户功能true开启false关闭');
insert into sys_config values(5, '用户登录-黑名单列表', 'sys.login.blackIPList', '', 'Y', 'admin', sysdate(), '', null, '设置登录IP黑名单限制多个匹配项以;分隔,支持匹配(*通配、网段)');