SpringBoot自定义注解API数据加密和签名校验
作者:BeiShangBuZaiLai
这篇文章主要介绍了SpringBoot自定义注解API数据加密和签名校验,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
api数据数据签名(MD5,SHA1)
签名枚举类SginEnum.java
package com.jx.app.api.framework.annotation.enums; /** * @ClassName: SginEnum * @Description: TODO(这是一个签名枚举类) * @author gangyu * @date 2018年11月20日 下午4:30:44 */ public enum SginEnum { //0不需要签名,1使用MD5数据加密 2 使用SHA数据加密 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(用一句话描述该文件做什么) * @author gangyu * @date 2018年11月20日 下午4:07:58 * @version V1.0 */ package com.jx.app.api.framework.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import com.jx.app.api.framework.annotation.enums.SginEnum; /** * @ClassName: SginAnot * @Description: TODO(签名验证注解) * @author gangyu * @date 2018年11月20日 下午4:07:58 * */ @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface SginAnot { SginEnum type() default SginEnum.ANY;//默认不需要签名 }
加密工具类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.BeanUtil; import com.jx.common.utils.TestEntity; /** * @ClassName: MD5 * @Description: TODO(MD5加密工具) * @author gangyu * @date 2018年11月20日 下午2:12:14 * */ public class MD5 { private static final Logger log = LoggerFactory.getLogger(MD5.class); public static String PRIVATE_KEY = "这是你的密钥"; private static final String hexDigIts[] = {"0","1","2","3","4","5","6","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加密异常:",e); return null; } } /** * @Title: encrypt * @Description: TODO(16位或32位密码) * @param @param * plainText * @param @param * flag true为32位,false为16位 * @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<String, Object> map = new HashMap<String,Object>(); if(obj instanceof Map){ map=(Map<String, Object>) obj; }else{ map = BeanUtil.transBean2Map(obj); } return encrypt(map,true); } /** * @Title: encrypt * @Description: TODO(16位或32位密码) * @param @param * plainText * @param @param * flag true为32位,false为16位 * @throws UnsupportedEncodingException */ public static String encrypt(Map<String, Object> map, boolean flag) { String param = null; map.remove("sign"); map.remove("encrypt"); String result = BeanUtil.mapOrderStr(map); if (StringUtils.isEmpty(result)) { return null; } param = encrypt(encrypt(result)+PRIVATE_KEY); if (flag) { return param; } else { param = param.substring(8, 24); } return param; } public static Map<String, Object> resultMap = new HashMap<String, Object>(); @SuppressWarnings("unchecked") public static Map<String, Object> mapFn(Map<String, Object> map) { for (String key : map.keySet()) { if (map.get(key) != null && map.get(key) != "" && (!key.equals("BTYPE") && !key.equals("SIGN"))) { if (key.equals("INPUT")) { if (map.get(key) != null) { mapFn((Map<String, Object>) map.get(key)); } } else { resultMap.put(key, map.get(key)); } } } return resultMap; } @SuppressWarnings("unchecked") public static boolean check(Object obj){ Map<String,Object> map=new HashMap<String,Object>(); if(obj==null){ return false; } if(obj instanceof Map){ map=(Map<String, Object>) obj; }else{ map = BeanUtil.transBean2Map(obj); } String sign=(String)map.get("sign"); if(sign==null){ return false; } String str=encrypt(obj); return sign.equals(str)?true:false; } public static String byteArrayToHexString(byte b[]){ StringBuffer resultSb = new StringBuffer(); for(int i = 0; i < b.length; i++){ resultSb.append(byteToHexString(b[i])); } return resultSb.toString(); } public static String byteToHexString(byte b){ int n = b; if(n < 0){ n += 256; } int d1 = n / 16; int d2 = n % 16; return hexDigIts[d1] + hexDigIts[d2]; } public static void main(String[] args) throws UnsupportedEncodingException { TestEntity test = new TestEntity(); test.setId("1"); test.setAge("20"); test.setClaes("你好"); test.setName("gyu"); test.setCreateTime("2018-11-20"); test.setSign("5189bd815c3850395f30779d0e59229e"); System.out.println("MD5验签成功:"+check(test)); } }
SHA加密工具类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.BeanUtil; /** * @ClassName: Sha1Util * @Description: TODO(SHA加密) * @author gangyu * @date 2018年11月20日 下午2:08:36 * */ 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加密异常:",e); } catch (UnsupportedEncodingException e) { e.printStackTrace(); log.error("SHA1加密异常:",e); } return str; } @SuppressWarnings("unchecked") public static String encrypt(Object obj) { if(obj==null){ return null; } Map<String, Object> map = new HashMap<String,Object>(); if(obj instanceof Map){ map=(Map<String, Object>) obj; }else{ map = BeanUtil.transBean2Map(obj); } map.remove("sign"); map.remove("encrypt"); String result = BeanUtil.mapOrderStr(map); if (StringUtils.isEmpty(result)) { return null; } return encrypt(result); } @SuppressWarnings("unchecked") public static boolean check(Object obj){ Map<String,Object> map=new HashMap<String,Object>(); if(obj==null){ return false; } if(obj instanceof Map){ map=(Map<String, Object>) obj; }else{ map = BeanUtil.transBean2Map(obj); } String sign=(String)map.get("sign"); if(sign==null){ return false; } String str=encrypt(obj); return sign.equals(str)?true:false; } }
返回数据对称加密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.DESedeKeySpec; import javax.crypto.spec.IvParameterSpec; import com.google.gson.Gson; import com.jx.common.utils.Base64; /** * @ClassName: Des * @Description: TODO(对称加密工具) * @author gangyu * @date 2018年11月20日 下午1:18:49 */ public class DES { // 密钥 private final static String secretKey = "123456789987654321"; // 向量 private final static String iv = "ggboy123"; // 加解密统一使用的编码方式 private final static String encoding = "utf-8"; /** * @Title: encode * @Description: TODO(加密) * @param String * @author gangyu2 * @date 2018年11月20日下午1:19:19 */ 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(解密) * @param String * @author gangyu2 * @date 2018年11月20日下午1:19:37 */ 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 ""; } } }
BeanUtil.java
package com.jx.common.utils; import java.beans.BeanInfo; import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.apache.commons.beanutils.BeanUtils; import org.apache.commons.beanutils.PropertyUtilsBean; import org.apache.commons.lang3.StringUtils; public class BeanUtil { // Map --> Bean 2: 利用org.apache.commons.beanutils 工具类实现 Map --> Bean public static void transMap2Bean2(Map<String, Object> map, Object obj) { if (map == null || obj == null) { return; } try { BeanUtils.populate(obj, map); } catch (Exception e) { System.out.println("transMap2Bean2 Error " + e); } } // Map --> Bean 1: 利用Introspector,PropertyDescriptor实现 Map --> Bean public static void transMap2Bean(Map<String, Object> map, Object obj) { try { BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass()); PropertyDescriptor[] propertyDescriptors = beanInfo .getPropertyDescriptors(); for (PropertyDescriptor property : propertyDescriptors) { String key = property.getName(); if (map.containsKey(key)) { Object value = map.get(key); // 得到property对应的setter方法 Method setter = property.getWriteMethod(); setter.invoke(obj, value); } } } catch (Exception e) { System.out.println("transMap2Bean Error " + e); } return; } // Bean --> Map 1: 利用Introspector和PropertyDescriptor 将Bean --> Map public static Map<String, Object> transBean2Map(Object obj) { if (obj == null) { return null; } Map<String, Object> map = new HashMap<String, Object>(); try { BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass()); PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors(); for (PropertyDescriptor property : propertyDescriptors) { String key = property.getName(); // 过滤class属性 if (!key.equals("class")) { // 得到property对应的getter方法 Method getter = property.getReadMethod(); Object value = getter.invoke(obj); if(null !=value && !"".equals(value)) map.put(key, value); } } } catch (Exception e) { System.out.println("transBean2Map Error " + e); } return map; } public static String mapOrderStr(Map<String, Object> map) { List<Map.Entry<String, Object>> list = new ArrayList<Map.Entry<String, Object>>(map.entrySet()); Collections.sort(list, new Comparator<Map.Entry<String, Object>>() { public int compare(Entry<String, Object> o1, Entry<String, Object> o2) { return o1.getKey().compareTo(o2.getKey()); } }); StringBuilder sb = new StringBuilder(); for (Map.Entry<String, Object> mapping : list) { sb.append(mapping.getKey() + "=" + mapping.getValue() + "&"); } return sb.substring(0, sb.length() - 1); } /** * * 将源的属性复制到目标属性上去 * @param src * @param dest * @lastModified * @history */ public static void copyProperties(Object dest,Object src) { if (src == null || dest == null) { return; } // 获取所有的get/set 方法对应的属性 PropertyUtilsBean propertyUtilsBean = new PropertyUtilsBean(); PropertyDescriptor[] descriptors = propertyUtilsBean.getPropertyDescriptors(src); for (int i = 0; i < descriptors.length; i++) { PropertyDescriptor propItem = descriptors[i]; // 过滤setclass/getclass属性 if ("class".equals(propItem.getName())) { continue; } try { Method method = propItem.getReadMethod(); // 通过get方法获取对应的值 Object val = method.invoke(src); // 如果是空,不做处理 if (null == val) { continue; } if(val instanceof String) { if(StringUtils.isBlank(val.toString())) { continue; } } // 值复制 PropertyDescriptor prop = propertyUtilsBean.getPropertyDescriptor(dest, propItem.getName()); // 调用写方法,设置值 if (null != prop && prop.getWriteMethod() != null) { prop.getWriteMethod().invoke(dest, val); } } catch (Exception e) { } } } public static <T> T mapToEntity(Map<String, Object> map, Class<T> entity) { T t = null; try { t = entity.newInstance(); for(Field field : entity.getDeclaredFields()) { 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; } }
拦截器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.Gson; import com.jx.app.api.framework.annotation.LoginAnot; import com.jx.app.api.framework.annotation.SginAnot; import com.jx.app.api.framework.annotation.enums.Auth; import com.jx.app.api.framework.annotation.enums.SginEnum; import com.jx.common.entrypt.MD5; import com.jx.common.entrypt.Sha1; 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(拦截器) * @author gangyu * @date 2018年11月20日 下午4:10:55 * */ 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)) { //签名验证注解 SginAnot signAnot = ((HandlerMethod) handler).getMethodAnnotation(SginAnot.class); //验签 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<String,Object> map=RequestUtil.parseRequset(request); if(enumm==SginEnum.MD5){ return MD5.check(map); }else if(enumm==SginEnum.SHA1){ return Sha1.check(map); } return false; } } } }
统一返回对象Result.java
package com.jx.common.utils; import java.io.Serializable; import com.google.gson.Gson; import com.jx.common.entrypt.DES; import com.jx.common.utils.enums.CodeEnum; /** * 结果DTO * @lastModified * @history */ public class Result implements Serializable{ private static final long serialVersionUID = 1L; /** * 结果详细 */ private String msg; /** * 需要传回页面的数据 */ private Object data; /** * 状态码 */ private String code; /** * 加密 */ private boolean encrypt; /** * 图标 */ 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; } }
状态码枚举类CodeEnum.java
package com.jx.common.utils.enums; /** * @ClassName: ExceptionEnum * @Description: TODO(系统编码) * @author gangyu * @date 2018年11月21日 下午5:22:32 */ public enum CodeEnum { //系统编码 SYS_EXCEPTION("999",false,"系统异常",'fail'), SUCCESS("0",false,"成功",'success'), ENCRYPT("0",true,"成功",'success'), FAIL("1",false,"失败",'fail'), SIGN_FAIL("1",false,"签名不正确",'fail'), DATA_EMPTY("0",false,"暂无数据",'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; } public Boolean getEncrypt() { return encrypt; } }
Controller层使用签名注解
@RequestMapping(value="encryptEntity",produces = "application/json;charset=UTF-8",method=RequestMethod.POST) @SginAnot(type = SginEnum.MD5) public Object encryptEntity(TestEntity test){ return businessService.encryptEntity(test); }
- 验签加密排序根据ASII表进行排序在BeanUtil.java类里已经实现
- url?a=1&c=2&b=3。。。->排序后 a=1&b=3&c=2 然后进行数据加密 俩边排序方式要一致当然为了安全可以排完序加入自己的密钥在进行一次加密
- Result.java提供了返回数据加密方法CodeEnum.ENCRYPT这里使用的是DES对称加密
到此这篇关于SpringBoot自定义注解API数据加密和签名校验的文章就介绍到这了,更多相关SpringBoot 数据加密和签名校验内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!