1. ホーム
  2. java

カスタムアノテーションによるAPIデータの暗号化および署名検証

2022-02-23 16:31:41
<パス
  • apiデータデータ署名(MD5,SHA1)
    • シグネチャ列挙クラス
      SginEnum.java
      package com.jx.app.api.framework.annotation.enums;
      
      /**  
      * @ClassName: SginEnum  
      * @Description: TODO (this is a signature enumeration class)  
      * @author gangyu
      * @date Nov 20, 2018 4:30:44 PM  
      */
      public enum SginEnum {
      	//0 no signature required, 1 use MD5 data encryption 2 use SHA data encryption
      	ANY(0), MD5(1), SHA1(2);
      	private final int value;
      
      	private SginEnum(int value) {
      		this.value = value;
      	}
      
      	public int getValue() {
      		return value;
      	}
      }
      
      
      
  • シグネチャーアノテーションクラス
    SginAnot.java
    /**    
    * @Title: SginAnot.java  
    * @Package com.jxkj.app.api.framework  
    * @Description: TODO (describe in one sentence what the file does)  
    * @author gangyu
    * @date Nov 20, 2018 4:07:58 PM  
    * @version V1.0    
    */
    package com.jx.app.api.framework.annotation;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation;
    RetentionPolicy; import java.lang.annotation;
    import java.lang.annotation;
    
    import com.jx.app.api.framework.annotation.enums.SginEnum;
    
    /**  
    * @ClassName: SginAnot  
    * @Description: TODO(signature verification annotation)  
    * @author gangyu
    * @date Nov 20, 2018 4:07:58 PM  
    *    
    */
    @Target({ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface SginAnot {
    	SginEnum type() default SginEnum.ANY;//Default does not require a signature
    }
    
    
    
  • 暗号化ツールクラス
    MD5.java
    package com.jx.common.entrypt;
    
    import java.io.UnsupportedEncodingException;
    import java.math.BigInteger;
    import java.security.MessageDigest;
    import java.security.NoSuchAlgorithmException;
    import java.util.HashMap;
    import java.util.Map;
    
    import org.apache.commons.lang3.StringUtils;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import com.jx.common.utils;
    import com.jx.common.utils.TestEntity;
    
    /**
     * @ClassName: MD5
     * @Description: TODO(MD5 encryption tool)
     * @author gangyu
     * @date Nov 20, 2018 2:12:14 PM
     *
     */
    public class MD5 {
    
    
    	private static final Logger log = LoggerFactory.getLogger(MD5.class);
    
    	public static String PRIVATE_KEY = "This is your key";
    	
        private static final String hexDigIts[] = {"0","1","2","3","4","5","6& quot;,"7","8","9","a","b","c","d","e","f" ;};
    
    	public static String encrypt(String plainText) {
    		try {
    			return encrypt(plainText,true);
    		} catch (UnsupportedEncodingException e) {
    			e.printStackTrace();
    			log.error("MD5 encryption exception:",e);
    			return null;
    		}
    	}
    	
    	/**
    	 * @Title: encrypt
    	 * @Description: TODO (16-bit or 32-bit password)
    	 * @param @param
    	 * plainText
    	 * @param @param
    	 * flag true for 32-bit, false for 16-bit
    	 * @throws UnsupportedEncodingException
    	 */
    	public static String encrypt(String plainText, boolean flag) throws UnsupportedEncodingException {
    		try {
    			if (StringUtils.isEmpty(plainText)) {
    				return null;
    			}
    			MessageDigest md = MessageDigest.getInstance("MD5");
                String encrStr = byteArrayToHexString(md.digest(plainText.getBytes("UTF-8")));
    			if (flag)
    				return encrStr;
    			else
    				return encrStr.substring(8, 24);
    		} catch (NoSuchAlgorithmException e) {
    			e.printStackTrace();
    			return null;
    		}
    
    	}
    
    	@SuppressWarnings("unchecked")
    	public static String encrypt(Object obj){
    		if(obj==null){
    			return null;
    		}
    		Map
    SHA encryption tool class
    
    SHA1.java
    package com.jx.common.entrypt;
    
    import java.io.UnsupportedEncodingException;
    import java.security.MessageDigest;
    import java.security.NoSuchAlgorithmException;
    import java.util.HashMap;
    import java.util.Map;
    
    import org.apache.commons.lang3.StringUtils;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import com.jx.common.utils;
    
    /**  
    * @ClassName: Sha1Util  
    * @Description: TODO(SHA encryption)  
    * @author gangyu
    * @date Nov 20, 2018 2:08:36 PM  
    *    
    */
    public class Sha1 {
    	private static final Logger log = LoggerFactory.getLogger(Sha1.class);
    	public static String encrypt(String str){
    	    if (null == str || 0 == str.length()){
    	        return null;
    	    }
    	    char[] hexDigits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 
    	            'a', 'b', 'c', 'd', 'e', 'f'};
    	    try {
    	        MessageDigest mdTemp = MessageDigest.getInstance("SHA1");
    	        mdTemp.update(new String(str.getBytes("iso8859-1"), "utf-8").getBytes());
    	        byte[] md = mdTemp.digest();
    	        int j = md.length;
    	        char[] buf = new char[j * 2];
    	        int k = 0;
    	        for (int i = 0; i < j; i++) {
    	            byte byte0 = md[i];
    	            buf[k++] = hexDigits[byte0 >>> 4 & 0xf];
    	            buf[k++] = hexDigits[byte0 & 0xf];
    	        }
    	        return new String(buf);
    	    } catch (NoSuchAlgorithmException e) {
    	        e.printStackTrace();
    			log.error("SHA1 encryption exception:",e);
    	    } catch (UnsupportedEncodingException e) {
    	        e.printStackTrace();
    			log.error("SHA1 encryption exception:",e);
    	    }
    		return str;
    	}
    	
    	@SuppressWarnings("unchecked")
    	public static String encrypt(Object obj) {
    		if(obj==null){
    			return null;
    		}
    		Map
    Return data symmetric encryption
    DES.java
    package com.jx.common.entrypt;
    
    import java.security.Key;
    import java.util.Map;
    
    import javax.crypto.Cipher;
    import javax.crypto.SecretKeyFactory;
    import javax.crypto.spec;
    import javax.crypto.spec;
    
    import com.google.gson.Gson;
    import com.jx.common.utils.Base64;
    
    
    /**
    * @ClassName: Des  
    * @Description: TODO(symmetric encryption tool)  
    * @author gangyu
    * @date Nov 20, 2018 1:18:49 PM  
    */
    public class DES {
    	// key
    	private final static String secretKey = "123456789987654321";
    	// vector
    	private final static String iv = "ggboy123";
    	// encoding method used for encryption and decryption unification
    	private final static String encoding = "utf-8";
    
    	/**
    	* @Title: encode
    	* @Description: TODO(encryption)
    	* @param String
    	* @author gangyu2
    	* @date Nov 20, 2018, 1:19:19 PM
    	 */
    	public static String encode(String plainText){
    		Key deskey = null;
    		DESedeKeySpec spec;
    		try {
    			spec = new DESedeKeySpec(secretKey.getBytes());
    			SecretKeyFactory keyfactory = SecretKeyFactory.getInstance("desede");
    			deskey = keyfactory.generateSecret(spec);
    
    			Cipher cipher = Cipher.getInstance("desede/CBC/PKCS5Padding");
    			IvParameterSpec ips = new IvParameterSpec(iv.getBytes());
    			cipher.init(Cipher.ENCRYPT_MODE, deskey, ips);
    			byte[] encryptData = cipher.doFinal(plainText.getBytes(encoding));
    			return Base64.encode(encryptData);
    		} catch (Exception e) {
    			e.printStackTrace();
    			return "";
    		}
    	}
    
    	/**
    	* @Title: decode
    	* @Description: TODO(decode)
    	* @param String
    	* @author gangyu2
    	* @date Nov 20, 2018, 1:19:37 PM
    	 */
    	public static String decode(String encryptText){
    		try{
    
    			Key deskey = null;
    			DESedeKeySpec spec = new DESedeKeySpec(secretKey.getBytes());
    			SecretKeyFactory keyfactory = SecretKeyFactory.getInstance("desede");
    			deskey = keyfactory.generateSecret(spec);
    			Cipher cipher = Cipher.getInstance("desede/CBC/PKCS5Padding");
    			IvParameterSpec ips = new IvParameterSpec(iv.getBytes());
    			cipher.init(Cipher.DECRYPT_MODE, deskey, ips);
    
    			byte[] decryptData = cipher.doFinal(Base64.decode(encryptText));
    
    			return new String(decryptData, encoding);
    		}catch(Exception e){
    			e.printStackTrace();
    			return "";
    		}
    	}
    
    
    }
    
    
    RequestUtil.java
    public class RequestUtil {
    
    	public static <T> T parseRequset(HttpServletRequest request, Class<T> c) {
    
    		T t = null;
    		try {
    			t = c.newInstance();// generate instance object based on reflection
    			Method[] ms = c.getMethods();
    
    			Map<String, String[]> map = request.getParameterMap();
    
    			// map.entrySet() is to take each key-value pair // out of the map and encapsulate it into an Entry object to be stored in a Set collection
    			// // Map.Entry<String[],
    			// String> means a generic type that // shows the String[] array and string contained in the Entry, which are // key and value respectively
    
    			for (Map.Entry<String, String[]> entry : map.entrySet()) {
    				String key = entry.getKey();
    				String[] values = entry.getValue();
    				if (values ! = null && values.length > 1) {
    					continue;
    				}
    				String v = values[0];
    				key = "set" + key;
    
    				for (Method m : ms) {
    					if (key.equalsIgnoreCase(m.getName())) {
    						String parameterTypeName = m.getParameterTypes()[0].getName();
    						if ("int".equals(parameterTypeName) || "java.lang.Integer".equals(parameterTypeName)) {
    							m.invoke(t, Integer.parseInt(v)));
    
    						} else if ("float".equals(parameterTypeName) || "java.lang.Float".equals(parameterTypeName)) {
    							m.invoke(t, Float.parseFloat(v));
    						} else if ("double".equals(parameterTypeName) || "java.lang.Double".equals(parameterTypeName)) {
    							m.invoke(t, Double.parseDouble(v));
    						} else if ("long".equals(parameterTypeName) || "java.lang.Long".equals(parameterTypeName)) {
    							m.invoke(t, Long.parseLong(v));
    						} else if ("short".equals(parameterTypeName) || "java.lang.Short".equals(parameterTypeName)) {
    							m.invoke(t, Short.parseShort(v));
    						} else if ("java.lang.String".equals(parameterTypeName)) {
    							m.invoke(t, v);
    						}
    						break;
    					}
    				}
    			}
    		} catch (Exception e) {
    			e.printStackTrace();
    			throw new RuntimeException(e);
    		}
    
    		return t;
    
    	}
    	
    	public static Map<String,Object> parseRequset(HttpServletRequest request) {
    
    		Map<String,Object> resultMap = new HashMap<String,Object>();
    		try {
    
    			Map<String, String[]> map = request.getParameterMap();
    
    			// map.entrySet() is to take each key-value pair // out of the map and encapsulate it into an Entry object to be stored in a Set collection
    			// // Map.Entry<String[],
    			// String> means a generic type that // shows the String[] array and string contained in the Entry, which are // key and value respectively
    
    			for (Map.Entry<String, String[]> entry : map.entrySet()) {
    				String key = entry.getKey();
    				String[] values = entry.getValue();
    				if (StringUtils.isEmpty(values[0])) {
    					continue;
    				}
    				String v = values[0];
    				resultMap.put(key, v);
    			}
    		} catch (Exception e) {
    			e.printStackTrace();
    			throw new RuntimeException(e);
    		}
    
    		return resultMap;
    
    	}
    }
    
    
    
    BeanUtil.java
    package com.jx.common.utils;
    
    import java.beans;
    import java.beans.Introspector;
    import java.beans.PropertyDescriptor;
    import java.lang.reflect;
    import java.lang.reflect;
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util;
    HashMap; import java.util;
    List; import java.util;
    import java.util.Map;
    import java.util.Map.Entry;
    
    import org.apache.commons.beanutils;
    import org.apache.commons.beanutils.PropertyUtilsBean;
    import org.apache.commons.lang3;
    
    public class BeanUtil {
    
    	// Map --> Bean 2: Using org.apache.commons.beanutils tool class to implement Map --> Bean
    	public static void transMap2Bean2(Map
     T mapToEntity(Map
     entity) {
    		T t = null;
    		try {
    			t = entity.newInstance();
    			for(Field field : entity.getDeclaredFields()) {
    				if (map.containsKey(field.getName())) { if (map.containsKey(field.getName())) {
    					boolean flag = field.isAccessible();
    		            field.setAccessible(true);
    		            Object object = map.get(field.getName());
    		            if (object!= null && field.getType().isAssignableFrom(object.getClass())) {
    		            	 field.set(t, object);
    					}
    		            field.setAccessible(flag);
    				}
    			}
    			return t;
    		} catch (InstantiationException e) {
    			e.printStackTrace();
    		} catch (IllegalAccessException e) {
    			e.printStackTrace();
    		}
    		return t;
    
    	}	
    
    }
    
    
    Interceptor
    AppInterceptor.java
    package com.jx.app.api.framework.interceptor;
    
    import java.util.Map;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.apache.commons.lang3.StringUtils;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.web.method.HandlerMethod;
    import org.springframework.web.servlet.HandlerInterceptor;
    
    import com.google.gson;
    import com.jx.app.api.framework.annotation.LoginAnot;
    import com.jx.app.api.framework.annotation.SginAnot;
    import com.jx.app.api.framework.annotation.annums.Auth;
    import com.jx.app.api.framework.annotation.enums;
    import com.jx.common.entrypt.MD5;
    import com.jx.common.entrypt;
    import com.jx.common.token.ServiceException;
    import com.jx.common.token.TokenException;
    import com.jx.common.token.TokenUtil;
    import com.jx.common.utils.Constants;
    import com.jx.common.utils.RequestUtil;
    import com.jx.common.utils.Result;
    import com.jx.common.utils.enums.CodeEnum;
    import com.jx.core.api.model.BaseModel;
    
    /**  
    * @ClassName: AppInterceptor  
    * @Description: TODO(interceptor)  
    * @author gangyu
    * @date Nov 20, 2018 4:10:55 PM  
    *    
    */
    public class AppInterceptor implements HandlerInterceptor{
        private final static Logger LOGGER = LoggerFactory.getLogger(AppInterceptor.class);
    	
    	private static final String CONTENT_TYPE="text/json;charset=UTF-8";
    	
    	@Override
    	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
    			throws Exception {
    		  if (handler.getClass().isAssignableFrom(HandlerMethod.class)) {
    			  	//Sign the validation annotation
    	        	SginAnot signAnot = ((HandlerMethod) handler).getMethodAnnotation(SginAnot.class);
    	        	
    	        	//check the sign
    	        	if(signAnot!=null && !signCheck(request,signAnot.type())){
                		response.setContentType(CONTENT_TYPE);
                    	response.getWriter().print(new Gson().toJson(new Result(CodeEnum.SIGN_FAIL)));
                    	return false;
    	        	}
    				return true;
    		  }else{
    				return true;
    		  }
    	}
    
    	private boolean signCheck(HttpServletRequest request,SginEnum enumm){
    		Map
    Uniform return object
    Result.java
    package com.jx.common.utils;
    
    
    import java.io;
    
    import com.google.gson;
    import com.jx.common.entrypt;
    import com.jx.common.utils.enums.CodeEnum;
    
    /**
     * Resulting DTO
     * @lastModified
     * @history
     */
    
    public class Result implements Serializable{
    	private static final long serialVersionUID = 1L;
    
    	/**
    	 * Result details
    	 */
    	private String msg;
    
    	/**
    	 * The data that needs to be passed back to the page
    	 */
    	private Object data;
    	
    	/**
    	 * Status code
    	 */
    	private String code;
    	
    	/**
    	 * Encryption
    	 */
    	private boolean encrypt;
    	
    	/**
    	 * Icon
    	 */
    	private Integer icon;
    
    	public boolean isEncrypt() {
    		return encrypt;
    	}
    
    	public void setEncrypt(boolean encrypt) {
    		this.encrypt = encrypt;
    	}
    
    	public String getMsg() {
    		return msg;
    	}
    
    	public void setMsg(String msg) {
    		this.msg = msg;
    	}
    
    	public Result() {
    
    	}
    
    	public Result(CodeEnum enums) {
    		this.msg = enums.getMsg();
    		this.encrypt = enums.getEncrypt();
    		this.code = enums.getCode();
    		this.icon = enums.getIcon();
    	}
    
    	public Result(CodeEnum enums,Object data) {
    		this.msg = enums.getMsg();
    		this.encrypt = enums.getEncrypt();
    		this.code = enums.getCode();
    		this.icon = enums.getIcon();
    		if(enums.getEncrypt()){
    			this.data=DES.encode(new Gson().toJson(data));
    		}else{
    			this.data=data;
    		}
    	}
    
    	public Object getData() {
    		return data;
    	}
    
    	public void setData(Object data) {
    		this.data = data;
    	}
    
    
    	public String getCode() {
    		return code;
    	}
    
    	public void setCode(String code) {
    		this.code = code;
    	}
    
    	public Integer getIcon() {
    		return icon;
    	}
    
    	public void setIcon(Integer icon) {
    		this.icon = icon;
    	}
    
    	public static Result success(CodeEnum enums) {
    		Result dto = new Result();
    		dto.setMsg(enums.getMsg());
    		dto.setEncrypt(enums.getEncrypt());
    		dto.setCode(enums.getCode());
    		dto.setIcon(enums.getIcon());
    		return dto;
    	}
    	
    	public static Result success(CodeEnum enums,Object data) {
    		Result dto = new Result();
    		dto.setData(data);
    		dto.setEncrypt(enums.getEncrypt());
    		dto.setCode(enums.getCode());
    		dto.setIcon(enums.getIcon());
    		if(enums.getEncrypt()){
    			dto.setData(DES.encode(new Gson().toJson(data))));
    		}else{
    			dto.setData(data);
    		}
    		return dto;
    	}
    	
    	public static Result fail(String msg) {
    		Result dto = new Result();
    		dto.setMsg(msg);
    		dto.setEncrypt(false);
    		dto.setCode("1");
    		dto.setIcon(SysCode.ICON.ICON_FAIL);
    		return dto;
    	}
    	
    
    }
    
    
    
    Status code enumeration class
    CodeEnum.java
    package com.jx.common.utils.enums;
    /**  
    * @ClassName: ExceptionEnum  
    * @Description: TODO(system code)  
    * @author gangyu
    * @date Nov 21, 2018 5:22:32 PM  
    */
    public enum CodeEnum {
    	// system code
        SYS_EXCEPTION("999",false,"system exception",'fail'),
        SUCCESS("0",false,"success",'success'),
        ENCRYPT("0",true,"success",'success'),
        FAIL("1",false,"failed",'fail'),
        SIGN_FAIL("1",false,"signature incorrect",'fail'),
        DATA_EMPTY("0",false,"No data available",'success'),
        ;
    
        private String code;
        
        private String msg;
        
        private Boolean encrypt;
        
        private Integer icon;
    
        CodeEnum(String code,Boolean encrypt, String msg,Integer icon) {
            this.code = code;
            this.encrypt = encrypt;
            this.msg = msg;
            this.icon = icon;
        }
    
        public Integer getIcon() {
    		return icon;
    	}
    
    	public String getCode() {
            return code;
        }
    
        public String getMsg() { return msg; }
            return msg;
        }
    
    	public Boolean getEncrypt() {
    		return encrypt;
    	}
        
    }
    
    Controller layer using signature annotations
    	@RequestMapping(value="encryptEntity",provides = "application/json;charset=UTF-8",method=RequestMethod.POST)
        @SginAnot(type = SginEnum.MD5)
        public Object encryptEntity(TestEntity test){
            return businessService.encryptEntity(test);
        }
    
    The checkmark cryptographic sorting based on the ASII table is implemented in the BeanUtil.java class
    url?a=1&c=2&b=3.... ->After sorting a=1&b=3&c=2 then encrypt the data The two sides should be sorted in the same way of course for security you can add your own key after sorting and encrypt once
    Result.java provides the return data encryption method
    CodeEnum.ENCRYPT
    DES symmetric encryption is used here