spring security 通過外部配置適配bcrypt和sm2兩種加密方式自由切換

1、引入依賴

      <dependency>
        <groupId>org.bouncycastle</groupId>
        <artifactId>bcprov-jdk15on</artifactId>
        <version>1.63</version>
      </dependency>
      <dependency>
        <groupId>cn.hutool</groupId>
        <artifactId>hutool-all</artifactId>
        <version>5.3.10</version>
        <scope>compile</scope>
      </dependency>
      <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.12</version>
        <scope>compile</scope>
      </dependency>

2、加密工具相關類

1) SM2KeyPair.java

import lombok.AllArgsConstructor;
import lombok.Data;

/**
 * 描述:
 * 時間: 2021/12/11 12:16 PM
 *
 * @author snake
 */
@Data
@AllArgsConstructor
public class SM2KeyPair {

  /**
   * 公鑰
   */
  private String publicKey;

  /*vue js端 公鑰*/
  private String publicQKey;
  /**
   * 私鑰
   */
  private String privateKey;

}

2)、SM2Util.java

import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SmUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.SM2;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;

/**
 * 描述:
 * 時間: 2021/12/11 12:16 PM
 *
 * @author snake
 */
public class SM2Util {

  /*生成密鑰對*/
  public static SM2KeyPair getSm2KeyPair() {
    SM2 sm2= SmUtil.sm2();
    /*公鑰*/
    String publickey=sm2.getPublicKeyBase64();
    /* js端公鑰 JS代碼實現 SM2的方案,都是直接使用的私鑰的d值和公鑰的q值直接進行的加解密所以後端口返回的最好是從公鑰裏面提取的q值,以q值做爲js端的加密公鑰*/
    String publicQkey = HexUtil.encodeHexStr(((BCECPublicKey)sm2.getPublicKey()).getQ().getEncoded(false));
    /*私鑰*/
    String privatekey=sm2.getPrivateKeyBase64();
    return new SM2KeyPair(publickey,publicQkey,privatekey);
  }

  /*公鑰加密*/
  public static String encrypt(String data, String publickey) {
    SM2 sm2=SmUtil.sm2(null,publickey);
    String encryptStr = sm2.encryptBcd(data, KeyType.PublicKey);
    return encryptStr;
  }

  /*私鑰解密 公鑰加密密文*/
  public static String decrypt(String encryptStr, String privatekey){
    if(!encryptStr.startsWith("04")){
      encryptStr="04".concat(encryptStr);
    }
    SM2 sm2=SmUtil.sm2(privatekey,null);
    String decryptStr = StrUtil.utf8Str(sm2.decryptFromBcd(encryptStr, KeyType.PrivateKey));
    return decryptStr;
  }

  /** 私鑰簽名*/
  public static String signByPrivateKey(String data, String privatekey){
    SM2 sm2= SmUtil.sm2(privatekey,null);
    String sign = sm2.signHex(HexUtil.encodeHexStr(data));
    return sign;
  }

  /**公鑰驗籤*/
  public static boolean verifyByPublicKey(String data, String publickey, String signature){
    SM2 sm2= SmUtil.sm2(null,publickey);
    boolean verify = sm2.verifyHex(HexUtil.encodeHexStr(data), signature);
    return verify;
  }

  public static void main(String[] args) {
    //生成一對公私鑰
    SM2KeyPair sm2KeyPair = getSm2KeyPair();
    
    String publicKey = sm2KeyPair.getPublicKey();
    String privateKey = sm2KeyPair.getPrivateKey();
    System.out.println("公鑰:"+sm2KeyPair.getPublicKey());
    System.out.println("私鑰:"+sm2KeyPair.getPrivateKey());

    String data = "123123";
    String encrypt = encrypt(data, publicKey);
    System.out.println("加密後內容:"+encrypt);
    String decrypt = decrypt(encrypt, privateKey);

    System.out.println("解密後內容:"+decrypt);

  }
}

 3、spring security 加密類適配

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;

/**
 * 描述:
 * 時間: 2021/12/9 2:59 PM
 *
 * @author snake
 */
@Component
@ConditionalOnProperty(name = "passwordEncoder",havingValue = "bcrypt")
@Slf4j
public class DefaultPasswordEncoder extends BCryptPasswordEncoder implements PasswordEncoder {

}
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;

/**
 * 描述:
 * 時間: 2021/12/8 10:18 PM
 *
 * @author snake
 */
@Component
@ConditionalOnProperty(name = "passwordEncoder",havingValue = "sm2")
@Slf4j
public class SM2PasswordEncoder implements PasswordEncoder {

  @Value("${sm2.public.key}")
  private String publicKey;

  @Value("${sm2.private.key}")
  private String privateKey;

  @Override
  public String encode(CharSequence charSequence) {
    log.info("SM2PasswordEncoder encode............");
    return SM2Util.encrypt(charSequence.toString(),publicKey);
  }

  @Override
  public boolean matches(CharSequence charSequence, String s) {
    log.info("SM2PasswordEncoder matches...........");
    String decrypt = SM2Util.decrypt(s, privateKey);
    return charSequence.toString().equals(decrypt);
  }
}

4、application.properties外部配置加密方式

passwordEncoder=bcrypt
sm2.public.key=MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEB/yGrVu52u/Jqd1zrMullpTKitVsE7vsHbFLM3KcRL2qzF1x6HERPWVnYeoO/EmxETuPsJ9NBw3HrM5ux6yhKg==
sm2.private.key=MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgDVlZriDVsfMkOeZmC2Z2CrHkA78LXziQ5JvC+CXdZ+igCgYIKoEcz1UBgi2hRANCAAQH/IatW7na78mp3XOsy6WWlMqK1WwTu+wdsUszcpxEvarMXXHocRE9ZWdh6g78SbERO4+wn00HDceszm7HrKEq

 

5、在使用加密 的業務代碼塊注入PasswordEncoder

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章