过期验证
This commit is contained in:
parent
f1fe30920f
commit
108066fab2
@ -3,12 +3,14 @@ package com.ruoyi;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
|
||||
/**
|
||||
* 启动程序
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@EnableScheduling
|
||||
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
|
||||
public class RuoYiApplication
|
||||
{
|
||||
|
@ -0,0 +1,64 @@
|
||||
package com.ruoyi.web.controller.overdue;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.domain.R;
|
||||
import com.ruoyi.common.utils.ServletUtils;
|
||||
import com.ruoyi.framework.AES.AESExample;
|
||||
import com.ruoyi.framework.constants.Constants;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.FileWriter;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author ruoyi
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping
|
||||
public class OverdueController {
|
||||
|
||||
@Resource
|
||||
private AESExample aesExample;
|
||||
|
||||
@Resource
|
||||
private RedisTemplate<String,String> redisTemplate;
|
||||
|
||||
@GetMapping("overdue")
|
||||
private R<String> overdue(@RequestParam String activationCode) {
|
||||
try {
|
||||
String overdue = aesExample.decrypt(activationCode);
|
||||
// 确保文件内容长度足够
|
||||
if (overdue != null && overdue.length() >= 19) {
|
||||
// 截取从第5个字符开始的14个字符
|
||||
String timeString = overdue.substring(4, 18);
|
||||
// 获取当前时间并转换为相同格式
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
|
||||
String currentTime = sdf.format(new Date());
|
||||
// 比较时间
|
||||
if (currentTime.compareTo(timeString) > 0) {
|
||||
// 当前时间大于激活码中的时间,返回激活码已经过期
|
||||
return R.fail("激活码已过期");
|
||||
}else {
|
||||
//当前时间小于激活码中的时间时
|
||||
FileWriter writer = new FileWriter(Constants.KEY_FILE_PATH);
|
||||
// 写入文件内容
|
||||
writer.write(activationCode);
|
||||
writer.close();
|
||||
redisTemplate.opsForValue().set("overdue", overdue);
|
||||
}
|
||||
} else {
|
||||
return R.fail("激活码不正确");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return R.fail("激活码不正确");
|
||||
}
|
||||
return R.ok("激活成功");
|
||||
}
|
||||
}
|
@ -111,7 +111,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
|
||||
// 过滤请求
|
||||
.authorizeRequests()
|
||||
// 对于登录login 注册register 验证码captchaImage 允许匿名访问
|
||||
.antMatchers("/login","/wxLogin", "/register","/registerSmsCode","/registerPhone", "/captchaImage").permitAll()
|
||||
.antMatchers("/login","/wxLogin", "/register","/registerSmsCode","/registerPhone", "/captchaImage","/overdue").permitAll()
|
||||
// 静态资源,可匿名访问
|
||||
.antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll()
|
||||
.antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll()
|
||||
|
@ -0,0 +1,10 @@
|
||||
package com.ruoyi.framework.constants;
|
||||
|
||||
public interface Constants {
|
||||
// 加密算法
|
||||
String ALGORITHM = "AES";
|
||||
// 常量密钥
|
||||
String SECRET_KEY = "jinanshandongdianliangxinxijishu";
|
||||
//密钥存储文件地址
|
||||
String KEY_FILE_PATH = "E:/overdue.txt";
|
||||
}
|
@ -1,8 +1,17 @@
|
||||
package com.ruoyi.framework.interceptor;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Method;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import com.ruoyi.framework.AES.AESExample;
|
||||
import com.ruoyi.framework.constants.Constants;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
@ -17,33 +26,104 @@ import com.ruoyi.common.utils.ServletUtils;
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Component
|
||||
public abstract class RepeatSubmitInterceptor implements HandlerInterceptor
|
||||
{
|
||||
public abstract class RepeatSubmitInterceptor implements HandlerInterceptor {
|
||||
|
||||
@Resource
|
||||
private AESExample aesExample;
|
||||
@Resource
|
||||
private RedisTemplate<String,String> redisTemplate;
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception
|
||||
{
|
||||
if (handler instanceof HandlerMethod)
|
||||
{
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||
|
||||
// 获取请求路径
|
||||
String requestURI = request.getRequestURI();
|
||||
|
||||
// 如果请求路径不是 /overdue,则执行过期检查逻辑
|
||||
if (!"overdue".equals(requestURI.substring( requestURI.lastIndexOf('/') + 1))) {
|
||||
String overdue = redisTemplate.opsForValue().get("overdue");
|
||||
if (overdue == null) {
|
||||
// 读取文件内容
|
||||
overdue = readFileContent();
|
||||
}
|
||||
// 确保文件内容长度足够
|
||||
if (overdue != null && overdue.length() >= 19) {
|
||||
// 截取从第5个字符开始的14个字符
|
||||
String timeString = overdue.substring(4, 18);
|
||||
// 获取当前时间并转换为相同格式
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
|
||||
String currentTime = sdf.format(new Date());
|
||||
// 比较时间
|
||||
if (currentTime.compareTo(timeString) > 0) {
|
||||
// 当前时间大于文件中的时间,返回901错误码
|
||||
AjaxResult ajaxResult = AjaxResult.error(901, "系统已经过期,请联系管理员");
|
||||
ServletUtils.renderString(response, JSON.toJSONString(ajaxResult));
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// 当前时间大于文件中的时间,返回901错误码
|
||||
AjaxResult ajaxResult = AjaxResult.error(901, "系统已经过期,请联系管理员");
|
||||
ServletUtils.renderString(response, JSON.toJSONString(ajaxResult));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (handler instanceof HandlerMethod) {
|
||||
HandlerMethod handlerMethod = (HandlerMethod) handler;
|
||||
Method method = handlerMethod.getMethod();
|
||||
RepeatSubmit annotation = method.getAnnotation(RepeatSubmit.class);
|
||||
if (annotation != null)
|
||||
{
|
||||
if (this.isRepeatSubmit(request, annotation))
|
||||
{
|
||||
if (annotation != null) {
|
||||
if (this.isRepeatSubmit(request, annotation)) {
|
||||
AjaxResult ajaxResult = AjaxResult.error(annotation.message());
|
||||
ServletUtils.renderString(response, JSON.toJSONString(ajaxResult));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 读取文件内容并返回解密后的字符串
|
||||
*
|
||||
* @return 文件内容
|
||||
*/
|
||||
private String readFileContent() {
|
||||
String filePath = Constants.KEY_FILE_PATH;
|
||||
File file = new File(filePath);
|
||||
|
||||
// 判断文件是否存在
|
||||
if (!file.exists()) {
|
||||
try {
|
||||
file.createNewFile();
|
||||
} catch (IOException e) {
|
||||
System.err.println("创建文件失败");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
StringBuilder content = new StringBuilder();
|
||||
try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
content.append(line);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
String decrypt = null;
|
||||
try {
|
||||
decrypt = aesExample.decrypt(content.toString());
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("验证程序错误,请检查");
|
||||
}
|
||||
redisTemplate.opsForValue().set("overdue", decrypt);
|
||||
return decrypt;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证是否重复提交由子类实现具体的防重复提交的规则
|
||||
*
|
||||
|
@ -40,16 +40,19 @@
|
||||
"@riophae/vue-treeselect": "0.4.0",
|
||||
"axios": "0.24.0",
|
||||
"clipboard": "2.0.8",
|
||||
"core-js": "3.25.3",
|
||||
"core-js": "^3.40.0",
|
||||
"cross-spawn": "^7.0.6",
|
||||
"dayjs": "^1.11.9",
|
||||
"echarts": "5.4.0",
|
||||
"element-ui": "2.15.12",
|
||||
"execa": "^9.5.2",
|
||||
"file-saver": "2.0.5",
|
||||
"fuse.js": "6.4.3",
|
||||
"highlight.js": "9.18.5",
|
||||
"js-beautify": "1.13.0",
|
||||
"js-cookie": "3.0.1",
|
||||
"jsencrypt": "3.0.0-rc.1",
|
||||
"nice-try": "^3.0.1",
|
||||
"nprogress": "0.2.0",
|
||||
"qrcodejs2": "0.0.2",
|
||||
"quill": "1.3.7",
|
||||
|
@ -8,7 +8,7 @@ import { isRelogin } from '@/utils/request'
|
||||
|
||||
NProgress.configure({ showSpinner: false })
|
||||
|
||||
const whiteList = ['/login', '/register','/faCade','/cerebrum']
|
||||
const whiteList = ['/login', '/register','/faCade','/cerebrum','/overdue']
|
||||
|
||||
router.beforeEach((to, from, next) => {
|
||||
NProgress.start()
|
||||
|
@ -83,7 +83,7 @@ export const constantRoutes = [
|
||||
path: 'index',
|
||||
component: () => import('@/views/index'),
|
||||
name: 'Index',
|
||||
meta: { title: '首页', icon: 'dashboard', affix: true }
|
||||
meta: {title: '首页', icon: 'dashboard', affix: true}
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -97,7 +97,7 @@ export const constantRoutes = [
|
||||
path: 'profile',
|
||||
component: () => import('@/views/system/user/profile/index'),
|
||||
name: 'Profile',
|
||||
meta: { title: '个人中心', icon: 'user' }
|
||||
meta: {title: '个人中心', icon: 'user'}
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -111,9 +111,14 @@ export const constantRoutes = [
|
||||
path: 'cerebrum',
|
||||
component: () => import('@/views/tabList/cerebrum.vue'),
|
||||
name: 'cerebrum',
|
||||
meta: { title: 'cerebrum', icon: 'user' }
|
||||
meta: {title: 'cerebrum', icon: 'user'}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/overdue',
|
||||
component: () => import('@/views/overdue'),
|
||||
hidden: true
|
||||
}
|
||||
]
|
||||
|
||||
@ -129,7 +134,7 @@ export const dynamicRoutes = [
|
||||
path: 'role/:userId(\\d+)',
|
||||
component: () => import('@/views/system/user/authRole'),
|
||||
name: 'AuthRole',
|
||||
meta: { title: '分配角色', activeMenu: '/system/user' }
|
||||
meta: {title: '分配角色', activeMenu: '/system/user'}
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -143,7 +148,7 @@ export const dynamicRoutes = [
|
||||
path: 'user/:roleId(\\d+)',
|
||||
component: () => import('@/views/system/role/authUser'),
|
||||
name: 'AuthUser',
|
||||
meta: { title: '分配用户', activeMenu: '/system/role' }
|
||||
meta: {title: '分配用户', activeMenu: '/system/role'}
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -157,7 +162,7 @@ export const dynamicRoutes = [
|
||||
path: 'index/:dictId(\\d+)',
|
||||
component: () => import('@/views/system/dict/data'),
|
||||
name: 'Data',
|
||||
meta: { title: '字典数据', activeMenu: '/system/dict' }
|
||||
meta: {title: '字典数据', activeMenu: '/system/dict'}
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -171,7 +176,7 @@ export const dynamicRoutes = [
|
||||
path: 'index/:jobId(\\d+)',
|
||||
component: () => import('@/views/monitor/job/log'),
|
||||
name: 'JobLog',
|
||||
meta: { title: '调度日志', activeMenu: '/monitor/job' }
|
||||
meta: {title: '调度日志', activeMenu: '/monitor/job'}
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -185,7 +190,7 @@ export const dynamicRoutes = [
|
||||
path: 'index/:tableId(\\d+)',
|
||||
component: () => import('@/views/tool/gen/editTable'),
|
||||
name: 'GenEdit',
|
||||
meta: { title: '修改生成配置', activeMenu: '/tool/gen' }
|
||||
meta: {title: '修改生成配置', activeMenu: '/tool/gen'}
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -199,6 +204,6 @@ Router.prototype.push = function push(location) {
|
||||
|
||||
export default new Router({
|
||||
mode: 'history', // 去掉url中的#
|
||||
scrollBehavior: () => ({ y: 0 }),
|
||||
scrollBehavior: () => ({y: 0}),
|
||||
routes: constantRoutes
|
||||
})
|
||||
|
@ -1,15 +1,15 @@
|
||||
import axios from 'axios'
|
||||
import { Notification, MessageBox, Message, Loading } from 'element-ui'
|
||||
import {Notification, MessageBox, Message, Loading} from 'element-ui'
|
||||
import store from '@/store'
|
||||
import { getToken } from '@/utils/auth'
|
||||
import {getToken} from '@/utils/auth'
|
||||
import errorCode from '@/utils/errorCode'
|
||||
import { tansParams, blobValidate } from "@/utils/ruoyi";
|
||||
import {tansParams, blobValidate} from "@/utils/ruoyi";
|
||||
import cache from '@/plugins/cache'
|
||||
import { saveAs } from 'file-saver'
|
||||
import {saveAs} from 'file-saver'
|
||||
|
||||
let downloadLoadingInstance;
|
||||
// 是否显示重新登录
|
||||
export let isRelogin = { show: false };
|
||||
export let isRelogin = {show: false};
|
||||
|
||||
axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8'
|
||||
// 创建axios实例
|
||||
@ -61,8 +61,8 @@ service.interceptors.request.use(config => {
|
||||
}
|
||||
return config
|
||||
}, error => {
|
||||
console.log(error)
|
||||
Promise.reject(error)
|
||||
console.log(error)
|
||||
Promise.reject(error)
|
||||
})
|
||||
|
||||
// 响应拦截器
|
||||
@ -72,30 +72,38 @@ service.interceptors.response.use(res => {
|
||||
// 获取错误信息
|
||||
const msg = errorCode[code] || res.data.msg || errorCode['default']
|
||||
// 二进制数据则直接返回
|
||||
if (res.request.responseType === 'blob' || res.request.responseType === 'arraybuffer') {
|
||||
if (res.request.responseType === 'blob' || res.request.responseType === 'arraybuffer') {
|
||||
return res.data
|
||||
}
|
||||
if (code === 401) {
|
||||
if (!isRelogin.show) {
|
||||
isRelogin.show = true;
|
||||
MessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', { confirmButtonText: '重新登录', cancelButtonText: '取消', type: 'warning' }).then(() => {
|
||||
MessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', {
|
||||
confirmButtonText: '重新登录',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
isRelogin.show = false;
|
||||
store.dispatch('LogOut').then(() => {
|
||||
location.href = '/index';
|
||||
})
|
||||
}).catch(() => {
|
||||
isRelogin.show = false;
|
||||
});
|
||||
}
|
||||
}).catch(() => {
|
||||
isRelogin.show = false;
|
||||
});
|
||||
}
|
||||
return Promise.reject('无效的会话,或者会话已过期,请重新登录。')
|
||||
} else if (code === 500) {
|
||||
Message({ message: msg, type: 'error' })
|
||||
Message({message: msg, type: 'error'})
|
||||
return Promise.reject(new Error(msg))
|
||||
} else if (code === 601) {
|
||||
Message({ message: msg, type: 'warning' })
|
||||
Message({message: msg, type: 'warning'})
|
||||
return Promise.reject('error')
|
||||
} else if (code === 901) {
|
||||
// 跳转到 overdue 页面
|
||||
location.href = '/overdue';
|
||||
return Promise.reject('使用期限已过,请联系管理员。');
|
||||
} else if (code !== 200) {
|
||||
Notification.error({ title: msg })
|
||||
Notification.error({title: msg})
|
||||
return Promise.reject('error')
|
||||
} else {
|
||||
return res.data
|
||||
@ -103,7 +111,7 @@ service.interceptors.response.use(res => {
|
||||
},
|
||||
error => {
|
||||
console.log('err' + error)
|
||||
let { message } = error;
|
||||
let {message} = error;
|
||||
if (message == "Network Error") {
|
||||
message = "后端接口连接异常";
|
||||
} else if (message.includes("timeout")) {
|
||||
@ -111,17 +119,23 @@ service.interceptors.response.use(res => {
|
||||
} else if (message.includes("Request failed with status code")) {
|
||||
message = "系统接口" + message.substr(message.length - 3) + "异常";
|
||||
}
|
||||
Message({ message: message, type: 'error', duration: 5 * 1000 })
|
||||
Message({message: message, type: 'error', duration: 5 * 1000})
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
// 通用下载方法
|
||||
export function download(url, params, filename, config) {
|
||||
downloadLoadingInstance = Loading.service({ text: "正在下载数据,请稍候", spinner: "el-icon-loading", background: "rgba(0, 0, 0, 0.7)", })
|
||||
downloadLoadingInstance = Loading.service({
|
||||
text: "正在下载数据,请稍候",
|
||||
spinner: "el-icon-loading",
|
||||
background: "rgba(0, 0, 0, 0.7)",
|
||||
})
|
||||
return service.post(url, params, {
|
||||
transformRequest: [(params) => { return tansParams(params) }],
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
transformRequest: [(params) => {
|
||||
return tansParams(params)
|
||||
}],
|
||||
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
|
||||
responseType: 'blob',
|
||||
...config
|
||||
}).then(async (data) => {
|
||||
|
Loading…
Reference in New Issue
Block a user