使用自定义注解标记加密字段

BASE

Posted by lijian on September 4, 2019

简介

最近在处理对接易宝支付。易宝支付有的接口需要传递签名(hmac 字段),但是每个接口的签名字段不一样,所以每个接口都需要传递一个string 数组,用来对数组中的字段进行签名,并且签名字段是有顺序的。

思路

因为每个接口的参数我都封装了对应的DTO,比如下订单接口,我封装了一个TokenDTO,支付接口,我封装了一个PayDTO,想要定义一个自定义注解,注解标记在字段上。通过对应的参数类反射来获取对应的加密字段。

实现

首先,需要有个注解,标记在字段上。


import java.lang.annotation.*;

/**
 * 标记字段需要被签名
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface HmacField {

    /**
     * 加密字段的顺序,从小到大
     *
     * @return
     */
    int sort();
}


YeePayUtils.java 包含了一些通用的请求以及解析方法,所以将处理直接放在了该帮助类中了,对应的 HamcFieldSortHelper 作为一个内部类处理。

    /**
     * 参与签名的字段缓存 map<类的全路径名,需要签名的字段列表>
     */
    private static Map<String, List<String>> hmacFiledCacheMap = new ConcurrentHashMap<>();

    /**
     * 获取某个类需要加密的字段列表,注意顺序以及对应类的父类字段的顺序
     *
     * @param clazz 参数类,注意父类字段也会获取
     * @return
     */
    public static List<String> getHmacFileds(Class clazz) {
        List<String> res = new ArrayList<>();
        List<Field> fieldList = ReflectionKit.getFieldList(Objects.requireNonNull(clazz));
        String fullName = clazz.getPackage().getName() + clazz.getSimpleName();
        List<String> cacheFields = hmacFiledCacheMap.get(fullName);
        if (CollectionUtils.isNotEmpty(cacheFields)) {
            return cacheFields;
        }
        if (CollectionUtils.isNotEmpty(fieldList)) {
            List<HamcFieldSortHelper> hamcFieldSortHelperList = new ArrayList<>();
            fieldList.stream().filter(field -> field.getAnnotation(HmacField.class) != null).forEach(item -> hamcFieldSortHelperList.add(new HamcFieldSortHelper().setName(item.getName()).setSort(item.getAnnotation(HmacField.class).sort())));
            res = hamcFieldSortHelperList.stream().sorted(Comparator.comparing(HamcFieldSortHelper::getSort)).map(HamcFieldSortHelper::getName).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(res)) {
                hmacFiledCacheMap.put(fullName, res);
            }
        }
        return res;
    }

    /**
     * 因为加密字段有顺序,该类用来帮助排序
     */
    @Data
    @Accessors(chain = true)
    static class HamcFieldSortHelper implements Serializable {
        String name;
        int sort;
    }

使用,在类上标记注解,注意顺序以及父类字段(本想加一个callback 来reset 字段,但是感觉可能用到的情况不会很多,如果有特殊字段以及处理就自行修改list吧)

@Data
@Accessors(chain = true)
@ApiModel(value = "MerchantDTO", description = "门店基类")
public class MerchantDTO extends BaseDTO {

    @HmacField(sort = 1)
    @ApiModelProperty(value = "代理商编号", hidden = true)
    private String parentMerchantNo;

    @HmacField(sort = 2)
    @ApiModelProperty("子商编号")
    private String merchantNo;
}