歡迎您光臨本站 註冊首頁

Springboot如何實現Web系統License授權認證

←手機掃碼閱讀     月球人 @ 2020-06-08 , reply:0

在我們做系統級框架的時候,我們要一定程度上考慮系統的使用版權,不能隨便一個人拿去在任何環境都能用,所以我們需要給我們系統做一個授權認證機制,只有上傳了我們下發的lic文件並驗證通過,才能正常使用,下面就開始一步一步實現這個功能

     1.生成機器碼        

我們首先要做的就是對軟件部署的環境的唯一性進行限制,這裡使用的是macadderss,當然你也可以換成cpu序列編號,並無太大影響,先上代碼

  private static String getMac() {      try {        Enumerationel = NetworkInterface            .getNetworkInterfaces();        while (el.hasMoreElements()) {          byte[] mac = el.nextElement().getHardwareAddress();          if (mac == null)            continue;          String hexstr = bytesToHexString(mac);          return getSplitString(hexstr, "-", 2).toUpperCase();        }      } catch (Exception exception) {        exception.printStackTrace();      }      return null;    }      public static String getMachineCode() throws Exception{      Setresult = new HashSet<>();      String mac = getMac();      result.add(mac);      Properties props = System.getProperties();      String javaVersion = props.getProperty("java.version");      result.add(javaVersion);      String javaVMVersion = props.getProperty("java.vm.version");      result.add(javaVMVersion);      String osVersion = props.getProperty("os.version");      result.add(osVersion);      String code = Encrpt.GetMD5Code(result.toString());      return getSplitString(code, "-", 4);       }

   

這裡進行的操作是取出機器碼,與java版本,jvm,操作系統參數進行混合,並進行MD5操作

     2.進行lic文件的生成        

   

   

