针对APP基于MD5加密验签工具

本文介绍了一种利用MD5签名认证提升APP安全性的方法,通过自定义注解简化参数加密流程,实现高效的数据传输完整性保护。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

小编针对研发工作有一定年限了,在针对APP安全上有很多种方式,在这里我们针对APP基于MD5签名认证及实现上做个描述。

MD5一种被广泛使用的密码散列函数,可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整一致.由于为不可逆所以我们在针对MD5加密的时候一般通过和APP在接口定义数据上进行一定规则的排序后并进行加密操作.有的时候需要加密的参数较多如果我们每次都手动去添加认证对于时间成本上相对消耗较大,为了减少拼接参数进行验证的所以归纳出一个方法(是否可借鉴参考需根据个人需求而决定).

先说下大体逻辑吧.当我们有很多参数需要进行加密的时候,而且加密顺序只有交互双方知道.这个情况下我们可以通过注解的模式进行确定哪些参数进行加密.然后在签名验证的时候进行解析注解后做比对.目前没有针对顺序做处理,如果有需要可以自行补充.下面先上代码

定义注解方法 EntryValidate 用于在参数中进行定义

package com.aibiancheng.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 加密验证:对需要加密的字段进行验证操作
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface EntryValidate {

    /**
     * 是否进行非空验证 默认验证,如果不需要则填写false
     * @return
     */
    public abstract boolean isValidateNull() default true;
}

 

参数案例:TestEntryParams

import com.linli.core.annotation.EntryValidate;

public class TestEntryParams {

    @EntryValidate
    private String userName;

    @EntryValidate
    private String userCode;

    @EntryValidate
    private Byte userSex;

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getUserCode() {
        return userCode;
    }

    public void setUserCode(String userCode) {
        this.userCode = userCode;
    }

    public Byte getUserSex() {
        return userSex;
    }

    public void setUserSex(Byte userSex) {
        this.userSex = userSex;
    }
}

验证方法: 解析EntryValidate注解 EntryValidateUtil<T>

package com.linli.core.common;


import com.linli.common.utils.ObjectUtil;
import com.linli.core.annotation.EntryValidate;
import com.linli.core.exception.CustomException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

/**
 * 参数校验:解析EntryValidate注解
 */
public class EntryValidateUtil<T> {

    private static Logger logger = LoggerFactory.getLogger(EntryValidateUtil.class);


    public  Class<T> clazz;

    /**
     * 构造函数
     * @param clazz
     */
    public EntryValidateUtil(Class<T> clazz) {
        this.clazz = clazz;
    }

    /**
     * 验证枚举类
     * @param t
     * @param signValue
     * @return
     */
    public boolean validate(T t,String signValue){
        try{
            String waitSign = "";
            Field[] allFields = clazz.getDeclaredFields();
            List<Field> fields = new ArrayList<Field>();
            for (Field field : allFields){
                if (field.isAnnotationPresent(EntryValidate.class)){
                    fields.add(field);
                }
            }
            for (int i = 0 ; i <fields.size() ; i ++){
                Field field = fields.get(i);
                field.setAccessible(true);
                EntryValidate entryValidate = field.getAnnotation(EntryValidate.class);
                if(entryValidate.isValidateNull()){
                    if(ObjectUtil.isEmpty(field.get(t))){
                        throw new CustomException("参数不完整");
                    }   
                }
                 if(i == fields.size()-1){
                   waitSign += field.getName()+"="+field.get(t);
                 }else{
                   waitSign += field.getName()+"="+field.get(t)+"&";
                 }
            }
            String sign = MD5SIGN.getMD5Sign(waitSign);
            return sign.equals(signValue);
        }catch (Exception e){
            logger.error("entry validate fail >> e:{}",e);
            throw new CustomException("加密校验失败");
        }
    }

}

MD5签名方法:  MD5SIGN

package com.linli.core.common;

import java.security.MessageDigest;

/**
 * md5签名认证
 */
public class MD5SIGN {

    /**
     * 获取MD5签名
     * @return
     */
    public static String getMD5Sign(String ciphertext){

        System.out.println("getMd5Sign:" + ciphertext);

        if ("".equals(ciphertext) || null == ciphertext || "".equals(ciphertext.trim())) {
            return null;
        }
        char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
        try {
            byte[] btInput = ciphertext.getBytes("utf-8");
            MessageDigest mdInst = MessageDigest.getInstance("MD5");
            mdInst.update(btInput);
            byte[] md = mdInst.digest();
            int j = md.length;
            char str[] = new char[j * 2];
            int k = 0;
            for (int i = 0; i < j; i++) {
                byte byte0 = md[i];
                str[k++] = hexDigits[byte0 >>> 4 & 0xf];
                str[k++] = hexDigits[byte0 & 0xf];
            }
            return new String(str);
        } catch (Exception e) {
            return null;
        }
    }
}

在调用的时候 T替换成自己的对象信息即可

 EntryValidateUtil<T> entryValidateUtil = new EntryValidateUtil<T>(T.class);
if(entryValidateUtil.validate(T,sign)){
  //验证通过处理逻辑
}

 

这样在APP签名验证的时候我们就不需要去为了参数的繁琐而浪费时间了,测试运行结果先用MD5生成一个模拟参数信息

getMd5Sign:userName=123456&userCode=123456&userSex=1
624C7999EBC6CE132D44AE32D4DBB0CA

调用我们的方法去进行测试

 public static void main(String[] args) {
        TestEntryParams entryParams = new TestEntryParams();
        entryParams.setUserCode("123456");
        entryParams.setUserName("123456");
        entryParams.setUserSex((byte)1);
        EntryValidateUtil<TestEntryParams> entryValidateUtil = new EntryValidateUtil<TestEntryParams>(TestEntryParams.class);
        if(entryValidateUtil.validate(entryParams,"624C7999EBC6CE132D44AE32D4DBB0CA")){
            System.out.println("验证通过");
        }
    }

 

 

 

 

 

 

 

 

转载于:https://my.oschina.net/LevelCoder/blog/2872934

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值