Rsa简单实现接口到期限制(springBoot)

生成方法

生成私钥和公钥

java 复制代码
import org.apache.commons.codec.binary.Base64;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;

/**
 * 你本地运行:生成 RSA 公私钥
 */
public class RsaKeyGenerate {
    public static void main(String[] args) throws Exception {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        keyPairGenerator.initialize(2048);
        KeyPair keyPair = keyPairGenerator.generateKeyPair();

        PublicKey publicKey = keyPair.getPublic();
        PrivateKey privateKey = keyPair.getPrivate();

        String pubKey = Base64.encodeBase64String(publicKey.getEncoded());
        String priKey = Base64.encodeBase64String(privateKey.getEncoded());

        System.out.println("=====公钥(给SpringBoot项目)=====");
        System.out.println(pubKey);
        System.out.println("\n=====私钥(你自己保存,不给客户)=====");
        System.out.println(priKey);
    }
}

根据私钥生成加密文件

java 复制代码
import com.alibaba.fastjson.JSON;
import com.jiliason.business.safety.License;
import org.apache.commons.codec.binary.Base64;
import javax.crypto.Cipher;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.time.LocalDateTime;

/**
 * 你本地专用:生成 license.lic 加密文件
 * 设置过期时间、最大可用天数
 */
public class LicenseGenerateTool {

    // 粘贴你刚才生成的私钥
    private static final String PRIVATE_KEY = "生成的私钥";

    // RSA 私钥加密
    public static String encrypt(String content) throws Exception {
        byte[] keyBytes = Base64.decodeBase64(PRIVATE_KEY);
        PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
        PrivateKey privateKey = KeyFactory.getInstance("RSA").generatePrivate(spec);

        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(Cipher.ENCRYPT_MODE, privateKey);
        return Base64.encodeBase64String(cipher.doFinal(content.getBytes()));
    }

    public static void main(String[] args) throws Exception {

        LocalDateTime expireTime = LocalDateTime.now().plusSeconds(600);
        // ========================================

        License license = new License();
        license.setExpireTime(expireTime);

        // 对象转JSON
        String jsonStr = JSON.toJSONString(license);
        // 私钥加密
        String encryptStr = encrypt(jsonStr);

        // 输出加密后的授权内容,你复制保存为 license.lic
        System.out.println("=====生成的license.lic内容=====");
        System.out.println(encryptStr);
    }
}

拦截器实现

定义实体类

java 复制代码
import lombok.Data;
import java.time.LocalDateTime;

@Data
public class License {
    private LocalDateTime expireTime; // 到期时间
}

定义拦截器方法

java 复制代码
@Component
public class AuthInterceptor implements HandlerInterceptor {

    @Value("${safety.useKey}")
    private String useKey;

    @Value("${safety.publicKey}")
    private String publicKey;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        try {
            getLicense();
            return true;
        } catch (Exception e) {
            response.setContentType("application/json;charset=utf-8");
            response.getWriter().write("{\"code\":403,\"msg\":\"产品已过期,请联系开发商续费\"}");
            return false;
        }
    }

    public License getLicense() {
        // 解密
        try {
            String json = decryptByPublicKey(useKey);
            License license = new com.alibaba.fastjson.JSONObject().parseObject(json, License.class);

            // 校验:不能超过到期时间
            if (LocalDateTime.now().isAfter(license.getExpireTime())) {
                throw new RuntimeException("产品已到期!");
            }
            return license;
        } catch (Exception e) {
            throw new RuntimeException("授权文件非法!" + e);
        }
    }

    // 公钥解密
    public  String decryptByPublicKey(String data) throws Exception {
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKey));
        PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(Cipher.DECRYPT_MODE, publicKey);
        return new String(cipher.doFinal(Base64.decodeBase64(data)));
    }
}

使用拦截器

java 复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Autowired
    private AuthInterceptor authInterceptor;
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(authInterceptor)
                .addPathPatterns("/**")
//                .excludePathPatterns("/login", "/static/**");
                .excludePathPatterns("/static/**");
    }
}

注意:

1.如果操作人,修改服务器时间,过期时间就没用了(有下面解决办法)

  • 如果是外网,增加时间校验api,通过校验传递过来的时间和标准时间校验,判断时间是否一致
  • 如果是内网,可以通过查询数据库中标志性数据判断是否修改了系统时间,或者增加文件用来记录最新操作时间

2.增加拦截器进行拦截,每次解密等操作还是比较费性能的,如果token有过期时间,可以在登录的时候进行校验

扩展

增加启动校验

java 复制代码
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

@Component
public class LicenseCheckRunner implements CommandLineRunner {
    @Override
    public void run(String... args) {
       //调用校验代码
    }
}
相关推荐
Java编程爱好者1 小时前
MySQL / PostgreSQL DDL 审核自动化:从人工 review 到 CI 拦截
后端
雨落在了我的手上1 小时前
初识java(二):数据类型与变量
java·开发语言
小闫BI设源码1 小时前
当20个节点选出两个Master时:Elasticsearch的致命故障与解决方案
java·elasticsearch·jenkins·php·面试宝典·深入解析
花花鱼1 小时前
Spring Framework 、Spring Boot 、 Spring Data 、Spring Cloud之间的关系简单说明
spring boot·spring·spring cloud
SamDeepThinking1 小时前
千万级用户购物车系统的架构设计
java·后端·架构
liwulin05061 小时前
【JAVAFX】从ORACLE JDK切换到国内的JDK以便使用JAVAFX功能
java·数据库·oracle
明月_清风1 小时前
Makefile 完全指南:从入门到 CMake 工程化实践
后端·cmake
十年编程老舅1 小时前
深度长文|Linux 图形与显示架构
linux·运维·后端·架构·内核·linux内核·通信机制
平凡但不平庸的码农1 小时前
Go GMP 调度模型详解
开发语言·后端·golang