Merge remote-tracking branch 'origin/main'

main
wanglei 3 months ago
commit abecaa3dd3

@ -0,0 +1,56 @@
package com.ruoyi.web.controller.system;
import com.ruoyi.common.annotation.Anonymous;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.system.service.ILicenseService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Date;
@RestController
@RequestMapping("/license")
public class LicenseController {
@Autowired
private ILicenseService licenseService;
@PostMapping("/activate")
public AjaxResult activateLicense(@RequestParam String licenseKey,
@RequestParam String expireDate) {
Date expire = DateUtils.parseDate(expireDate);
boolean success = licenseService.activateLicense(licenseKey, expire);
return success ? AjaxResult.success("授权激活成功")
: AjaxResult.error("授权密钥无效");
}
@PostMapping("/getLicenseKey")
public AjaxResult getLicenseKey(String expire) {
Date expireDate = DateUtils.parseDate(expire);
String licenseKey = licenseService.generateLicenseKey(expireDate);
return AjaxResult.success(licenseKey);
}
@GetMapping("/check")
public AjaxResult checkLicense() {
boolean isValid = licenseService.checkLicense();
Date expireDate = licenseService.getExpireDate();
return AjaxResult.success("检查成功", new LicenseStatus(isValid, expireDate));
}
static class LicenseStatus {
private boolean valid;
private Date expireDate;
private boolean expired;
public LicenseStatus(boolean valid, Date expireDate) {
this.valid = valid;
this.expireDate = expireDate;
this.expired = expireDate != null && expireDate.before(new Date());
}
// getters and setters
}
}

@ -0,0 +1,28 @@
package com.ruoyi.common.exception;
/**
*
*/
public class LicenseException extends RuntimeException {
private static final long serialVersionUID = 1L;
// 错误码字段(可扩展)
private Integer code;
public LicenseException(String message) {
super(message);
}
public LicenseException(String message, Throwable cause) {
super(message, cause);
}
public LicenseException(Integer code, String message) {
super(message);
this.code = code;
}
public Integer getCode() {
return code;
}
}

@ -1,6 +1,8 @@
package com.ruoyi.framework.config;
import java.util.concurrent.TimeUnit;
import com.ruoyi.framework.interceptor.LicenseInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@ -25,6 +27,8 @@ public class ResourcesConfig implements WebMvcConfigurer
{
@Autowired
private RepeatSubmitInterceptor repeatSubmitInterceptor;
@Autowired
private LicenseInterceptor licenseInterceptor;
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry)
@ -46,6 +50,9 @@ public class ResourcesConfig implements WebMvcConfigurer
public void addInterceptors(InterceptorRegistry registry)
{
registry.addInterceptor(repeatSubmitInterceptor).addPathPatterns("/**");
registry.addInterceptor(licenseInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("/login", "/license/**");
}
/**

@ -111,7 +111,8 @@ public class SecurityConfig
.authorizeHttpRequests((requests) -> {
permitAllUrl.getUrls().forEach(url -> requests.antMatchers(url).permitAll());
// 对于登录login 注册register 验证码captchaImage 允许匿名访问
requests.antMatchers("/login", "/register", "/captchaImage").permitAll()
// requests.antMatchers("/login", "/register", "/captchaImage").permitAll()
requests.antMatchers("/login", "/register", "/captchaImage", "/license/**").permitAll()
// 静态资源,可匿名访问
.antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll()
.antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll()

@ -0,0 +1,54 @@
package com.ruoyi.framework.interceptor;
import com.ruoyi.common.exception.LicenseException;
import com.ruoyi.system.service.ILicenseService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
@Component
public class LicenseInterceptor implements HandlerInterceptor {
@Autowired
private ILicenseService licenseService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 白名单路径直接放行
if (isExcludePath(request.getRequestURI())) {
return true;
}
// 验证授权状态
if (!licenseService.checkLicense()) {
throw new LicenseException("系统授权已过期,请更新授权!");
}
// 检查剩余有效期提前30天提醒
Date expireDate = licenseService.getExpireDate();
if (expireDate != null && isNearExpire(expireDate)) {
Long licw = getRemainingDays(expireDate);
response.setHeader("License-Warning", licw.toString());//系统到期天数存到header中用于前端获取
// response.setHeader("Access-Control-Expose-Headers", "License-Warning");
}
return true;
}
private boolean isExcludePath(String uri) {
return uri.startsWith("/license") ||
uri.startsWith("/login") ||
uri.startsWith("/static");
}
private boolean isNearExpire(Date expireDate) {
long diff = expireDate.getTime() - System.currentTimeMillis();
return diff > 0 && diff < 30L * 24 * 60 * 60 * 1000;
}
private long getRemainingDays(Date expireDate) {
return (expireDate.getTime() - System.currentTimeMillis()) / (1000 * 60 * 60 * 24);
}
}

@ -0,0 +1,42 @@
package com.ruoyi.system.domain;
import java.util.Date;
public class SysLicense {
private Long id;
private String licenseKey;
private Date expireDate;
private Date createTime;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getLicenseKey() {
return licenseKey;
}
public void setLicenseKey(String licenseKey) {
this.licenseKey = licenseKey;
}
public Date getExpireDate() {
return expireDate;
}
public void setExpireDate(Date expireDate) {
this.expireDate = expireDate;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
// getter/setter省略
}

@ -0,0 +1,31 @@
package com.ruoyi.system.mapper;
import com.ruoyi.system.domain.SysLicense;
import java.util.Date;
public interface SysLicenseMapper {
/**
*
*/
SysLicense selectLicense();
/**
*
* @param license
* @return
*/
int insertLicense(SysLicense license);
/**
*
* @return
*/
int deleteLicense();
/**
*
* @param currentDate
* @return
*/
int checkValidLicense(Date currentDate);
}

