渗透测试漏洞修复

This commit is contained in:
马三炮 2025-11-25 13:11:00 +08:00
parent d1cbf21290
commit 462a4df8af
24 changed files with 388 additions and 131 deletions

View File

@ -25,76 +25,78 @@ public class SysOperLog extends BaseEntity
/** 用户编号 */
private String userId;
/** 操作人员 */
@Excel(name = "用户名")
private String operName;
/** 电话 */
@Excel(name = "手机号")
private String phone;
/** 业务类型0其它 1新增 2修改 3删除 */
private Integer businessType;
@Excel(name = "业务类型")
private String type;
/** 操作模块 */
@Excel(name = "操作模块")
private String title;
/** 业务类型0其它 1新增 2修改 3删除 */
@Excel(name = "业务类型", readConverterExp = "0=其它,1=新增,2=修改,3=删除,4=授权,5=导出,6=导入,7=强退,8=生成代码,9=清空数据")
private Integer businessType;
/** 业务类型数组 */
private Integer[] businessTypes;
/** 请求方法 */
@Excel(name = "请求方法")
private String method;
/** 请求方式 */
@Excel(name = "请求方式")
private String requestMethod;
/** 操作类别0其它 1后台用户 2手机端用户 */
@Excel(name = "操作类别", readConverterExp = "0=其它,1=后台用户,2=手机端用户")
private Integer operatorType;
/** 操作人员 */
@Excel(name = "操作人员")
private String operName;
/** 部门名称 */
@Excel(name = "部门名称")
private String deptName;
/** 请求url */
@Excel(name = "请求地址")
private String operUrl;
/** 操作地址 */
@Excel(name = "操作地址")
private String operIp;
/** 请求参数 */
@Excel(name = "请求参数")
private String operParam;
/** 返回参数 */
@Excel(name = "返回参数")
private String jsonResult;
/** 操作类别0其它 1后台用户 2手机端用户 */
@Excel(name = "资源类型")
private String operatoType;
private Integer operatorType;
//新增的一些字段 fly
@Excel(name = "操作时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private String opersTime;
/** 操作地址 */
@Excel(name = "操作地址")
private String operIp;
/** 操作状态0异常 1正常 */
@Excel(name = "状态", readConverterExp = "0=异常,1=正常")
@Excel(name = "状态", readConverterExp = "0=请求异常,1=请求成功")
private Integer status;
/** 业务类型数组 */
private Integer[] businessTypes;
/** 请求方法 */
private String method;
/** 请求方式 */
private String requestMethod;
/** 部门名称 */
private String deptName;
/** 请求url */
private String operUrl;
/** 请求参数 */
private String operParam;
/** 错误消息 */
@Excel(name = "错误消息")
private String errorMsg;
/** 操作时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Excel(name = "操作时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date operTime;
//新增的一些字段 fly
/** 电话 */
private String opersTime;
/** 电话 */
private String phone;
private String type;
private String operatoType;
private String statusRes;
private String startTime;
private String endTime;
private String module;
private String result;
}

View File

@ -7,6 +7,7 @@ import com.bonus.common.core.constant.SecurityConstants;
import com.bonus.common.core.domain.R;
import com.bonus.common.core.utils.JwtUtils;
import com.bonus.common.core.utils.StringUtils;
import com.bonus.common.redis.service.RedisService;
import com.bonus.common.security.auth.AuthUtil;
import com.bonus.common.security.service.TokenService;
import com.bonus.common.security.utils.SecurityUtils;
@ -35,6 +36,9 @@ public class TokenController
@Autowired
private LocalSessionManager sessionManager;
@Autowired
private RedisService redisService;
@PostMapping("login")
public R<?> login(@RequestBody LoginBody form)
@ -72,6 +76,11 @@ public class TokenController
// 记录用户退出日志
sysLoginService.logout(userId);
}
String userId = JwtUtils.getUserId(token);
// 删除token缓存
redisService.deleteObject(getTokenKey(token));
// 删除用户-token关联
redisService.deleteObject("user:token:" + userId);
return R.ok();
}
@ -95,4 +104,6 @@ public class TokenController
sysLoginService.register(registerBody.getUsername(), registerBody.getPassword());
return R.ok();
}
}

