All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cn.k7g.alloy.expose.AlloyContentHandler Maven / Gradle / Ivy

package cn.k7g.alloy.expose;

import cn.k7g.alloy.exception.AlloyContentDecodeException;
import cn.k7g.alloy.exception.AlloyContentEncodeException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;

/**
 * 加密的内容的处理器,根据key生成内容
 *
 * @author victor-wu
 * @date 2024年4月3日
 */
public abstract class AlloyContentHandler {

    public static final Class[] BASIC_TYPE = {
            Long.class,
            String.class,
            Integer.class,
            long.class,
            int.class,
            Boolean.class,
            boolean.class,
            Byte.class,
            byte.class,
            Double.class,
            double.class,
            Float.class,
            float.class,
            Short.class,
            short.class,};

    @Autowired
    private ObjectMapper objectMapper;

    /**
     * 返回一个匿名情况下的 key,这个通常是固定的一个值,
     * 在没有登录的情况下用户都将使用这个key
     *
     * @return
     */
    public abstract byte[] anonymousOwnerKey();

    /**
     * 数据拥有者,一般为用户ID 或者 租户ID 商户ID等,不可超出32长度
     *
     * @return
     */
    public abstract byte[] ownerKey();

    /**
     * 是否登录,如果已经登录就用  ownerKey  否则就是 anonymousOwnerKey
     *
     * @return
     */
    public abstract boolean isLogin();

    public byte[] getKey() {
        return getKey(false);
    }

    /**
     * 填充KEY,超出范围截断
     *
     * @param forceAny 强制使用匿名key, 不论是否登录都使用匿名key。
     * @return 返回用于加密的key
     */
    public byte[] getKey(boolean forceAny) {
        byte[] key = !forceAny && isLogin() ? ownerKey() : anonymousOwnerKey();
        if (key.length > 32) {
            throw new RuntimeException("alloy key 长度不能超过32");
        }
        if (key.length == 16 || key.length == 24 || key.length == 32) {
            return key;
        }
        if (key.length < 16) {
            return fill(key, 16);
        }
        if (key.length < 24) {
            return fill(key, 24);
        }
        return fill(key, 32);
    }

    public byte[] fill(byte[] key, int len) {
        byte[] nk = new byte[len];
        System.arraycopy(key, 0, nk, 0, key.length);
        for (int i = key.length; i < nk.length; i++) {
            nk[i] = '0';
        }
        return nk;
    }

    /**
     * 解密, 返回解码后的明文
     *
     * @param value 密文
     * @param key   必须是一个AES有效的内容,不做二次处理
     * @return 返回一个解密后的内容
     */
    public static String decode(String value, byte[] key) {
        try {
            SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
            // 创建AES加密器
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            // 解密文本
            cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
            byte[] decryptedBytes = cipher.doFinal(Base64.getUrlDecoder().decode(value));
            return new String(decryptedBytes, StandardCharsets.UTF_8);

        } catch (Exception e) {
            throw new AlloyContentDecodeException("无效的alloy content", e);
        }
    }

    /**
     * 加密, 返回加密后的内容
     *
     * @param originId 原始数据ID
     * @param key      必须是一个AES有效的内容,不做二次处理
     * @return 返回一个加密后的内容
     */
    public static String encode(String originId, byte[] key) {
        try {
            SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
            // 创建AES加密器
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            // 加密文本
            cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
            byte[] encryptedBytes = cipher.doFinal(originId.getBytes(StandardCharsets.UTF_8));
            return Base64.getUrlEncoder().encodeToString(encryptedBytes);
        } catch (Exception e) {
            throw new AlloyContentEncodeException("加密失败", e);
        }
    }

    /**
     * 将AlloyContent转化成对象
     *
     * @param content  密文
     * @param dataType 转化类型
     * @return 解密后的对象
     * @throws JsonProcessingException json解析错误
     */
    public  T decodeObject(String content, Class dataType) throws JsonProcessingException {
        String originContent;
        try {
            originContent = decode(content, getKey());
        } catch (Exception e) {
            // 这里是解密操作,出现的异常只可能是解密失败。
            // 在未登录的情况下访问的数据,登录后再次访问会导致解码结果不一致。
            originContent = decode(content, getKey(true));
        }
        return objectMapper.readValue(originContent, dataType);
    }


//    public Object decodeObject(String content, Class dataType) throws JsonProcessingException {
//        String originContent = decode(content, getKey());
//        if (dataType.isAssignableFrom(Long.class)) {
//            return Long.parseLong(originContent);
//        } else if (dataType.isAssignableFrom(String.class)) {
//            return originContent;
//        } else if (dataType.isAssignableFrom(Integer.class)) {
//            return Integer.parseInt(originContent);
//        } else if (dataType.isAssignableFrom(long.class)) {
//            return Long.parseLong(originContent);
//        } else if (dataType.isAssignableFrom(int.class)) {
//            return Integer.parseInt(originContent);
//        } else if (dataType.isAssignableFrom(Boolean.class)) {
//            return Boolean.parseBoolean(originContent);
//        } else if (dataType.isAssignableFrom(boolean.class)) {
//            return Boolean.parseBoolean(originContent);
//        } else if (dataType.isAssignableFrom(Byte.class)) {
//            return Byte.parseByte(originContent);
//        } else if (dataType.isAssignableFrom(byte.class)) {
//            return Byte.parseByte(originContent);
//        } else if (dataType.isAssignableFrom(Double.class)) {
//            return Double.parseDouble(originContent);
//        } else if (dataType.isAssignableFrom(double.class)) {
//            return Double.parseDouble(originContent);
//        } else if (dataType.isAssignableFrom(Float.class)) {
//            return Float.parseFloat(originContent);
//        } else if (dataType.isAssignableFrom(float.class)) {
//            return Float.parseFloat(originContent);
//        } else if (dataType.isAssignableFrom(Short.class)) {
//            return Short.parseShort(originContent);
//        } else if (dataType.isAssignableFrom(short.class)) {
//            return Short.parseShort(originContent);
//        } else {
//            return objectMapper.readValue(originContent, dataType);
//        }
//    }

    /**
     * 将对象值转化为 AlloyContent
     *
     * @param o
     * @return
     * @throws JsonProcessingException
     */
    public String encodeObject(Object o) throws JsonProcessingException {
//        for (Class cls : BASIC_TYPE) {
//            if (o.getClass().isAssignableFrom(cls)) {
//                return encode(o.toString(), getKey());
//            }
//        }
        return encode(objectMapper.writeValueAsString(o), getKey());
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy