diff --git a/win-framework/win-spring-boot-starter-web/src/main/java/com/win/framework/web/config/WinWebAutoConfiguration.java b/win-framework/win-spring-boot-starter-web/src/main/java/com/win/framework/web/config/WinWebAutoConfiguration.java index 7e8ccce..3721a7c 100644 --- a/win-framework/win-spring-boot-starter-web/src/main/java/com/win/framework/web/config/WinWebAutoConfiguration.java +++ b/win-framework/win-spring-boot-starter-web/src/main/java/com/win/framework/web/config/WinWebAutoConfiguration.java @@ -5,6 +5,7 @@ import com.win.framework.common.enums.WebFilterOrderEnum; import com.win.framework.web.constant.Constant; import com.win.framework.web.core.filter.CacheRequestBodyFilter; import com.win.framework.web.core.filter.DemoFilter; +import com.win.framework.web.core.filter.ModuleAuthenInterceptor; import com.win.framework.web.core.filter.MyI18nInterceptor; import com.win.framework.web.core.handler.GlobalExceptionHandler; import com.win.framework.web.core.handler.GlobalResponseBodyHandler; @@ -150,11 +151,15 @@ public class WinWebAutoConfiguration implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { + // 模块权限拦截器 张斌 2024-05-15 10:29 +// registry.addInterceptor(new ModuleAuthenInterceptor()).addPathPatterns("/**"); + // 注册拦截器 MyI18nInterceptor myHandlerInterceptor = new MyI18nInterceptor(); InterceptorRegistration loginRegistry = registry.addInterceptor(myHandlerInterceptor); // 拦截路径 loginRegistry.addPathPatterns("/**"); + } /** diff --git a/win-framework/win-spring-boot-starter-web/src/main/java/com/win/framework/web/core/filter/ModuleAuthenInterceptor.java b/win-framework/win-spring-boot-starter-web/src/main/java/com/win/framework/web/core/filter/ModuleAuthenInterceptor.java new file mode 100644 index 0000000..d0bfb6d --- /dev/null +++ b/win-framework/win-spring-boot-starter-web/src/main/java/com/win/framework/web/core/filter/ModuleAuthenInterceptor.java @@ -0,0 +1,40 @@ +package com.win.framework.web.core.filter; + +import cn.hutool.json.JSONObject; +import com.win.framework.web.core.util.ModuleAuthenUtils; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.servlet.HandlerInterceptor; +import org.springframework.web.servlet.ModelAndView; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.time.LocalDateTime; + +@Slf4j +public class ModuleAuthenInterceptor implements HandlerInterceptor { + + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + LocalDateTime endTime = LocalDateTime.parse(ModuleAuthenUtils.decrypt(ModuleAuthenUtils.moduleExpire.getStr(request.getRequestURI().split("/")[1],null))); + if (endTime == null || endTime.isBefore(LocalDateTime.now())){ + throw new Exception("权限到期或没有当前模块使用权限,请联系服务商缴费"); + } + return true; + } + + /** + * 请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后) + */ + @Override + public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) { + } + + /** + * 在整个请求结束之后被调用,也就是在DispatcherServlet 渲染了对应的视图之后执行(主要是用于进行资源清理工作) + */ + @Override + public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { + } + +} diff --git a/win-framework/win-spring-boot-starter-web/src/main/java/com/win/framework/web/core/util/ModuleAuthenUtils.java b/win-framework/win-spring-boot-starter-web/src/main/java/com/win/framework/web/core/util/ModuleAuthenUtils.java new file mode 100644 index 0000000..8187209 --- /dev/null +++ b/win-framework/win-spring-boot-starter-web/src/main/java/com/win/framework/web/core/util/ModuleAuthenUtils.java @@ -0,0 +1,36 @@ +package com.win.framework.web.core.util; + +import cn.hutool.core.codec.Base64; +import cn.hutool.json.JSONObject; + +import javax.crypto.Cipher; +import javax.crypto.KeyGenerator; +import javax.crypto.spec.SecretKeySpec; +import java.nio.charset.StandardCharsets; +import java.security.NoSuchAlgorithmException; + +public class ModuleAuthenUtils { + private static final String ALGORITHM = "AES"; + private static final int KEY_SIZE = 128; + public static String secretKey; + public static JSONObject moduleExpire; + public static String decrypt(String encryptedData) throws Exception { + SecretKeySpec secretKeySpec = new SecretKeySpec(Base64.decode(secretKey), ALGORITHM); + Cipher cipher = Cipher.getInstance(ALGORITHM); + cipher.init(Cipher.DECRYPT_MODE, secretKeySpec); + byte[] decryptedBytes = cipher.doFinal(Base64.decode(encryptedData)); + return new String(decryptedBytes, StandardCharsets.UTF_8); + } + public static String encrypt(String data) throws Exception { + SecretKeySpec secretKeySpec = new SecretKeySpec(Base64.decode(secretKey), ModuleAuthenUtils.ALGORITHM); + Cipher cipher = Cipher.getInstance(ModuleAuthenUtils.ALGORITHM); + cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec); + byte[] encryptedBytes = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8)); + return Base64.encode(encryptedBytes); + } + public static String generateKey() throws NoSuchAlgorithmException { + KeyGenerator keyGenerator = KeyGenerator.getInstance(ModuleAuthenUtils.ALGORITHM); + keyGenerator.init(ModuleAuthenUtils.KEY_SIZE); + return Base64.encode(keyGenerator.generateKey().getEncoded()); + } +} diff --git a/win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/mq/consumer/LicencesConsumer.java b/win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/mq/consumer/LicencesConsumer.java new file mode 100644 index 0000000..88ae477 --- /dev/null +++ b/win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/mq/consumer/LicencesConsumer.java @@ -0,0 +1,14 @@ +package com.win.module.eam.mq.consumer; + +import com.alibaba.fastjson.JSONObject; +import com.win.framework.mq.core.stream.AbstractStreamMessageListener; +import com.win.module.eam.mq.message.LicencesMessage; +import com.win.module.eam.service.licences.LicencesService; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +@Component +public class LicencesConsumer { + @Resource + private LicencesService licencesService; +} diff --git a/win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/mq/message/LicencesMessage.java b/win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/mq/message/LicencesMessage.java index 15ba2db..55d5be7 100644 --- a/win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/mq/message/LicencesMessage.java +++ b/win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/mq/message/LicencesMessage.java @@ -1,13 +1,10 @@ package com.win.module.eam.mq.message; - import lombok.Data; import lombok.ToString; -import java.util.List; - @Data @ToString(callSuper = true) -public class LicencesMessage { +public class LicencesMessage{ private String secretKey; private String data; -} +} \ No newline at end of file diff --git a/win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/service/licences/LicencesService.java b/win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/service/licences/LicencesService.java index f6f00ee..0dfda8e 100644 --- a/win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/service/licences/LicencesService.java +++ b/win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/service/licences/LicencesService.java @@ -1,6 +1,7 @@ package com.win.module.eam.service.licences; import com.win.module.eam.controller.licences.vo.GenerateLicenceReqVO; +import com.win.module.eam.mq.message.LicencesMessage; import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletResponse; diff --git a/win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/service/licences/LicencesServiceImpl.java b/win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/service/licences/LicencesServiceImpl.java index 86812e2..2fc84e1 100644 --- a/win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/service/licences/LicencesServiceImpl.java +++ b/win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/service/licences/LicencesServiceImpl.java @@ -4,8 +4,9 @@ import cn.hutool.core.codec.Base64; import cn.hutool.crypto.digest.MD5; import cn.hutool.extra.qrcode.QrCodeUtil; import cn.hutool.extra.qrcode.QrConfig; -import com.alibaba.fastjson.JSONArray; -import com.alibaba.fastjson.JSONObject; +import cn.hutool.json.JSONObject; +import com.win.framework.web.core.filter.ModuleAuthenInterceptor; +import com.win.framework.web.core.util.ModuleAuthenUtils; import com.win.module.eam.controller.licences.vo.GenerateLicenceReqVO; import com.win.module.eam.mq.message.LicencesMessage; import org.apache.calcite.util.Util; @@ -22,8 +23,6 @@ import javax.crypto.spec.SecretKeySpec; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.List; import static com.win.framework.common.exception.util.ServiceExceptionUtil.exception; import static com.win.module.eam.enums.ErrorCodeConstants.ENCRYPTION_STR_FORMAT_IS_ERROR; @@ -31,35 +30,10 @@ import static com.win.module.eam.enums.ErrorCodeConstants.ENCRYPTION_STR_FORMAT_ @Service @Validated public class LicencesServiceImpl implements LicencesService { - private static final String ALGORITHM = "AES"; - private static final int KEY_SIZE = 128; - private static final String LICENCES_UPDATE = "LICENCES"; + public static final String LICENCES_UPDATE = "system.licences"; @Resource private RedisTemplate redisTemplate; - private static String generateKey() throws Exception { - KeyGenerator keyGenerator = KeyGenerator.getInstance(ALGORITHM); - keyGenerator.init(KEY_SIZE); - SecretKey secretKey = keyGenerator.generateKey(); - return Base64.encode(secretKey.getEncoded()); - } - - private static String encrypt(String data, String key) throws Exception { - SecretKeySpec secretKeySpec = new SecretKeySpec(Base64.decode(key), ALGORITHM); - Cipher cipher = Cipher.getInstance(ALGORITHM); - cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec); - byte[] encryptedBytes = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8)); - return Base64.encode(encryptedBytes); - } - - private static String decrypt(String encryptedData, String key) throws Exception { - SecretKeySpec secretKeySpec = new SecretKeySpec(Base64.decode(key), ALGORITHM); - Cipher cipher = Cipher.getInstance(ALGORITHM); - cipher.init(Cipher.DECRYPT_MODE, secretKeySpec); - byte[] decryptedBytes = cipher.doFinal(Base64.decode(encryptedData)); - return new String(decryptedBytes, StandardCharsets.UTF_8); - } - @Override public void licencesDiscernByCodeImage(MultipartFile file) throws IOException { licenceDiscernByCodeStr(QrCodeUtil.decode(file.getInputStream())); @@ -72,22 +46,25 @@ public class LicencesServiceImpl implements LicencesService { } try { //todo 数据校验 - JSONObject codeJson = JSONObject.parseObject(encryptionStr); - String secretKey = codeJson.getString("secretKey"); - if (Util.isNullOrEmpty(secretKey)) { + JSONObject codeJson = new JSONObject(encryptionStr); + String tmpSecretKey = codeJson.getStr("secretKey"); + if (Util.isNullOrEmpty(tmpSecretKey)) { throw exception(ENCRYPTION_STR_FORMAT_IS_ERROR); } - String dataStr = codeJson.getString("data"); + ModuleAuthenUtils.secretKey = tmpSecretKey; + String dataStr = codeJson.getStr("data"); if (Util.isNullOrEmpty(dataStr)) { throw exception(ENCRYPTION_STR_FORMAT_IS_ERROR); } - JSONArray dataJson = JSONArray.parseArray(decrypt(dataStr, secretKey)); - if (dataJson.isEmpty()) { + //todo 需迁移至mq订阅逻辑中 + JSONObject tmpJson = new JSONObject(ModuleAuthenUtils.decrypt(dataStr)); + if (tmpJson.isEmpty()) { throw exception(ENCRYPTION_STR_FORMAT_IS_ERROR); } + ModuleAuthenUtils.moduleExpire = tmpJson; //todo 更新到redis并使用发布订阅通知其他pods拉取过滤路径 - redisTemplate.opsForValue().set(LICENCES_UPDATE, dataJson.toJSONString()); - redisTemplate.convertAndSend(LICENCES_UPDATE, 1); + redisTemplate.opsForValue().set(LICENCES_UPDATE, ModuleAuthenUtils.moduleExpire.toString()); + redisTemplate.convertAndSend(LICENCES_UPDATE, ModuleAuthenUtils.moduleExpire.toString()); } catch (Exception e) { throw exception(500, e); } @@ -95,22 +72,20 @@ public class LicencesServiceImpl implements LicencesService { @Override public void generateLicence(GenerateLicenceReqVO req, HttpServletResponse response) throws Exception { + //todo 数据准备 LicencesMessage licencesMessage = new LicencesMessage() {{ - String secretKey = generateKey(); + String secretKey = ModuleAuthenUtils.generateKey(); setSecretKey(secretKey); - List data = new ArrayList(); MD5 md5 = MD5.create(); - //todo 从数据库表中取业主各子系统到期时间,路径通过拦截器获取第一层进行MD5验证,时间只能用对称加密解析后做对比 - data.add(new JSONObject(){{ - put(md5.digestHex("/MES"),encrypt("2025-10-10 00:00:00",secretKey)); - }}); - data.add(new JSONObject(){{ - put(md5.digestHex("/WMS"),encrypt("2025-10-10 00:00:00",secretKey)); - }}); - setData(encrypt(JSONObject.toJSONString(data),secretKey)); + JSONObject modules = new JSONObject(){{ + put(md5.digestHex("/MES"),ModuleAuthenUtils.encrypt("2025-10-10 00:00:00")); + put(md5.digestHex("/WMS"),ModuleAuthenUtils.encrypt("2025-10-10 00:00:00")); + }}; + setData(ModuleAuthenUtils.encrypt(modules.toString())); }}; + //todo 生成二维码 QrConfig config = new QrConfig(300, 300); config.setErrorCorrection(com.google.zxing.qrcode.decoder.ErrorCorrectionLevel.M); // 设置纠错级别 - QrCodeUtil.generate(JSONObject.toJSONString(licencesMessage), config, "", response.getOutputStream()); + QrCodeUtil.generate(new JSONObject(licencesMessage).toString(), config, "", response.getOutputStream()); } }