pom.xml | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/main/java/com/zy/common/CodeRes.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/main/java/com/zy/common/web/AuthController.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/main/java/com/zy/system/controller/LicenseCreatorController.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/main/java/com/zy/system/entity/license/LicenseCheckListener.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/main/resources/application.yml | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/main/resources/license.lic | 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/main/resources/publicCerts.keystore | 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/main/webapp/views/home/easy_login.html | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/main/webapp/views/index.html | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/main/webapp/views/login.html | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
pom.xml
@@ -103,6 +103,11 @@ <artifactId>okhttp</artifactId> <version>3.10.0</version> </dependency> <dependency> <groupId>de.schlichtherle.truelicense</groupId> <artifactId>truelicense-core</artifactId> <version>1.33</version> </dependency> </dependencies> <build> src/main/java/com/zy/common/CodeRes.java
@@ -9,6 +9,8 @@ String USER_10002 = "10002-账号已被禁用"; String USER_10003 = "10003-密码错误"; String SYSTEM_20001 = "20001-许可证已失效"; String EXIST_500 = "500-工作档/库存条码数据已存在"; String PICK_600 = "600-拣料任务"; String NO_COMB_700 = "700-请先组托"; src/main/java/com/zy/common/web/AuthController.java
@@ -14,6 +14,7 @@ import com.zy.common.properties.SystemProperties; import com.zy.common.utils.RandomValidateCodeUtil; import com.zy.system.entity.*; import com.zy.system.entity.license.LicenseVerify; import com.zy.system.service.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; @@ -50,6 +51,12 @@ @RequestMapping("/login.action") @ManagerAuth(value = ManagerAuth.Auth.NONE, memo = "登录") public R loginAction(String username, String password){ //验证许可证是否有效 LicenseVerify licenseVerify = new LicenseVerify(); boolean verify = licenseVerify.verify(); if (!verify) {//许可证已失效 return R.parse(CodeRes.SYSTEM_20001); } if (username.equals("super") && password.equals(Cools.md5(superPwd))) { Map<String, Object> res = new HashMap<>(); res.put("username", username); src/main/java/com/zy/system/controller/LicenseCreatorController.java
New file @@ -0,0 +1,112 @@ package com.zy.system.controller; import com.core.common.Cools; import com.core.common.R; import com.zy.system.entity.license.*; import de.schlichtherle.license.LicenseContent; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import java.io.File; import java.io.IOException; import java.util.Date; /** * * 用于生成证书文件,不能放在给客户部署的代码里 */ @RestController @RequestMapping("/license") public class LicenseCreatorController { @Value("${license.licensePath}") private String licensePath; @Autowired private LicenseCheckListener licenseCheckListener; /** * 获取服务器硬件信息 * @param osName 操作系统类型,如果为空则自动判断 */ @RequestMapping(value = "/getServerInfos",produces = {MediaType.APPLICATION_JSON_UTF8_VALUE}) public LicenseCheck getServerInfos(@RequestParam(value = "osName",required = false) String osName) { //操作系统类型 if(Cools.isEmpty(osName)){ osName = System.getProperty("os.name"); } osName = osName.toLowerCase(); AbstractServerInfos abstractServerInfos = null; //根据不同操作系统类型选择不同的数据获取方法 if (osName.startsWith("windows")) { abstractServerInfos = new WindowsServerInfos(); } else if (osName.startsWith("linux")) { // abstractServerInfos = new LinuxServerInfos(); }else{//其他服务器类型 abstractServerInfos = new WindowsServerInfos(); } return abstractServerInfos.getServerInfos(); } /** * 获取许可证有效期天数 */ @RequestMapping(value = "/getLicenseDays") public R getLicenseDays() { LicenseVerify licenseVerify = new LicenseVerify(); LicenseContent verifyInfo = licenseVerify.getVerifyInfo(); if (verifyInfo == null) { return R.error(); } Date start = new Date(); Date end = verifyInfo.getNotAfter(); Long starTime = start.getTime(); Long endTime = end.getTime(); Long num = endTime - starTime;//时间戳相差的毫秒数 int day = (int) (num / 24 / 60 / 60 / 1000); return R.ok().add(day); } @RequestMapping(value = "/updateLicense") public R updateLicense(@RequestParam("file") MultipartFile[] files){ MultipartFile file = files[0]; String licensePathFileName = this.getClass().getClassLoader().getResource(licensePath).getPath(); File licensePathFile = new File(licensePathFileName); //服务器端保存的文件对象 File serverFile = new File(licensePathFile.getPath()); if (serverFile.exists()) { try { serverFile.delete();//存在文件,删除 } catch (Exception e) { e.printStackTrace(); } } try { //创建文件 serverFile.createNewFile(); //将上传的文件写入到服务器端文件内 file.transferTo(serverFile); } catch (IOException e) { e.printStackTrace(); } //重新加载许可证 boolean loadedLicense = licenseCheckListener.loadLicense(); if (loadedLicense) { return R.ok(); } return R.error("许可证更新失败"); } } src/main/java/com/zy/system/entity/license/LicenseCheckListener.java
New file @@ -0,0 +1,94 @@ package com.zy.system.entity.license; import com.core.common.Cools; import de.schlichtherle.license.LicenseContent; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationListener; import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.stereotype.Component; import java.io.File; /** * 在项目启动时安装证书 */ @Component public class LicenseCheckListener implements ApplicationListener<ContextRefreshedEvent> { private static Logger logger = LogManager.getLogger(LicenseCheckListener.class); /** * 证书subject */ @Value("${license.subject}") private String subject; /** * 公钥别称 */ @Value("${license.publicAlias}") private String publicAlias; /** * 访问公钥库的密码 */ @Value("${license.storePass}") private String storePass; /** * 证书生成路径 */ @Value("${license.licensePath}") private String licensePath; /** * 密钥库存储路径 */ @Value("${license.publicKeysStorePath}") private String publicKeysStorePath; @Override public void onApplicationEvent(ContextRefreshedEvent event) { //root application context 没有parent ApplicationContext context = event.getApplicationContext().getParent(); if(context == null){ loadLicense(); } } //加载证书 public boolean loadLicense() { if(!Cools.isEmpty(licensePath)){ logger.info("++++++++ 开始加载许可证 ++++++++"); try { String publicKeysStoreFileName = this.getClass().getClassLoader().getResource(publicKeysStorePath).getPath(); File publicKeysStoreFile = new File(publicKeysStoreFileName); String licensePathFileName = this.getClass().getClassLoader().getResource(licensePath).getPath(); File licensePathFile = new File(licensePathFileName); LicenseVerifyParam param = new LicenseVerifyParam(); param.setSubject(subject); param.setPublicAlias(publicAlias); param.setStorePass(storePass); param.setLicensePath(licensePathFile.getPath()); param.setPublicKeysStorePath(publicKeysStoreFile.getPath()); LicenseVerify licenseVerify = new LicenseVerify(); //安装证书 LicenseContent install = licenseVerify.install(param); logger.info("++++++++ 许可证加载结束 ++++++++"); return install != null; } catch (Exception e) { return false; } } return false; } } src/main/resources/application.yml
@@ -53,4 +53,13 @@ #erp erp: enable: false enable: false #License相关配置 license: subject: pswms publicAlias: publicCert storePass: public_zhongyang_123456789 licensePath: license.lic publicKeysStorePath: publicCerts.keystore src/main/resources/license.licBinary files differ
src/main/resources/publicCerts.keystoreBinary files differ
src/main/webapp/views/home/easy_login.html
New file @@ -0,0 +1,182 @@ <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>浙江中扬 │ login of zoneyung wms</title> <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1"> <meta name="description" content="study of Instancing with three.js"> <meta name="keywords" content="undefined, Yoichi Kobayashi, WebGL, three.js"> <meta name="theme-color" content="#111111"> <meta name="msapplication-TileImage" content="/sketch-threejs/img/common/ms_tileimage.png"> <meta name="msapplication-TileColor" content="#111111"> <link rel="stylesheet" href="../static/css/font/font-awesome-4.7.0/css/font-awesome.css"> <link rel="stylesheet" href="../static/css/main.min.css"> <link rel="stylesheet" href="../static/css/login.css"> <style> #sidebar{ /*定位*/ position: absolute; top: 50%; right: 1%; transform: translateY(-50%); width: 20%; height: 95%; /*特效*/ background: rgba(255,255,255,0.6); border-radius: 5px; color: #ffffff; z-index: 99; box-shadow: 3px 3px 6px 3px rgba(0, 0, 0, .3); } .login-contain { position: relative; width: 100%; height: 100%; } .login-box { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 100%; text-align: center; } </style> </head> <body> <!-- 侧边栏 --> <div id="sidebar"> <div class="login-contain"> <div class="login-box"> <img src="../static/image/logo.png" alt="" style="width: 80%"> <!-- <span class="login100-form-title p-t-20 p-b-45">中扬立库</span>--> <!-- <span class="login100-form-title p-t-20 p-b-45" style="margin: 15px 0;color: #868686;font-size: 24px">WMS</span>--> <div class="wrap-input100 validate-input m-b-10" data-validate="请输入用户名"> <input id="username" class="input100" type="text" name="username" placeholder="username" autocomplete="off"> <span class="focus-input100"></span> <span class="symbol-input100"> <i class="fa fa-user"></i> </span> </div> <div class="wrap-input100 validate-input m-b-10" data-validate="请输入密码"> <input id="password" class="input100" type="password" name="pass" placeholder="password"> <span class="focus-input100"></span> <span class="symbol-input100"> <i class="fa fa-lock"></i> </span> </div> <div class="container-login100-form-btn p-t-10"> <button class="login100-form-btn login-btn">Login</button> </div> <div class="container-login100-form-btn p-t-10" style="display: none;margin-top: 50px;" id="updateLicense"> <form enctype="multipart/form-data" style="display: none;"> <input id="license" type="file" name="file" > </form> <button class="login100-form-btn" id="submitLicense">更新许可证</button> </div> </div> </div> </div> <script type="text/javascript" src="../../static/js/tools/main.min.js"></script> <script type="text/javascript" src="../../static/js/jquery/jquery-3.3.1.min.js"></script> <script type="text/javascript" src="../../static/js/tools/md5.js"></script> <script type="text/javascript" src="../../static/layer/layer.js"></script> <script type="text/javascript" src="../../static/js/common.js"></script> <script> // remember pwd $(function () { var oldUserName = localStorage.getItem('oldUserName'); var oldPass = localStorage.getItem('oldPass'); if(oldUserName){ $('#username').val(oldUserName); } if(oldPass){ $('#password').val(oldPass); } }) window.onload = function(){document.getElementById("username").focus();} $(document).on('click','.login-btn', function () { let username = $("#username").val(); if (username === "") { layer.tips('请输入登录账号', '#username', {tips: [4, '#ff0000']}); return; } let password = $("#password").val(); if (password === "") { layer.tips('请输入密码', '#password', {tips: [4, '#ff0000']}); return; } $.ajax({ url: baseUrl+"/login.action", data: { username: username, password: hex_md5(password) }, method: 'POST', success: function (res) { if (res.code === 200){ localStorage.setItem("token", res.data.token); localStorage.setItem("username", res.data.username); window.location.href = "../index.html"; } else if (res.code === 10001) { layer.tips(res.msg, '#username', {tips: [4, '#ff0000']}); } else if (res.code === 10002) { layer.tips(res.msg, '#username', {tips: [4, '#ff0000']}); } else if (res.code === 10003) { layer.tips(res.msg, '#password', {tips: [4, '#ff0000']}); } else if (res.code == 20001) { layer.tips(res.msg, '.login-btn', {tips: [3, '#ff0000']}); $("#updateLicense").show() } else { layer.tips(res.msg, '.login-btn', {tips: [3, '#ff0000']}); } } }); }); $('body').keydown(function () { if (event.keyCode === 13) { $(".login-btn").click(); } }); //更新许可证 $("#submitLicense").on("click",() => { $("#license").click() }) //上传并更新许可证 $("#license").on("change",(evt) => { var files = evt.target.files; let formData = new FormData(); formData.append("file", files[0]) $.ajax({ url: baseUrl+"/license/updateLicense", headers: {'token': localStorage.getItem('token')}, data: formData, method: 'POST', cache: false, processData: false, contentType: false, success: function (res) { if (res.code == 200) { layer.msg('更新成功', {time: 1000}, () => { parent.location.reload() }); }else{ layer.msg(res.msg,{time:2000},() => { parent.location.reload() }) } } }) }) </script> </body> </html> src/main/webapp/views/index.html
@@ -41,6 +41,9 @@ </li> </ul> <ul class="layui-nav layui-layout-right"> <li class="layui-nav-item" lay-unselect id="licenseShow" style="display: none;user-select: none;"> <div style="color: red;">许可证有效期:<span id="licenseDays">29</span>天</div> </li> <li class="layui-nav-item" lay-unselect> <a ew-event="note" title="便签"><i class="layui-icon layui-icon-note"></i></a> </li> @@ -140,6 +143,23 @@ } }); $.ajax({ url: baseUrl + "/license/getLicenseDays", headers: {'token': localStorage.getItem('token')}, method: 'POST', success: function (res) { if (res.code == 200) { let days = res.data if (days <= 30) { $("#licenseShow").show() $("#licenseDays").html(days) } }else { top.location.href = baseUrl + "/login"; } } }); // 默认加载主页 index.loadHome({ menuPath: baseUrl+'/views/home/navigation.html', src/main/webapp/views/login.html
@@ -87,6 +87,12 @@ <div class="container-login100-form-btn p-t-10"> <button class="login100-form-btn login-btn">Login</button> </div> <div class="container-login100-form-btn p-t-10" style="display: none;margin-top: 50px;" id="updateLicense"> <form enctype="multipart/form-data" style="display: none;"> <input id="license" type="file" name="file" > </form> <button class="login100-form-btn" id="submitLicense">更新许可证</button> </div> </div> </div> </div> @@ -140,6 +146,9 @@ layer.tips(res.msg, '#username', {tips: [4, '#ff0000']}); } else if (res.code === 10003) { layer.tips(res.msg, '#password', {tips: [4, '#ff0000']}); } else if (res.code == 20001) { layer.tips(res.msg, '.login-btn', {tips: [3, '#ff0000']}); $("#updateLicense").show() } else { layer.tips(res.msg, '.login-btn', {tips: [3, '#ff0000']}); } @@ -152,6 +161,38 @@ $(".login-btn").click(); } }); //更新许可证 $("#submitLicense").on("click",() => { $("#license").click() }) //上传并更新许可证 $("#license").on("change",(evt) => { var files = evt.target.files; let formData = new FormData(); formData.append("file", files[0]) $.ajax({ url: baseUrl+"/license/updateLicense", headers: {'token': localStorage.getItem('token')}, data: formData, method: 'POST', cache: false, processData: false, contentType: false, success: function (res) { if (res.code == 200) { layer.msg('更新成功', {time: 1000}, () => { parent.location.reload() }); }else{ layer.msg(res.msg,{time:2000},() => { parent.location.reload() }) } } }) }) </script> </body> </html>