@ -0,0 +1,11 @@
package com.ruoyi.system.service;
import java.util.Date;
public interface ILicenseService {
boolean activateLicense(String licenseKey, Date expireDate);
boolean checkLicense();
Date getExpireDate();
String generateLicenseKey(Date expireDate);
}

@ -0,0 +1,62 @@
package com.ruoyi.system.service.impl;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.sign.Md5Utils;
import com.ruoyi.system.domain.SysLicense;
import com.ruoyi.system.mapper.SysLicenseMapper;
import com.ruoyi.system.service.ILicenseService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Date;
@Service
public class LicenseServiceImpl implements ILicenseService {
@Resource
private SysLicenseMapper licenseMapper;
private static final String SECRET_KEY = "TangShanKaoKeSecretKey076";
@Override
public boolean activateLicense(String licenseKey, Date expireDate) {
if (StringUtils.isEmpty(licenseKey) || expireDate == null) {
return false;
}
String expectedKey = generateLicenseKey(expireDate);
if (!expectedKey.equals(licenseKey)) {
return false;
}
SysLicense license = new SysLicense();
license.setLicenseKey(licenseKey);
license.setExpireDate(expireDate);
license.setCreateTime(new Date());
licenseMapper.deleteLicense();
return licenseMapper.insertLicense(license) > 0;
}
@Override
public boolean checkLicense() {
SysLicense license = licenseMapper.selectLicense();
if (license == null||(!generateLicenseKey( license.getExpireDate()).equals(license.getLicenseKey()))) {
return false;
}
return !license.getExpireDate().before(new Date());
}
@Override
public Date getExpireDate() {
SysLicense license = licenseMapper.selectLicense();
return license != null ? license.getExpireDate() : null;
}
public String generateLicenseKey(Date expireDate) {
String raw = SECRET_KEY + DateUtils.parseDateToStr("yyyyMMdd", expireDate);
return Md5Utils.hash(raw);
}
}

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.system.mapper.SysLicenseMapper">
<resultMap type="SysLicense" id="SysLicenseResult">
<result property="id" column="id"/>
<result property="licenseKey" column="license_key"/>
<result property="expireDate" column="expire_date"/>
<result property="createTime" column="create_time"/>
</resultMap>
<sql id="selectLicenseVo">
select id, license_key, expire_date, create_time from sys_license
</sql>
<select id="selectLicense" resultMap="SysLicenseResult">
<include refid="selectLicenseVo"/>
order by id desc limit 1
</select>
<insert id="insertLicense" parameterType="SysLicense" useGeneratedKeys="true" keyProperty="id">
insert into sys_license (
<if test="licenseKey != null and licenseKey != ''">license_key,</if>
<if test="expireDate != null">expire_date,</if>
create_time
) values (
<if test="licenseKey != null and licenseKey != ''">#{licenseKey},</if>
<if test="expireDate != null">#{expireDate},</if>
NOW()
)
</insert>
<delete id="deleteLicense" flushCache="true">
DELETE FROM sys_license
</delete>
<select id="checkValidLicense" parameterType="Date" resultType="int">
SELECT COUNT(1)
FROM sys_license
WHERE expire_date >= #{currentDate,jdbcType=TIMESTAMP}
AND license_key IS NOT NULL
</select>
</mapper>
Loading…
Cancel
Save