当前位置: 移动技术网 > IT编程>开发语言>Java > Springboot如何实现Web系统License授权认证

Springboot如何实现Web系统License授权认证

2020年06月23日  | 移动技术网IT编程  | 我要评论

红点设计大奖,李洋子,剑灵宠物美容师

在我们做系统级框架的时候,我们要一定程度上考虑系统的使用版权,不能随便一个人拿去在任何环境都能用,所以我们需要给我们系统做一个授权认证机制,只有上传了我们下发的lic文件并验证通过,才能正常使用,下面就开始一步一步实现这个功能

1.生成机器码

我们首先要做的就是对软件部署的环境的唯一性进行限制,这里使用的是macadderss,当然你也可以换成cpu序列编号,并无太大影响,先上代码

private static string getmac() {
    try {
      enumeration<networkinterface> el = 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{
    set<string> result = 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工具进行生成,

教程地址:

在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 map<object,object> licenseauth(multiparthttpservletrequest multireq){
    map<object,object> map = new hashmap<object,object>();
    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);
            hashmap<string, string> props = 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;
  }

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网