View File

@ -1,5 +1,6 @@
package com.bonus.auth.service;
import com.bonus.common.core.constant.CacheConstants;
import com.bonus.common.core.constant.Constants;
import com.bonus.common.core.constant.SecurityConstants;
import com.bonus.common.core.constant.UserConstants;
@ -16,8 +17,12 @@ import com.bonus.system.api.domain.SysUser;
import com.bonus.system.api.model.LoginUser;
import io.jsonwebtoken.Claims;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;
/**
* 登录校验方法
*
@ -32,6 +37,11 @@ public class SysLoginService
@Autowired
private RemoteUserService remoteUserService;
@Resource
private RedisTemplate<String, Object> redisTemplate;
/**
* 登录
*/
@ -42,6 +52,11 @@ public class SysLoginService
password = AESCBCUtils.decrypt(password);*/
username = RSAUtil.decrypt(username);
password = RSAUtil.decrypt(password);
// 1. 检查用户是否被锁定
if (isLocked(username)) {
long remainTime = redisTemplate.getExpire(CacheConstants.LOCK_KEY_PREFIX + username, TimeUnit.SECONDS);
throw new ServiceException("用户已被锁定,请" + remainTime / 60 + "" + remainTime % 60 + "秒后重试") ;
}
if(StringUtils.isNotEmpty(jwtToken)){
Claims claims = JwtUtils.parseToken(jwtToken);
jwtToken = (String) claims.get(SecurityConstants.DETAILS_USERNAME);
@ -81,6 +96,7 @@ public class SysLoginService
if (StringUtils.isNull(userResult) || StringUtils.isNull(userResult.getData()))
{
recordLogininfor(username, Constants.LOGIN_FAIL, "登录用户不存在");
throw new ServiceException("登录用户:" + username + " 不存在");
}
@ -98,11 +114,21 @@ public class SysLoginService
}
if (!username.equals(jwtToken)) {
if (!SecurityUtils.matchesPassword(password, user.getPassword())) {
// 登录失败递增失败次数
incrementFailCount(username);
long failCount = getFailCount(username);
if (failCount >= CacheConstants.FAIL_LIMIT) {
// 达到阈值锁定用户
lockUser(username);
throw new ServiceException("登录失败次数达到" + CacheConstants.FAIL_LIMIT + "用户已锁定5分钟");
}
recordLogininfor(user.getUserId() + "", Constants.LOGIN_FAIL, "用户密码错误");
throw new ServiceException("用户不存在/密码错误");
throw new ServiceException("用户不存在/密码错误,还有"+(CacheConstants.FAIL_LIMIT-failCount)+"次机会");
}
}
recordLogininfor(user.getUserId() + "", Constants.LOGIN_SUCCESS, "登录成功");
// 3. 登录成功重置失败次数和锁定状态
resetLoginStatus(username);
return userInfo;
}
@ -171,4 +197,47 @@ public class SysLoginService
}
remoteLogService.saveLogininfor(logininfor, SecurityConstants.INNER);
}
/**
* 检查用户是否被锁定
*/
private boolean isLocked(String username) {
return redisTemplate.hasKey(CacheConstants.LOCK_KEY_PREFIX + username);
}
/**
* 递增登录失败次数
*/
private void incrementFailCount(String username) {
String key = CacheConstants.FAIL_COUNT_KEY_PREFIX + username;
redisTemplate.opsForValue().increment(key, 1);
// 设置失败次数缓存有效期如1小时避免长期存储
if (redisTemplate.getExpire(key) == -1) {
redisTemplate.expire(key, 1, TimeUnit.HOURS);
}
}
/**
* 获取登录失败次数
*/
private long getFailCount(String username) {
Object count = redisTemplate.opsForValue().get(CacheConstants.FAIL_COUNT_KEY_PREFIX + username);
return count == null ? 0 : Long.parseLong(count.toString());
}
/**
* 锁定用户
*/
private void lockUser(String username) {
String key = CacheConstants.LOCK_KEY_PREFIX + username;
redisTemplate.opsForValue().set(key, "locked");
redisTemplate.expire(key, CacheConstants.LOCK_MINUTES, TimeUnit.MINUTES);
}
/**
* 重置登录状态成功后
*/
private void resetLoginStatus(String username) {
redisTemplate.delete(CacheConstants.FAIL_COUNT_KEY_PREFIX + username);
redisTemplate.delete(CacheConstants.LOCK_KEY_PREFIX + username);
}
}

