Custom annotation encryption, decryption and desensitization


Define custom annotations

@Documented
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Order(Ordered.HIGHEST_PRECEDENCE)
public @interface PrivateData {

}Copy the code
@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Order(Ordered.HIGHEST_PRECEDENCE)
public @interface PrivateDataMethod {

}Copy the code

Start by defining two custom annotations, privateData and privateDataMethod, to define the @target attribute as FIELD and METHOD, respectively.

Constructing AOP logic

  • Declare a pointcut

      @Pointcut("@annotation(com.max.base.services.annotation.PrivateDataMethod)")
      public void annotationPointCut() {
      }Copy the code

    Enter any method that adds the @privateDatamethod annotation.

  • Claim notification

    @Around("annotationPointCut()") public Object around(ProceedingJoinPoint joinPoint) { Object responseObj = null; try { Object[] request = joinPoint.getArgs(); for (Object object : request) { if (object instanceof Collection) { Collection collection = (Collection) object; collection.forEach(var -> { try { handleEncrypt(var); } catch (IllegalAccessException e) { e.printStackTrace(); }}); } else { handleEncrypt(object); } } responseObj = joinPoint.proceed(); if (responseObj instanceof Collection) { Collection collection = (Collection) responseObj; collection.forEach(var -> { try { handleDecrypt(var); } catch (IllegalAccessException e) { e.printStackTrace(); }}); } else { handleDecrypt(responseObj); } } catch (Throwable throwable) { throwable.printStackTrace(); Log. error("SecureFieldAop exception {}", throwable); } return responseObj; }Copy the code

    Declare Aroud to inform the method of the input and output of the object, if the object is not a collection of direct encryption and decryption, otherwise split the collection, one by one operation

  • Processing encryption and decryption

@param requestObj */ private void handleEncrypt(Object requestObj) throws IllegalAccessException {if (Objects.isNull(requestObj)) { return; } Field[] fields = requestObj.getClass().getDeclaredFields(); for (Field field : fields) { boolean hasSecureField = field.isAnnotationPresent(PrivateData.class); if (hasSecureField) { Boolean accessible = field.isAccessible(); if (! accessible) { field.setAccessible(true); } String plaintextValue = (String) field.get(requestObj); String encryptValue = AseUtil.encrypt(plaintextValue, secretKey); field.set(requestObj, encryptValue); if (! accessible) { field.setAccessible(false); }}}}Copy the code

Get the list of fields for the object through reflection, execute the encryptValue() method on fields with the @privateData annotation and override the original Field with an encrypted string. The decryption logic is similar to encryption.

test

  • Identify the INSERT () method as the one that needs to be encrypted

    public interface CmTenantMapper {
      int deleteByPrimaryKey(Long id);
    
      @PrivateDataMethod
      int insert(CmTenant record);
    
      int insertSelective(CmTenant record);
    
      CmTenant selectByPrimaryKey(Long id);
    
      int updateByPrimaryKeySelective(CmTenant record);
    
      int updateByPrimaryKey(CmTenant record);
    }Copy the code
  • Annotate the fields in the incoming object that need to be encrypted

    public class CmTenant {
      private Long id;
      private String tenantId;
      @PrivateData
      private String tenantName;
      private String createBy;
      private Date createDate;
      private String updateBy;
      private Date updateDate;
      private String remarks;
      private Byte delFlag;
    //set get...Copy the code
  • Call the INSERT method to view the data save result incoming object

    {"createBy": "not happy ", "delFlag": "NOTDELETE"," Remarks ": "test encryption ", "tenantId": "996", "tenantName": "UpdateBy ":" Coke is not fun "}Copy the code

    Database save object

  • The decryption test is not commented, so try it yourself

Desensitization logic

The desensitization logic is basically the same as encryption and decryption. It should be noted that desensitization annotations need to add type

@Documented
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Order(Ordered.HIGHEST_PRECEDENCE)
public @interface MaskingField {
    MaskingTypeEnum type();
}Copy the code

Define the classification of desensitization in MaskingTypeEnum

Public enum MaskingTypeEnum {/* ID number */ ID_CARD, /* mobile number */ PHONE, /* ADDRESS */ ADDRESS, /* NAME */ NAME}Copy the code

Identifies the type of a field when MaskingTypeEnum is used

    @MaskingField(type = MaskingTypeEnum.NAME)
    private String cpName;Copy the code

Follow-up ~~bug~~ function everyone research, peace~

This article is published by OpenWrite!