這是我生成證書與進行授權證書的界面,可以看到授權證書主要包含三個要素,機器碼,是否永久有效標識,證書時效,我們會將這些數據寫入文本中並進行加密處理,看下生成證書的代碼

  public static void getLicense(String isNoTimeLimit, String licenseLimit, String machineCode, String licensePath, String priavateKeyPath) throws Exception{      String[] liccontent = {          "LICENSEID=yanpeng19940119@gmail.com",          "LICENSENAME=YBLOG使用證書",          MessageFormat.format("LICENSETYPE={0}",isNoTimeLimit),          MessageFormat.format("EXPIREDAY={0}",licenseLimit), //日期採用yyyy-MM-dd日期格式          MessageFormat.format("MACHINECODE={0}",machineCode),          ""      };         //將lic內容進行混合簽名並寫入內容      StringBuilder sign = new StringBuilder();      for(String item:liccontent){        sign.append(item+"yblog");      }      liccontent[5] = MessageFormat.format("LICENSESIGN={0}",Encrpt.GetMD5Code(sign.toString()));      FileUtil.createFileAndWriteLines(licensePath,liccontent);      //將寫入的內容整體加密替換      String filecontent =FileUtil.readFileToString(licensePath);      String encrptfilecontent = Encrpt.EncriptWRSA_Pri(filecontent,priavateKeyPath);      File file = new File(licensePath);      file.delete();      FileUtil.createFile(licensePath,encrptfilecontent);    }

   

這裡我們是將一些信息與特定標識進行拼接然後加密,使用的是RSA加密,我們使用私鑰加密公鑰解密,保證驗證的開放性與生成證書的私密性,密鑰可以使用java自帶的keytool工具進行生成,

教程地址:     http://note.youdao.com/noteshare?id=09e2bfc902b21a335a4505f7946a45c9

在lic文件最後我們加上一個LICENSESIGN參數,對其他信息進行一次加密,防止信息被篡改,生成文件後再對文本進行整體加密

這裡生成密鑰的長度為2048而非1024,所以解密塊長度為256,這裡需要注意下,公鑰加密方法為,為了方便大家,這裡提供下具體加密代碼

  private static final int MAX_ENCRYPT_BLOCK = 117;  private static final int MAX_DECRYPT_BLOCK=256;   public static String EncriptWRSA_Pri(String data,String path) throws Exception{      String encryptData ="";         FileInputStream in = new FileInputStream(path);      KeyStore ks = KeyStore.getInstance("JKS");// JKS: Java KeyStoreJKS,可以有多種類型      ks.load(in, "123".toCharArray());      in.close();         String alias = "yblogkey"; // 記錄的別名      String pswd = "123"; // 記錄的訪問密碼      java.security.cert.Certificate cert = ks.getCertificate(alias);      //獲取私鑰      PrivateKey privateKey = (PrivateKey) ks.getKey(alias, pswd.toCharArray());      //私鑰加密      Cipher cipher = Cipher.getInstance("rsa");      SecureRandom random = new SecureRandom();      cipher.init(Cipher.ENCRYPT_MODE, privateKey, random);         try {        // Cipher cipher = Cipher.getInstance("RSA");        //  cipher.init(Cipher.ENCRYPT_MODE, publicKey);        int length = data.getBytes().length;        int offset = 0;        byte[] cache;        ByteArrayOutputStream outStream = new ByteArrayOutputStream();        int i = 0;        while(length - offset > 0){          if(length - offset > MAX_ENCRYPT_BLOCK){            cache = cipher.doFinal(data.getBytes(), offset, MAX_ENCRYPT_BLOCK);          }else{            cache = cipher.doFinal(data.getBytes(), offset, length - offset);          }          outStream.write(cache, 0, cache.length);          i++;          offset = i * MAX_ENCRYPT_BLOCK;        }        return encode.encode(outStream.toByteArray());      } catch (IllegalBlockSizeException e) {        e.printStackTrace();      } catch (BadPaddingException e) {        e.printStackTrace();      }      return encryptData;    }      public static String DecriptWithRSA_Pub(String data,String path) throws Exception{      X509Certificate x509Certificate = (X509Certificate) getCertificate(path);      // 獲得公鑰      PublicKey publicKey = x509Certificate.getPublicKey();         Cipher cipher = Cipher.getInstance("rsa");      SecureRandom random = new SecureRandom();         byte[] bEncrypt = decoder.decodeBuffer(data);      //公鑰解密      cipher.init(Cipher.DECRYPT_MODE, publicKey, random);      String decryptData = "";      // byte[] plainData = cipher.doFinal(bEncrypt);      // System.out.println("11111:"+new String(plainData));      int inputLen = bEncrypt.length;      ByteArrayOutputStream out = new ByteArrayOutputStream();      int offSet = 0;      byte[] cache;      int i = 0;      // 對數據分段解密      while (inputLen - offSet > 0) {        if (inputLen - offSet > MAX_DECRYPT_BLOCK) {          cache = cipher.doFinal(bEncrypt, offSet, MAX_DECRYPT_BLOCK);        } else {          cache = cipher.doFinal(bEncrypt, offSet, inputLen - offSet);        }        out.write(cache, 0, cache.length);        i++;        offSet = i * MAX_DECRYPT_BLOCK;      }      byte[] decryptedData = out.toByteArray();      out.close();      return new String(decryptedData);    }

   

     3.驗證lic        

我們會在系統中註冊一個攔截器,未通過系統授權認證會自動跳轉到lic文件上傳界面,springboot接收文件與常規java有一些不同,使用的MultipartFile對象,會獲取到上傳文件的數組,進行操作,看下保存上傳lic文件代碼

  @RequestMapping(value="/login/licenseauth",method= RequestMethod.POST)    @ResponseBody    public Maplicenseauth(MultipartHttpServletRequest multiReq){      Mapmap = new HashMap();      try {        String savePath = ResourceUtils.getURL("src/main/resources/static/lic").getPath();        MultipartFile file = multiReq.getFile("file");        String filename = file.getOriginalFilename();        File uploadfile = new File(savePath + "" + filename);        if (!uploadfile.exists()){          //獲取item中的上傳文件的輸入流          InputStream in = file.getInputStream();          //創建一個文件輸出流          FileOutputStream out = new FileOutputStream(savePath + "" + filename);          //創建一個緩衝區          byte buffer[] = new byte[1024];          //判斷輸入流中的數據是否已經讀完的標識          int len = 0;          //循環將輸入流讀入到緩衝區當中,(len=in.read(buffer))>0就表示in裡面還有數據          while((len=in.read(buffer))>0){            //使用FileOutputStream輸出流將緩衝區的數據寫入到指定的目錄(savePath + "" + filename)當中            out.write(buffer, 0, len);          }          //關閉輸入流          in.close();          //關閉輸出流          out.close();        }        map.put("executestatus","1");         }catch (Exception e){        e.printStackTrace();        map.put("executestatus","0");      }         return map;    }

   

有了上傳文件,我們就可以通過系統內置的公鑰對lic文件的機器碼,授權時間進行驗證,確定是否能正常訪問系統

  public static boolean authLicense() throws Exception{      boolean isauth = false;      String pubkpath = ResourceUtils.getURL("src/main/resources/static/lic/").getPath()+"yblog.crt";      String licpath = ResourceUtils.getURL("src/main/resources/static/lic/").getPath();      File lic = new File(licpath);      String[] filelist = lic.list();      if (filelist.length>0){        for (int i = 0; i < filelist.length; i++) {          if (filelist[i].contains(".lic")){            File readfile = new File(licpath + filelist[i]);            if (readfile.isFile()) {              String liccontent = FileUtil.readFileToString(readfile);              String decriptliccontent = Encrpt.DecriptWithRSA_Pub(liccontent,pubkpath);              HashMapprops = genDataFromArrayByte(decriptliccontent.getBytes());              String licenseid = props.get("LICENSEID");              String licensename= props.get("LICENSENAME");              String licensetype = props.get("LICENSETYPE");              String liclimit = props.get("EXPIREDAY");              String machinecode = props.get("MACHINECODE");              String lincensesign = props.get("LICENSESIGN");              //驗證簽名              String allinfogroup = "LICENSEID="+licenseid+"yblog"+"LICENSENAME="+licensename+"yblog"+                  "LICENSETYPE="+licensetype+"yblog"+"EXPIREDAY="+liclimit+"yblog"+"MACHINECODE="+machinecode+"yblogyblog";              if (lincensesign.equals(Encrpt.GetMD5Code(allinfogroup))){                //驗證機器碼                if (getMachineCode().equals(machinecode)){                  SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");                  Date bt=new Date();                  Date et=sdf.parse(liclimit);                  //驗證時間                  if(bt.compareTo(et)<=0){                    isauth = true;                    System.out.println("註冊文件:"+filelist[i]+",已通過驗證");                    break;                  }else{                    System.out.println("證書過期");                  }                }else{                  System.out.println("機器碼不一致");                }              }else{                System.out.println("簽名不一致");              }            }          }        }      }else{        System.out.println("未上傳證書");      }      return isauth;    }

   


[月球人 ] Springboot如何實現Web系統License授權認證已經有262次圍觀

http://coctec.com/docs/java/show-post-237494.html