View File

@ -21,4 +21,12 @@ public class CacheConstants
* 权限缓存前缀
*/
public final static String LOGIN_TOKEN_KEY = "login_tokens:";
// 登录失败次数阈值
public static final int FAIL_LIMIT = 5;
// 锁定时间分钟
public static final long LOCK_MINUTES = 60;
// Redis键前缀
public static final String FAIL_COUNT_KEY_PREFIX = "login:fail:count:";
public static final String LOCK_KEY_PREFIX = "login:lock:";
}

View File

@ -55,13 +55,25 @@ public class TokenService
loginUser.setUsername(userName);
loginUser.setIpaddr(IpUtils.getIpAddr(ServletUtils.getRequest()));
refreshToken(loginUser);
// 用户token存储key用户ID -> 当前token
String userTokenKey = getTokenKey(String.valueOf(userId));
// 获取用户当前的旧token
String oldToken = redisService.getCacheObject(userTokenKey);
// 如果存在旧token删除旧的token缓存
if (oldToken != null) {
String oldTokenKey = getTokenKey(oldToken);
redisService.deleteObject(oldTokenKey);
}
// 存储新的token关联
redisService.setCacheObject(userTokenKey, token, expireTime, TimeUnit.SECONDS);
String userKey = getTokenKey(loginUser.getToken());
// Jwt存储信息
Map<String, Object> claimsMap = new HashMap<String, Object>();
claimsMap.put(SecurityConstants.USER_KEY, token);
claimsMap.put(SecurityConstants.DETAILS_USER_ID, userId);
claimsMap.put(SecurityConstants.DETAILS_USERNAME, userName);
redisService.setCacheObject(getTokenKey(userKey),loginUser);
//redisService.setCacheObject(getTokenKey(userKey),loginUser);
//redisService.setCacheObject(userKey, loginUser, expireTime, TimeUnit.SECONDS);
// 接口返回信息
Map<String, Object> rspMap = new HashMap<String, Object>();
rspMap.put("access_token", JwtUtils.createToken(claimsMap));

View File

@ -11,7 +11,7 @@ import org.springframework.web.reactive.function.server.RouterFunctions;
/**
* 路由配置信息
*
*
* @author zys
*/
@Configuration
@ -20,12 +20,12 @@ public class RouterFunctionConfiguration
@Autowired
private ValidateCodeHandler validateCodeHandler;
// @SuppressWarnings("rawtypes")
// @Bean
// public RouterFunction routerFunction()
// {
// return RouterFunctions.route(
// RequestPredicates.GET("/code").and(RequestPredicates.accept(MediaType.TEXT_PLAIN)),
// validateCodeHandler);
// }
@SuppressWarnings("rawtypes")
@Bean
public RouterFunction routerFunction()
{
return RouterFunctions.route(
RequestPredicates.GET("/code").and(RequestPredicates.accept(MediaType.TEXT_PLAIN)),
validateCodeHandler);
}
}

View File

@ -25,7 +25,7 @@ import reactor.core.publisher.Mono;
/**
* 网关鉴权
*
*
* @author zys
*/
@Component
@ -64,6 +64,15 @@ public class AuthFilter implements GlobalFilter, Ordered
return chain.filter(exchange);
}
String token = getToken(request);
// 获取token中的用户ID
String userId = JwtUtils.getUserId(token);
// 获取用户当前有效的token
String currentToken = redisService.getCacheObject(CacheConstants.LOGIN_TOKEN_KEY + userId);
// 如果当前token和缓存中的token不一致说明已被挤下线
if (currentToken == null || !currentToken.equals(token)) {
return unauthorizedResponse(exchange,"您的账号已在其他设备登录");
}
if (StringUtils.isEmpty(token) )
{
return unauthorizedResponse(exchange, "令牌不能为空");
@ -156,4 +165,4 @@ public class AuthFilter implements GlobalFilter, Ordered
{
return -200;
}
}
}

