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

在我们做系统级框架的时候,我们要一定程度上考虑系统的使用版权,不能随便一个人拿去在任何环境都能用,所以我们需要给我们系统做一个授权认证机制,只有上传了我们下发的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工具进行生成,

教程地址: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 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;
  }

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

(0)

相关推荐

  • 运用springboot搭建并部署web项目的示例

    前言 一直以来都是用springmvc+mybatis进行后端接口开发工作,最近闲来无事,根据现有功能需求,用springboot+mybatis部署一套简单的web项目. 所用工具 IntelliJ IDEA 2018.1.4 JDK 1.8 apache-tomcat-8.0.50 所解决的问题 1.如何用idea创建springboot项目 2.如何进行 服务器.数据库.mybatis.视图解析器的配置 3.如何使用mybatis generator 自动生成代码 4.如何使用multip

  • SpringBoot+WebSocket+Netty实现消息推送的示例代码

    上一篇文章讲了Netty的理论基础,这一篇讲一下Netty在项目中的应用场景之一:消息推送功能,可以满足给所有用户推送,也可以满足给指定某一个用户推送消息,创建的是SpringBoot项目,后台服务端使用Netty技术,前端页面使用WebSocket技术. 大概实现思路: 前端使用webSocket与服务端创建连接的时候,将用户ID传给服务端 服务端将用户ID与channel关联起来存储,同时将channel放入到channel组中 如果需要给所有用户发送消息,直接执行channel组的writ

  • Spring Boot非Web项目运行的方法

    有时候一些项目并不需要提供 Web 服务,例如跑定时任务的项目,如果都按照 Web 项目启动未免画蛇添足浪费资源 为了达到非 Web 运行的效果,首先调整 Maven 依赖,不再依赖 spring-boot-starter-web,转而依赖最基础的 spring-boot-starter: <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactI

  • SpringBoot+WebSocket搭建简单的多人聊天系统

    前言 今天闲来无事,就来了解一下WebSocket协议.来简单了解一下吧. WebSocket是什么 首先了解一下WebSocket是什么?WebSocket是一种在单个TCP连接上进行全双工通信的协议.这是一种比较官方的说法,简单点来说就是,在一次TCP连接中,通信的双方可以相互通信.比如A和B在打电话,A说话的时候,B也可以说话来进行信息的交互,这就叫做全双工通信.对应的是单工通信,和半双工通信,单工通信就是只能由A向B通信,比如电脑和打印机.半双工通信是可以AB可以互相通信,但是同一时间只

  • springboot web项目打jar或者war包并运行的实现

    (一)springboot web项目打jar包 1.打包 两种打包方式 maven命令打包 切换目录到工程根下,pom.xml所在位置,运行maven的打包命令 mvn clean package -Dmaven.test.skip=true IDEA 工具执行maven任务打包 会在xxx项目模块下/target目录下生成xxx-0.0.1-SNAPSHOT.jar 2.运行jar包 启动运行(切换目录到target下,执行命令) F:\Java\idea-workspace\shixun0

  • SpringBoot集成WebSocket实现前后端消息互传的方法

    什么是WebSocket? WebSocket 协议是基于 TCP 的一种新的网络协议.它实现了浏览器与服务器全双工 (full-duplex) 通信-允许服务器主动发送信息给客户端. 为什么需要WebSocket? 大家都知道以前客户端想知道服务端的处理进度,要不停地使用 Ajax 进行轮询,让浏览器隔个几秒就向服务器发一次请求,这对服务器压力较大.另外一种轮询就是采用 long poll 的方式,这就跟打电话差不多,没收到消息就一直不挂电话,也就是说,客户端发起连接后,如果没消息,就一直不返

  • Spring Boot配置接口WebMvcConfigurer的实现

    WebMvcConfigurer配置类其实是Spring内部的一种配置方式,采用JavaBean的形式来代替传统的xml配置文件形式进行针对框架个性化定制.基于java-based方式的spring mvc配置,需要创建一个配置类并实现WebMvcConfigurer 接口,WebMvcConfigurerAdapter 抽象类是对WebMvcConfigurer接口的简单抽象(增加了一些默认实现),但在在SpringBoot2.0及Spring5.0中WebMvcConfigurerAdapt

  • SpringBoot2.0整合WebSocket代码实例

    这篇文章主要介绍了SpringBoot2.0整合WebSocket代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 之前公司的某个系统为了实现推送技术,所用的技术都是Ajax轮询,这种方式浏览器需要不断的向服务器发出请求,显然这样会浪费很多的带宽等资源,所以研究了下WebSocket,本文将详细介绍下. 一.什么是WebSocket? WebSocket是HTML5开始提供的一种在单个TCP连接上进行全双工通讯的协议,能更好的节省服务器资

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

    在我们做系统级框架的时候,我们要一定程度上考虑系统的使用版权,不能随便一个人拿去在任何环境都能用,所以我们需要给我们系统做一个授权认证机制,只有上传了我们下发的lic文件并验证通过,才能正常使用,下面就开始一步一步实现这个功能 1.生成机器码 我们首先要做的就是对软件部署的环境的唯一性进行限制,这里使用的是macadderss,当然你也可以换成cpu序列编号,并无太大影响,先上代码 private static String getMac() { try { Enumeration<Networ

  • 基于springboot搭建的web系统架构的方法步骤

    从接触springboot开始,便深深的被它的简洁性深深的折服了,精简的配置,方便的集成,使我再也不想用传统的ssm框架来搭建项目,一大堆的配置文件,维护起来很不方便,集成的时候也要费力不少.从第一次使用springboot开始,一个简单的main方法,甚至一个配置文件也不需要(当然我是指的没有任何数据交互,没有任何组件集成的情况),就可以把一个web项目启动起来,下面总结一下自从使用springboot依赖,慢慢完善的自己的一个web系统的架构,肯定不是最好的,但平时自己用着很舒服. 1. 配

  • SpringBoot+SpringSecurity+JWT实现系统认证与授权示例

    目录 1. Spring Security简介 2. JWT简介 3. Spring Boot整合Spring Security 4. 配置Spring Security使用JWT认证 5. 实现登录接口 6. 测试 7. 源码 1. Spring Security简介 Spring Security是Spring的一个核心项目,它是一个功能强大且高度可定制的认证和访问控制框架.它提供了认证和授权功能以及抵御常见的攻击,它已经成为保护基于spring的应用程序的事实标准. Spring Boot

  • SpringBoot+SpringSecurity实现基于真实数据的授权认证

    (一)概述 Spring Security是一个功能强大且高度可定制的身份验证和访问控制框架,Spring Security主要做两个事情,认证.授权.我之前写过一篇关于SpringSecurity的博客,但是当时只是介绍了基于mock数据的案例,本期就来介绍一下基于真实数据的认证授权实现. (二)前期项目搭建 为了更好的展示SpringSecurity,我们先搭建一个简单的web项目出来.引入thymeleaf依赖 <dependency> <groupId>org.spring

  • .Net Core授权认证方案JWT(JSON Web Token)初探

    一.前言 现在越来越多的项目或多或少会用到JWT,为什么会出现使用JWT这样的场景的呢? 假设现在有一个APP,后台是分布式系统.APP的首页模块部署在上海机房的服务器上,子页面模块部署在深圳机房的服务器上.此时你从首页登录了该APP,然后跳转到子页面模块.session在两个机房之间不能同步,用户是否需要重新登录? 传统的方式(cookie+session)需要重新登录,用户体验不好.session共享(在多台物理机之间传输和复制session)方式对网络IO的压力大,延迟太长,用户体验也不好

  • Yii2框架RESTful API 格式化响应,授权认证和速率限制三部分详解

    之前写过一篇Yii2框架制作RESTful风格的API快速入门教程,今天接着来探究一下Yii2 RESTful的格式化响应,授权认证和速率限制三个部分 一.目录结构 先列出需要改动的文件.目录如下: web ├─ common │ └─ models │ └ User.php └─ frontend ├─ config │ └ main.php └─ controllers └ BookController.php 二.格式化响应 Yii2 RESTful支持JSON和XML格式,如果想指定返回

  • SpringBoot +Vue开发考试系统的教程

    一.考试系统简介 新鲜出炉的一款SpringBoot +Vue的考试系统,支持多种题型:选择题.多选题.判断题.填空题.综合题以及数学公式.支持在线考试,教师在线批改试卷. 二.项目架构 后端技术栈 SpringBoot: SpringBoot是由Pivotal团队提供的全新框架,其设计目的是用来简化Spring应用的创建.运行.调试.部署等. Mybatis: 一个持久层的框架,与数据库进行交互,将数据持久化到关系型数据库中 Shiro: 一个功能强大且易于使用的Java安全框架,进行身份验证

  • springboot+jwt+springSecurity微信小程序授权登录问题

    场景重现:1.微信小程序向后台发送请求 --而后台web采用的springSecuriry没有token生成,就会拦截请求,,所以小编记录下这个问题 微信小程序授权登录问题 思路 参考网上一大堆资料 核心关键字: 自定义授权+鉴权 (说的通俗就是解决办法就是改造springSecurity的过滤器) 参考文章 https://www.jb51.net/article/204704.htm 总的来说的 通过自定义的WxAppletAuthenticationFilter替换默认的UsernameP

  • springboot整合shiro实现登录验证授权的过程解析

    springboot整合shiro实现登录验证授权,内容如下所示: 1.添加依赖: <!-- shiro --> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.7.1</version> </dependency> 2.yml配置: #配置服务端口 s

  • 浅谈ASP.NET Core 中jwt授权认证的流程原理

    1,快速实现授权验证 什么是 JWT ?为什么要用 JWT ?JWT 的组成? 这些百度可以直接找到,这里不再赘述. 实际上,只需要知道 JWT 认证模式是使用一段 Token 作为认证依据的手段. 我们看一下 Postman 设置 Token 的位置. 那么,如何使用 C# 的 HttpClient 访问一个 JWT 认证的 WebAPI 呢? 下面来创建一个 ASP.NET Core 项目,尝试添加 JWT 验证功能. 1.1 添加 JWT 服务配置 在 Startup.cs 的 Confi

随机推荐