mirror of
https://gitee.com/dromara/RuoYi-Vue-Plus.git
synced 2026-09-20 02:08:15 +08:00
Merge remote-tracking branch 'upstream/dev' into dev
This commit is contained in:
commit
4c3eecb805
@ -18,7 +18,6 @@ import com.ruoyi.common.utils.file.FileUtils;
|
||||
import com.ruoyi.system.domain.SysOss;
|
||||
import com.ruoyi.system.domain.bo.SysOssBo;
|
||||
import com.ruoyi.system.domain.vo.SysOssVo;
|
||||
import com.ruoyi.system.service.ISysConfigService;
|
||||
import com.ruoyi.system.service.ISysOssService;
|
||||
import io.swagger.annotations.*;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@ -48,7 +47,6 @@ import java.util.Map;
|
||||
public class SysOssController extends BaseController {
|
||||
|
||||
private final ISysOssService iSysOssService;
|
||||
private final ISysConfigService iSysConfigService;
|
||||
|
||||
/**
|
||||
* 查询OSS对象存储列表
|
||||
@ -77,7 +75,8 @@ public class SysOssController extends BaseController {
|
||||
SysOss oss = iSysOssService.upload(file);
|
||||
Map<String, String> map = new HashMap<>(2);
|
||||
map.put("url", oss.getUrl());
|
||||
map.put("fileName", oss.getFileName());
|
||||
map.put("fileName", oss.getOriginalName());
|
||||
map.put("ossId", oss.getOssId().toString());
|
||||
return R.ok(map);
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,39 @@
|
||||
package com.ruoyi.common.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 登录类型
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum LoginType {
|
||||
|
||||
/**
|
||||
* 密码登录
|
||||
*/
|
||||
PASSWORD("user.password.retry.limit.exceed", "user.password.retry.limit.count"),
|
||||
|
||||
/**
|
||||
* 短信登录
|
||||
*/
|
||||
SMS("sms.code.retry.limit.exceed", "sms.code.retry.limit.count"),
|
||||
|
||||
/**
|
||||
* 小程序登录
|
||||
*/
|
||||
XCX("", "");
|
||||
|
||||
/**
|
||||
* 登录重试超出限制提示
|
||||
*/
|
||||
final String retryLimitExceed;
|
||||
|
||||
/**
|
||||
* 登录重试限制计数提示
|
||||
*/
|
||||
final String retryLimitCount;
|
||||
}
|
||||
@ -11,6 +11,7 @@ import com.ruoyi.common.core.domain.model.LoginUser;
|
||||
import com.ruoyi.common.core.domain.model.XcxLoginUser;
|
||||
import com.ruoyi.common.core.service.LogininforService;
|
||||
import com.ruoyi.common.enums.DeviceType;
|
||||
import com.ruoyi.common.enums.LoginType;
|
||||
import com.ruoyi.common.enums.UserStatus;
|
||||
import com.ruoyi.common.exception.user.CaptchaException;
|
||||
import com.ruoyi.common.exception.user.CaptchaExpireException;
|
||||
@ -28,6 +29,7 @@ import org.springframework.stereotype.Service;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* 登录校验方法
|
||||
@ -60,35 +62,8 @@ public class SysLoginService {
|
||||
if (captchaOnOff) {
|
||||
validateCaptcha(username, code, uuid, request);
|
||||
}
|
||||
// 获取用户登录错误次数(可自定义限制策略 例如: key + username + ip)
|
||||
Integer errorNumber = RedisUtils.getCacheObject(Constants.LOGIN_ERROR + username);
|
||||
// 锁定时间内登录 则踢出
|
||||
if (ObjectUtil.isNotNull(errorNumber) && errorNumber.equals(Constants.LOGIN_ERROR_NUMBER)) {
|
||||
asyncService.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.retry.limit.exceed", Constants.LOGIN_ERROR_LIMIT_TIME), request);
|
||||
throw new UserException("user.password.retry.limit.exceed", Constants.LOGIN_ERROR_LIMIT_TIME);
|
||||
}
|
||||
|
||||
SysUser user = loadUserByUsername(username);
|
||||
|
||||
if (!BCrypt.checkpw(password, user.getPassword())) {
|
||||
// 是否第一次
|
||||
errorNumber = ObjectUtil.isNull(errorNumber) ? 1 : errorNumber + 1;
|
||||
// 达到规定错误次数 则锁定登录
|
||||
if (errorNumber.equals(Constants.LOGIN_ERROR_NUMBER)) {
|
||||
RedisUtils.setCacheObject(Constants.LOGIN_ERROR + username, errorNumber, Constants.LOGIN_ERROR_LIMIT_TIME, TimeUnit.MINUTES);
|
||||
asyncService.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.retry.limit.exceed", Constants.LOGIN_ERROR_LIMIT_TIME), request);
|
||||
throw new UserException("user.password.retry.limit.exceed", Constants.LOGIN_ERROR_LIMIT_TIME);
|
||||
} else {
|
||||
// 未达到规定错误次数 则递增
|
||||
RedisUtils.setCacheObject(Constants.LOGIN_ERROR + username, errorNumber);
|
||||
asyncService.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.retry.limit.count", errorNumber), request);
|
||||
throw new UserException("user.password.retry.limit.count", errorNumber);
|
||||
}
|
||||
}
|
||||
|
||||
// 登录成功 清空错误次数
|
||||
RedisUtils.deleteObject(Constants.LOGIN_ERROR + username);
|
||||
|
||||
checkLogin(LoginType.PASSWORD, username, () -> !BCrypt.checkpw(password, user.getPassword()));
|
||||
// 此处可根据登录用户的数据不同 自行创建 loginUser
|
||||
LoginUser loginUser = buildLoginUser(user);
|
||||
// 生成token
|
||||
@ -104,33 +79,7 @@ public class SysLoginService {
|
||||
SysUser user = loadUserByPhonenumber(phonenumber);
|
||||
|
||||
HttpServletRequest request = ServletUtils.getRequest();
|
||||
// 获取用户登录错误次数(可自定义限制策略 例如: key + username + ip)
|
||||
Integer errorNumber = RedisUtils.getCacheObject(Constants.LOGIN_ERROR + user.getUserName());
|
||||
// 锁定时间内登录 则踢出
|
||||
if (ObjectUtil.isNotNull(errorNumber) && errorNumber.equals(Constants.LOGIN_ERROR_NUMBER)) {
|
||||
asyncService.recordLogininfor(user.getUserName(), Constants.LOGIN_FAIL, MessageUtils.message("sms.code.retry.limit.exceed", Constants.LOGIN_ERROR_LIMIT_TIME), request);
|
||||
throw new UserException("sms.code.retry.limit.exceed", Constants.LOGIN_ERROR_LIMIT_TIME);
|
||||
}
|
||||
|
||||
if (!validateSmsCode(phonenumber, smsCode)) {
|
||||
// 是否第一次
|
||||
errorNumber = ObjectUtil.isNull(errorNumber) ? 1 : errorNumber + 1;
|
||||
// 达到规定错误次数 则锁定登录
|
||||
if (errorNumber.equals(Constants.LOGIN_ERROR_NUMBER)) {
|
||||
RedisUtils.setCacheObject(Constants.LOGIN_ERROR + user.getUserName(), errorNumber, Constants.LOGIN_ERROR_LIMIT_TIME, TimeUnit.MINUTES);
|
||||
asyncService.recordLogininfor(user.getUserName(), Constants.LOGIN_FAIL, MessageUtils.message("sms.code.retry.limit.exceed", Constants.LOGIN_ERROR_LIMIT_TIME), request);
|
||||
throw new UserException("sms.code.retry.limit.exceed", Constants.LOGIN_ERROR_LIMIT_TIME);
|
||||
} else {
|
||||
// 未达到规定错误次数 则递增
|
||||
RedisUtils.setCacheObject(Constants.LOGIN_ERROR + user.getUserName(), errorNumber);
|
||||
asyncService.recordLogininfor(user.getUserName(), Constants.LOGIN_FAIL, MessageUtils.message("sms.code.retry.limit.count", errorNumber), request);
|
||||
throw new UserException("sms.code.retry.limit.count", errorNumber);
|
||||
}
|
||||
}
|
||||
|
||||
// 登录成功 清空错误次数
|
||||
RedisUtils.deleteObject(Constants.LOGIN_ERROR + user.getUserName());
|
||||
|
||||
checkLogin(LoginType.SMS, user.getUserName(), () -> !validateSmsCode(phonenumber, smsCode));
|
||||
// 此处可根据登录用户的数据不同 自行创建 loginUser
|
||||
LoginUser loginUser = buildLoginUser(user);
|
||||
// 生成token
|
||||
@ -275,4 +224,42 @@ public class SysLoginService {
|
||||
sysUser.setUpdateBy(username);
|
||||
userService.updateUserProfile(sysUser);
|
||||
}
|
||||
|
||||
/**
|
||||
* 登录校验
|
||||
*/
|
||||
private void checkLogin(LoginType loginType, String username, Supplier<Boolean> supplier) {
|
||||
HttpServletRequest request = ServletUtils.getRequest();
|
||||
String errorKey = Constants.LOGIN_ERROR + username;
|
||||
Integer errorLimitTime = Constants.LOGIN_ERROR_LIMIT_TIME;
|
||||
Integer setErrorNumber = Constants.LOGIN_ERROR_NUMBER;
|
||||
String loginFail = Constants.LOGIN_FAIL;
|
||||
|
||||
// 获取用户登录错误次数(可自定义限制策略 例如: key + username + ip)
|
||||
Integer errorNumber = RedisUtils.getCacheObject(errorKey);
|
||||
// 锁定时间内登录 则踢出
|
||||
if (ObjectUtil.isNotNull(errorNumber) && errorNumber.equals(setErrorNumber)) {
|
||||
asyncService.recordLogininfor(username, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), errorLimitTime), request);
|
||||
throw new UserException(loginType.getRetryLimitExceed(), errorLimitTime);
|
||||
}
|
||||
|
||||
if (supplier.get()) {
|
||||
// 是否第一次
|
||||
errorNumber = ObjectUtil.isNull(errorNumber) ? 1 : errorNumber + 1;
|
||||
// 达到规定错误次数 则锁定登录
|
||||
if (errorNumber.equals(setErrorNumber)) {
|
||||
RedisUtils.setCacheObject(errorKey, errorNumber, errorLimitTime, TimeUnit.MINUTES);
|
||||
asyncService.recordLogininfor(username, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), errorLimitTime), request);
|
||||
throw new UserException(loginType.getRetryLimitExceed(), errorLimitTime);
|
||||
} else {
|
||||
// 未达到规定错误次数 则递增
|
||||
RedisUtils.setCacheObject(errorKey, errorNumber);
|
||||
asyncService.recordLogininfor(username, loginFail, MessageUtils.message(loginType.getRetryLimitCount(), errorNumber), request);
|
||||
throw new UserException(loginType.getRetryLimitCount(), errorNumber);
|
||||
}
|
||||
}
|
||||
|
||||
// 登录成功 清空错误次数
|
||||
RedisUtils.deleteObject(errorKey);
|
||||
}
|
||||
}
|
||||
|
||||
@ -41,6 +41,7 @@
|
||||
|
||||
<script>
|
||||
import { getToken } from "@/utils/auth";
|
||||
import { delOss } from "@/api/system/oss";
|
||||
|
||||
export default {
|
||||
name: "FileUpload",
|
||||
@ -89,9 +90,7 @@ export default {
|
||||
const list = Array.isArray(val) ? val : this.value.split(',');
|
||||
// 然后将数组转为对象数组
|
||||
this.fileList = list.map(item => {
|
||||
if (typeof item === "string") {
|
||||
item = { name: item, url: item };
|
||||
}
|
||||
item = { name: item.name, url: item.url, ossId: item.ossId };
|
||||
item.uid = item.uid || new Date().getTime() + temp++;
|
||||
return item;
|
||||
});
|
||||
@ -153,12 +152,12 @@ export default {
|
||||
// 上传成功回调
|
||||
handleUploadSuccess(res, file) {
|
||||
if (res.code === 200) {
|
||||
this.uploadList.push({ name: res.data.fileName, url: res.data.url });
|
||||
this.uploadList.push({ name: res.data.fileName, url: res.data.url, ossId: res.data.ossId });
|
||||
if (this.uploadList.length === this.number) {
|
||||
this.fileList = this.fileList.concat(this.uploadList);
|
||||
this.uploadList = [];
|
||||
this.number = 0;
|
||||
this.$emit("input", this.listToString(this.fileList));
|
||||
this.$emit("input", this.fileList);
|
||||
this.$modal.closeLoading();
|
||||
}
|
||||
} else {
|
||||
@ -168,26 +167,20 @@ export default {
|
||||
},
|
||||
// 删除文件
|
||||
handleDelete(index) {
|
||||
let ossId = this.fileList[index].ossId;
|
||||
delOss(ossId);
|
||||
this.fileList.splice(index, 1);
|
||||
this.$emit("input", this.listToString(this.fileList));
|
||||
this.$emit("input", this.fileList);
|
||||
},
|
||||
// 获取文件名称
|
||||
getFileName(name) {
|
||||
// 如果是url那么取最后的名字 如果不是直接返回
|
||||
if (name.lastIndexOf("/") > -1) {
|
||||
return name.slice(name.lastIndexOf("/") + 1);
|
||||
} else {
|
||||
return "";
|
||||
return name;
|
||||
}
|
||||
},
|
||||
// 对象转成指定字符串分隔
|
||||
listToString(list, separator) {
|
||||
let strs = "";
|
||||
separator = separator || ",";
|
||||
for (let i in list) {
|
||||
strs += list[i].url + separator;
|
||||
}
|
||||
return strs != "" ? strs.substr(0, strs.length - 1) : "";
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@ -44,6 +44,7 @@
|
||||
|
||||
<script>
|
||||
import { getToken } from "@/utils/auth";
|
||||
import { delOss } from "@/api/system/oss";
|
||||
|
||||
export default {
|
||||
props: {
|
||||
@ -92,9 +93,8 @@ export default {
|
||||
const list = Array.isArray(val) ? val : this.value.split(',');
|
||||
// 然后将数组转为对象数组
|
||||
this.fileList = list.map(item => {
|
||||
if (typeof item === "string") {
|
||||
item = { name: item, url: item };
|
||||
}
|
||||
// 此处name使用ossId 防止删除出现重名
|
||||
item = { name: item.ossId, url: item.url, ossId: item.ossId };
|
||||
return item;
|
||||
});
|
||||
} else {
|
||||
@ -117,19 +117,21 @@ export default {
|
||||
handleRemove(file, fileList) {
|
||||
const findex = this.fileList.map(f => f.name).indexOf(file.name);
|
||||
if(findex > -1) {
|
||||
let ossId = this.fileList[findex].ossId;
|
||||
delOss(ossId);
|
||||
this.fileList.splice(findex, 1);
|
||||
this.$emit("input", this.listToString(this.fileList));
|
||||
this.$emit("input", this.fileList);
|
||||
}
|
||||
},
|
||||
// 上传成功回调
|
||||
handleUploadSuccess(res) {
|
||||
if (res.code == 200) {
|
||||
this.uploadList.push({ name: res.data.fileName, url: res.data.url });
|
||||
this.uploadList.push({ name: res.data.fileName, url: res.data.url, ossId: res.data.ossId });
|
||||
if (this.uploadList.length === this.number) {
|
||||
this.fileList = this.fileList.concat(this.uploadList);
|
||||
this.uploadList = [];
|
||||
this.number = 0;
|
||||
this.$emit("input", this.listToString(this.fileList));
|
||||
this.$emit("input", this.fileList);
|
||||
this.$modal.closeLoading();
|
||||
}
|
||||
} else {
|
||||
@ -182,15 +184,6 @@ export default {
|
||||
this.dialogImageUrl = file.url;
|
||||
this.dialogVisible = true;
|
||||
},
|
||||
// 对象转成指定字符串分隔
|
||||
listToString(list, separator) {
|
||||
let strs = "";
|
||||
separator = separator || ",";
|
||||
for (let i in list) {
|
||||
strs += list[i].url + separator;
|
||||
}
|
||||
return strs != '' ? strs.substr(0, strs.length - 1) : '';
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user