View File

@ -12,6 +12,7 @@ import com.bonus.common.core.domain.R;
import com.bonus.common.core.table.PageTableHandler;
import com.bonus.common.core.table.PageTableRequest;
import com.bonus.common.core.table.PageTableResponse;
import com.bonus.common.core.utils.RSAUtil;
import com.bonus.common.core.utils.StringUtils;
import com.bonus.common.log.annotation.Log;
import com.bonus.common.log.enums.BusinessType;
@ -52,7 +53,12 @@ public class UserController {
@PostMapping
@Log(title = "用户管理-新增用户", businessType = BusinessType.INSERT)
@RequiresPermissions("sys:user:add")
public R saveUser(@RequestBody UserBean userDto) {
public R saveUser(UserBean userDto) {
userDto.setUserName(RSAUtil.decrypt(userDto.getUserName()));
userDto.setPhonenumber(RSAUtil.decrypt(userDto.getPhonenumber()));
userDto.setIdNumber(RSAUtil.decrypt(userDto.getIdNumber()));
userDto.setOrgId(RSAUtil.decrypt(userDto.getOrgId()));
userDto.setRoleId(RSAUtil.decrypt(userDto.getRoleId()));
String u = userService.getExistUser(userDto.getPhonenumber());
if (u != null) {
throw new IllegalArgumentException(u + "手机号码已被注册");
@ -65,6 +71,8 @@ public class UserController {
@PutMapping
@RequiresPermissions("sys:user:add")
public R updateUser(@RequestBody UserBean userDto) {
userDto.setUserName(RSAUtil.decrypt(userDto.getUserName()));
userDto.setPhone(RSAUtil.decrypt(userDto.getPhone()));
return userService.updateUser(userDto);
}
@ -72,6 +80,9 @@ public class UserController {
@PutMapping("/{username}")
@RequiresPermissions("sys:user:password")
public void changePassword(@PathVariable String username, String oldPassword, String newPassword) {
//解密
oldPassword = RSAUtil.decrypt(oldPassword);
newPassword = RSAUtil.decrypt(newPassword);
userService.changePassword(username, oldPassword, newPassword);
}

View File

@ -28,8 +28,8 @@ public interface UserDao {
List<UserBean> list(@Param("params") Map<String, Object> params, @Param("offset") Integer offset,
@Param("limit") Integer limit);
@Update("update \"ynrealname\".\"sys_role_user\" set \"is_active\" = '0' where \"userId\" = #{userId}")
int deleteUserRole(int userId);
int deleteUserRole(@Param("userId") int userId);
int saveUserRoles(@Param("userId")String userId, @Param("roleId") String roleId);

View File

@ -2,6 +2,9 @@
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bonus.bmw.basic.dao.UserDao">
<delete id="deleteUserRole">
update "ynrealname"."sys_role_user" set "is_active" = '0' where "userId" = #{userId}
</delete>
<select id="count" resultType="int">
select count(1)
@ -172,10 +175,8 @@
insert into "ynrealname"."sys_role_user"("roleId", "userId","is_active") values(#{roleId},#{userId},'1')
</insert>
<!-- 添加用户 -->
<insert id="saveUser">
<selectKey resultType="java.lang.Long" keyProperty="userId" order="BEFORE">
SELECT @@IDENTITY
</selectKey>
<insert id="saveUser" keyProperty="userId" useGeneratedKeys="true">
insert into "ynrealname"."sys_user"
("username", "password", "loginname", "id_number","phone",
<if test="orgId != null and orgId !=''">
@ -270,4 +271,4 @@
UPDATE "ynrealname"."sys_user" SET "is_push"= #{user.status} WHERE "phone" = #{user.phone} and "is_active" = #{user.isActive}
</foreach>
</update>
</mapper>
</mapper>

View File

@ -10,7 +10,7 @@ function initMenu() {
url: ctxPath + "/permissions/current",
type: "get",
headers: {
"Authorization": token
"token": token
},
async: false,
success: function (data) {
@ -98,7 +98,7 @@ function showLoginInfo() {
type: 'get',
url: ctxPath + '/users/current',
headers: {
"Authorization": token
"token": token
},
async: false,
success: function (data) {
@ -142,7 +142,7 @@ function logout() {
type: 'delete',
url: DATA_URL + '/auth/logout',
headers: {
"Authorization": token
"token": token
},
success: function (data) {
if (data.code==401) {
@ -293,3 +293,5 @@ function onclickIndex(lay_id){
layui.use(['layer'], function () {
layer = layui.layer;
});

View File

@ -157,25 +157,27 @@ function init() {
},
"dom": "<'dt-toolbar'r>t<'dt-toolbar-footer'<'col-sm-4 col-xs-4 hidden-xs'i><'col-xs-8 col-sm-8' p v>>",
"columns": [
{"width":"5%",
{"width":"4%",
data: function (row, type, set, meta) {
var c = meta.settings._iDisplayStart + meta.row + 1;
return c;
}
},
{"data": "operName", "defaultContent": "","width":"8%"},
{"data": "phone", "defaultContent": "","width":"8%"},
{"data": "type", "defaultContent": "","width":"8%"},
{"data": "title", "defaultContent": "","width":"10%"},
{"data": "operName", "defaultContent": "","width":"7%"},
{"data": "phone", "defaultContent": "","width":"7%"},
{"data": "type", "defaultContent": "","width":"7%"},
{"data": "title", "defaultContent": "","width":"8%"},
{"render": function (data, type, row) {
let jsonResult = row['jsonResult'];
let id = row['id'];
let html = "";
html = '<textarea class="layui-textarea">'+jsonResult+'</textarea>';
return html;
}, width: "43%"},
{"data": "operatoType", "defaultContent": "","width":"8%"},
{"data": "opersTime", "defaultContent": "","width":"10%"},
}, width: "37%"},
{"data": "operatoType", "defaultContent": "","width":"7%"},
{"data": "opersTime", "defaultContent": "","width":"8%"},
{"data": "operIp", "defaultContent": "","width":"8%"},
{"data": "statusRes", "defaultContent": "","width":"7%"},
],
"order": [[0, "desc"], [1, "asc"]]
});
@ -192,3 +194,19 @@ function getNowTime() {
var day = time.getDate() >= 10 ? time.getDate() : '0' + time.getDate();
return year + "-" + month + "-" + day;
}
function exportData() {
var keyWord = $('#keyWord').val();
var module = $('#module').val();
var result = $('#result').val();
var type = $('#type').val();
var startTime = $('#startTime').val();
var endTime = $('#endTime').val();
window.location.href = DATA_URL + "/system/operlog/export?token=" + token
+ "&keyword=" + keyWord
+ "&module=" + module
+ "&result=" + result
+ "&type=" + type
+ "&startTime=" + startTime
+ "&endTime=" + endTime;
}

View File

@ -53,9 +53,16 @@ function addUser(formData) {
type: 'POST',
async: false, // 默认异步true,false表示同步
url: formUrl, // 请求地址
contentType: "application/json; charset=utf-8",
dataType: 'json', // 服务器返回数据类型
data: JSON.stringify(formData.field), //获取提交的表单字段
//contentType: "application/x-www-form-urlencoded",
//dataType: 'json', // 服务器返回数据类型
//data: JSON.stringify(formData.field), //获取提交的表单字段
data: {
userName : encryptRsa($("#userName").val()),
idNumber : encryptRsa($("#idNumber").val()),
phonenumber : encryptRsa($("#phonenumber").val()),
orgId : encryptRsa($("#orgId").val()),
roleId : encryptRsa($("#roleId").val())
},
success: function (data) {
layer.close(loadingMsg); // 关闭提示层
if(data.code == 200){
@ -217,4 +224,4 @@ function reloading() {
var index = parent.layer.getFrameIndex(window.name); //先得到当前 iframe层的索引
parent.layer.close(index); //再执行关闭
window.parent.location.reload();
}
}

View File

@ -20,7 +20,7 @@
<div class="form-group">
<label class="col-md-2 control-label">旧密码</label>
<div class="col-md-10">
<input class="form-control" placeholder="旧密码" type="text" name="oldPassword"
<input class="form-control" placeholder="旧密码" type="text" name="oldPassword" id="oldPassword"
data-bv-notempty="true"
data-bv-notempty-message="旧密码 不能为空">
</div>
@ -31,7 +31,7 @@
<input class="form-control" placeholder="新密码" type="text" name="newPassword" id="newPassword"
data-bv-notempty="true"
data-bv-notempty-message="新密码 不能为空"
data-bv-identical="true"
data-bv-identical-field="newPassword2"
data-bv-identical-message="两次密码不一致">
@ -66,6 +66,7 @@
<script type="text/javascript" src="../../layui/layui.js"></script>
<script type="text/javascript" src="../../js/plugin/bootstrapvalidator/bootstrapValidator.min.js"></script>
<script type="text/javascript" src="../../js/publicJs.js"></script>
<script type="text/javascript" src="../../js/Rsa.js"></script>
<script type="text/javascript">
layui.use('layer', function(){
var layer = layui.layer;
@ -80,11 +81,11 @@
$("#username").val(data.username);
}
});
}
init();
function update() {
$('#form').bootstrapValidator();
var bootstrapValidator = $("#form").data('bootstrapValidator');
@ -101,7 +102,13 @@
$.ajax({
type : 'put',
url : ctxPath + '/users/'+$("#username").val(),
data : $("#form").serialize(),
//data : $("#form").serialize(),
data: {
username : encryptRsa($("#username").val()),
oldPassword : encryptRsa($("#oldPassword").val()),
newPassword : encryptRsa($("#newPassword").val()),
newPassword2 : encryptRsa($("#newPassword2").val())
},
success : function(data) {
layer.msg("修改成功", {shift: -1, time: 1000}, function(){
deleteCurrentTab();
@ -127,4 +134,4 @@
}
</script>
</body>
</html>
</html>

View File

@ -76,10 +76,11 @@
<script type="text/javascript" src="../../js/plugin/bootstrapvalidator/bootstrapValidator.min.js"></script>
<script type="text/javascript" src="../../js/common.js"></script>
<script type="text/javascript" src="../../js/dict.js"></script>
<script type="text/javascript" src="../../js/Rsa.js"></script>
<script type="text/javascript">
showDictSelect("sex", "sex");
initData();
function initData(){
$.ajax({
type : 'get',
@ -97,9 +98,9 @@
}
});
}
$('#form').bootstrapValidator();
layui.use(['layer','laydate'], function(){
var layer = layui.layer;
var laydate = layui.laydate;
@ -107,21 +108,32 @@
elem: '#birthday'
});
});
function update() {
var bootstrapValidator = $("#form").data('bootstrapValidator');
bootstrapValidator.validate();
if(!bootstrapValidator.isValid()){
return;
}
var formdata = $("#form").serializeObject();
$.ajax({
type : 'put',
url : ctxPath + '/users',
contentType: "application/json; charset=utf-8",
data : JSON.stringify(formdata),
contentType: "application/json; charset=utf-8",
//data : JSON.stringify(formdata),
data: {
id :$("#id").val(),
username : encryptRsa($("#username").val()),
nickname : encryptRsa($("#nickname").val()),
phone : encryptRsa($("#phone").val()),
telephone : encryptRsa($("#telephone").val()),
email : encryptRsa($("#email").val()),
birthday : encryptRsa($("#birthday").val()),
sex : $("#sex").val(),
status: $("#status").val()
},
success : function(data) {
layer.msg("修改成功", {shift: -1, time: 1000}, function(){
deleteCurrentTab();
@ -129,7 +141,7 @@
}
});
}
</script>
</body>
</html>
</html>

View File

@ -79,7 +79,7 @@
</fieldset>
</form>
</div>
</div>
<script type="text/javascript" src="../../js/libs/jquery-3.6.0.js"></script>
<script type="text/javascript" src="../../js/jq.js"></script>
<script type="text/javascript" src="../../js/plugin/bootstrapvalidator/bootstrapValidator.min.js"></script>
@ -88,6 +88,7 @@
<script type="text/javascript" src="../../layui/layui.js"></script>
<script type="text/javascript" src="../../js/dict.js"></script>
<script type="text/javascript" src="../../js/publicJs.js"></script>
<script type="text/javascript" src="../../js/Rsa.js"></script>
<script type="text/javascript">
layui.use(['layer','laydate'], function(){
var layer = layui.layer;
@ -96,14 +97,14 @@
elem: '#birthday'
});
});
showDictSelect("sex", "sex");
showDictSelect("status", "userStatus");
initRoles();
initData();
function initData(){
var id = getUrlParam("id");
if(id != ""){
@ -123,28 +124,38 @@
$("#status").val(data.status);
}
});
initRoleDatas(id);
}
}
$('#form').bootstrapValidator();
function update() {
var bootstrapValidator = $("#form").data('bootstrapValidator');
bootstrapValidator.validate();
if(!bootstrapValidator.isValid()){
return;
}
var formdata = $("#form").serializeObject();
formdata.roleIds = getCheckedRoleIds();
$.ajax({
type : 'put',
url : ctxPath + '/users',
contentType: "application/json; charset=utf-8",
data : JSON.stringify(formdata),
contentType: "application/json; charset=utf-8",
//data : JSON.stringify(formdata),
data: {
username : encryptRsa($("#username").val()),
nickname : encryptRsa($("#nickname").val()),
phone : encryptRsa($("#phone").val()),
telephone : encryptRsa($("#telephone").val()),
email : encryptRsa($("#email").val()),
birthday : encryptRsa($("#birthday").val()),
sex : $("#sex").val(),
status: $("#status").val()
},
success : function(data) {
layer.msg("修改成功", {shift: -1, time: 1000}, function(){
location.href = ctxPath + "/pages/user/userList.html";
@ -152,7 +163,7 @@
}
});
}
</script>
</body>
</html>
</html>

View File

@ -54,6 +54,9 @@
<button id="searchBt" class="layui-btn layui-btn-sm" permission="sys:operlog:query"
><i class="layui-icon">&#xe615;</i>搜索
</button>
<button class="layui-btn layui-btn-sm" onclick="exportData()">
导出
</button>
<input type="hidden" id="hidMinListDate" value="2022-07-01" />
<input type="hidden" id="hidMaxListDate" value='@DateTime.Now.ToString("yyyy-MM-dd")' />
</div>
@ -75,6 +78,8 @@
<th>返回值</th>
<th>资源类型</th>
<th>操作时间</th>
<th>操作地址</th>
<th>请求结果</th>
</tr>
</thead>
<tbody>
@ -97,4 +102,4 @@
<script type="text/javascript" src="../../../../js/dict.js"></script>
<script type="text/javascript" src="../../../../js/select.js"></script>
<script type="text/javascript" src="../../../../js/work/SettingManage/OperateLog/SysOperateLog.js"
defer="defer"></script>
defer="defer"></script>

View File

@ -111,6 +111,7 @@
<script src="../../../../css/ztree/3.5/jquery.ztree.all.min.js"></script>
<script type="text/javascript" src="../../../../js/work/SettingManage/UserManage/OrgTree.js"></script>
<script type="text/javascript" src="../../../../js/work/SettingManage/UserManage/UserForm.js" defer="defer"></script>
<script type="text/javascript" src="../../../../js/Rsa.js"></script>
<script type="text/javascript">
</script>
</script>

View File

@ -64,8 +64,13 @@ public class SelectController {
//@CrossOrigin
@Log(title = "查询工程-orgId", businessType = BusinessType.SELECT)
public R getProByOrgId(SelectBean o){
SelfPermissionSettingUtils.getSelfPermissionByOrgId(o);
return service.getProByOrgId(o);
try{
SelfPermissionSettingUtils.getSelfPermissionByOrgId(o);
return service.getProByOrgId(o);
} catch (Exception e) {
return R.ok("请求异常,请联系管理员");
}
}
@GetMapping("getProByTeamId")

View File

@ -21,7 +21,7 @@ import java.util.List;
/**
* 操作日志记录
*
*
* @author zys
*/
@RestController
@ -62,11 +62,11 @@ public class SysOperlogController extends BaseController
@Log(title = "操作日志", businessType = BusinessType.EXPORT)
@RequiresPermissions("system:operlog:export")
@PostMapping("/export")
//@RequiresPermissions("system:operlog:export")
@GetMapping("/export")
public void export(HttpServletResponse response, SysOperLog operLog)
{
List<SysOperLog> list = operLogService.selectOperLogList(operLog);
List<SysOperLog> list = operLogService.export(operLog);
ExcelUtil<SysOperLog> util = new ExcelUtil<SysOperLog>(SysOperLog.class);
util.exportExcel(response, list, "操作日志");
}

View File

@ -53,4 +53,5 @@ public interface SysOperLogMapper
List<SysOperLog> list(@Param("params") Map<String, Object> params, @Param("offset") Integer offset, @Param("limit")Integer limit);
List<SysOperLog> export(SysOperLog operLog);
}

View File

@ -52,4 +52,6 @@ public interface ISysOperLogService
int count(Map<String, Object> params);
List<SysOperLog> list(Map<String, Object> params, Integer offset, Integer limit);
List<SysOperLog> export(SysOperLog operLog);
}

View File

@ -10,7 +10,7 @@ import java.util.Map;
/**
* 操作日志 服务层处理
*
*
* @author zys
*/
@Service
@ -21,7 +21,7 @@ public class SysOperLogServiceImpl implements ISysOperLogService
/**
* 新增操作日志
*
*
* @param operLog 操作日志对象
* @return 结果
*/
@ -33,7 +33,7 @@ public class SysOperLogServiceImpl implements ISysOperLogService
/**
* 查询系统操作日志集合
*
*
* @param operLog 操作日志对象
* @return 操作日志集合
*/
@ -45,7 +45,7 @@ public class SysOperLogServiceImpl implements ISysOperLogService
/**
* 批量删除系统操作日志
*
*
* @param operIds 需要删除的操作日志ID
* @return 结果
*/
@ -57,7 +57,7 @@ public class SysOperLogServiceImpl implements ISysOperLogService
/**
* 查询操作日志详细
*
*
* @param operId 操作ID
* @return 操作日志对象
*/
@ -85,4 +85,10 @@ public class SysOperLogServiceImpl implements ISysOperLogService
public List<SysOperLog> list(Map<String, Object> params, Integer offset, Integer limit) {
return operLogMapper.list(params,offset,limit);
}
@Override
public List<SysOperLog> export(SysOperLog operLog) {
List<SysOperLog> res =operLogMapper.export(operLog);
return res;
}
}

View File

@ -160,6 +160,63 @@
OFFSET #{offset} ROWS FETCH NEXT #{limit} ROWS ONLY
</if>
</select>
<select id="export" resultType="com.bonus.system.api.domain.SysOperLog">
select
su."username" AS operName,
su."phone",
a.*
from(
SELECT
"user_id",
"oper_id" AS operId,
"title",
"json_result" as jsonResult,
"oper_ip" as operIp,
"status" as status,
CASE
"business_type"
WHEN 1 THEN '查询'
WHEN 2 THEN '新增'
WHEN 3 THEN '修改'
WHEN 4 THEN '删除'
WHEN 5 THEN '授权'
WHEN 6 THEN '导出'
WHEN 7 THEN '导入'
WHEN 8 THEN '强退'
WHEN 9 THEN '生成代码'
WHEN 10 THEN '清空数据'
ELSE '其他'
END AS type,
CASE
"operator_type"
WHEN 1 THEN '后台'
WHEN 2 THEN 'APP'
ELSE '其他'
END AS operatoType ,
CASE
"status"
WHEN 0 THEN '请求异常'
WHEN 1 THEN '请求成功'
ELSE '其他'
END AS statusRes ,
"create_time" AS opersTime
FROM
"ynrealname"."sys_oper_log"
where
"create_time" BETWEEN #{startTime} || ' 00:00:00' and #{endTime} || ' 23:59:59'
<if test="type != null and type != ''">
and "operator_type" = #{type}
</if>
<if test="module != null and module != ''">
and INSTR("title", #{module}) > 0
</if>
<if test="result != null and result != ''">
and INSTR("json_result", #{result}) > 0
</if>
) a
LEFT JOIN "ynrealname"."sys_user" su ON su."id" = a."user_id"
order by a.opersTime DESC
</select>
<update id="cleanOperLog">
truncate table "ynrealname"."sys_oper_log"