zoukankan      html  css  js  c++  java
  • Spring 接口参数加密传输

    加密方式 AES

    spring jar 包 pom.xml配置(注意版本)

            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-core</artifactId>
                <version>3.2.5.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-jdbc</artifactId>
                <version>3.2.5.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-orm</artifactId>
                <version>3.2.5.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>3.2.5.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context-support</artifactId>
                <version>3.2.5.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-beans</artifactId>
                <version>3.2.5.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-aspects</artifactId>
                <version>3.2.5.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-aop</artifactId>
                <version>3.2.5.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-webmvc</artifactId>
                <version>3.2.5.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-web</artifactId>
                <version>3.2.5.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-tx</artifactId>
                <version>3.2.5.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-webmvc-portlet</artifactId>
                <version>3.2.5.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-oxm</artifactId>
                <version>3.2.5.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-jms</artifactId>
                <version>3.2.5.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-test</artifactId>
                <version>3.2.5.RELEASE</version>
                <scope>test</scope>
            </dependency>

    这个是原理图

    在spring做如下 配置。

        <!-- 启动Spring MVC的注解功能,完成请求和注解POJO的映射 -->
        <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
            <property name="order" value="0" />
        </bean>
        <bean class="com.sifude.youlife.spring.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
            
            <property name="messageConverters">
                <list>
                    <ref bean="jsonHttpMessageConverter" />
                    <ref bean="stringHttpMessageConverter" />
                    <!-- <ref bean="marshallingHttpMessageConverter" /> -->
                </list>
            </property>
        </bean>
        <bean id="stringHttpMessageConverter"
            class="org.springframework.http.converter.StringHttpMessageConverter">
            <constructor-arg value="UTF-8" />
            <property name="supportedMediaTypes">
                <value>text/html;charset=UTF-8</value>
            </property>
        </bean>
        <bean id="jsonHttpMessageConverter"
            class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
            <property name="supportedMediaTypes">
                <list>
                    <value>text/html;charset=UTF-8</value>
                    <value>application/json;charset=UTF-8</value>
                </list>
            </property>
        </bean>

    可以发现com.sifude.youlife.spring.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter这个类就是我们自己写的。从spring里面拷贝出如下几个类

    RequestParamMethodArgumentResolver对每个参数进行了拦截,然后在resolveName方法进行处理,因此我们只要

    重写RequestParamMethodArgumentResolver中的resolveName方法即可

        @Override
        protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest webRequest) throws Exception {
    
            Object arg;
    
            HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
            MultipartHttpServletRequest multipartRequest =
                WebUtils.getNativeRequest(servletRequest, MultipartHttpServletRequest.class);
    
            if (MultipartFile.class.equals(parameter.getParameterType())) {
                assertIsMultipartRequest(servletRequest);
                Assert.notNull(multipartRequest, "Expected MultipartHttpServletRequest: is a MultipartResolver configured?");
                arg = multipartRequest.getFile(name);
            }
            else if (isMultipartFileCollection(parameter)) {
                assertIsMultipartRequest(servletRequest);
                Assert.notNull(multipartRequest, "Expected MultipartHttpServletRequest: is a MultipartResolver configured?");
                arg = multipartRequest.getFiles(name);
            }
            else if ("javax.servlet.http.Part".equals(parameter.getParameterType().getName())) {
                assertIsMultipartRequest(servletRequest);
                arg = servletRequest.getParameter(name);
            }
            else {
                arg = null;
                if (multipartRequest != null) {
                    List<MultipartFile> files = multipartRequest.getFiles(name);
                    if (!files.isEmpty()) {
                        arg = (files.size() == 1 ? files.get(0) : files);
                    }
                }
                if (arg == null) {
                    boolean isEnc = false;
                    if (null != parameter.getMethod().getAnnotation(EncRequest.class)) {
                        isEnc = true;
                    }
                    if (isEnc) {// 数据需要加密的情况
                        String content = servletRequest.getParameter("content");
                        if (null != content) {
                            content = AESUtil.decrypt(content);
                            ObjectMapper mapper = new ObjectMapper(); // can reuse, share
                            mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);// 忽略未知元素
                            Object o = mapper.readValue(content, HashMap.class).get(name);
                            if(o instanceof String[]) {
                                String[] paramValues = (String[]) o;
                                if (paramValues != null) {
                                    arg = paramValues.length == 1 ? paramValues[0] : paramValues;
                                }
                            } else {
                                arg = o;
                            }
                        }
                    } else {
                        String[] paramValues = webRequest.getParameterValues(name);
                        if (paramValues != null) {
                            arg = paramValues.length == 1 ? paramValues[0] : paramValues;
                        }
                    }
                }
            }
    
            return arg;
        }

    其他1个注解和加密算法

    package com.sifude.annotations;
    
    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface EncRequest {
    
    }
    package com.sifude.tool.util;
    
    import java.io.UnsupportedEncodingException;
    import java.util.Random;
    
    import javax.crypto.Cipher;
    import javax.crypto.spec.IvParameterSpec;
    import javax.crypto.spec.SecretKeySpec;
    
    import org.apache.commons.codec.binary.Base64;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import com.sifude.tool.util.entity.Constant;
    
    /**
     * AES加解密算法
     * key:每次登陆动态随机生成(大小写字母和数字组成),并保存在session中
     * 此处使用AES-128-CBC加密模式,key需要为16位
     */
    public class AESUtil {
        private static Logger log = LoggerFactory.getLogger(FileUtil.class);
        
        public static boolean isAES = Constant.AES.ISAES;
        public static String sKey = Constant.AES.SKEY;
        
        // 加密
        public static String encrypt(String sSrc) throws Exception {
            
            if(!isAES) {
                return sSrc;
            }
            if (sKey == null) {
                //System.out.print("Key为空null");
                return null;
            }
            // 判断Key是否为16位
            if (sKey.length() != 16) {
                //System.out.print("Key长度不是16位");
                return null;
            }
            byte[] raw = sKey.getBytes();
            SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");// "算法/模式/补码方式"
            IvParameterSpec iv = new IvParameterSpec("0102030405060708".getBytes());// 使用CBC模式,需要一个向量iv,可增加加密算法的强度
            cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
            //加密前要进行编码,否则js无法解码
            byte[] encrypted = cipher.doFinal(sSrc.getBytes("UTF-8"));
    
            return Base64.encodeBase64String(encrypted);// 此处使用BAES64做转码功能,同时能起到2次加密的作用。
        }
    
        // 解密
        public static String decrypt(String sSrc) throws Exception {
            if(!isAES) {
                return sSrc;
            }
            // 判断Key是否正确
            if (sKey == null) {
                //System.out.print("Key为空null");
                return null;
            }
            // 判断Key是否为16位
            if (sKey.length() != 16) {
                //System.out.print("Key长度不是16位");
                return null;
            }
            byte[] raw = sKey.getBytes("ASCII");
            SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            IvParameterSpec iv = new IvParameterSpec("0102030405060708"
                    .getBytes());
            cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
            byte[] encrypted1 = Base64.decodeBase64(sSrc);// 先用bAES64解密
            //System.out.println(encrypted1.length);
            byte[] original = cipher.doFinal(encrypted1);
            String originalString = new String(original);
            return originalString;
        }
    
        // 生成随机密锁
        public static String getKey(int length) {
            StringBuffer sb = new StringBuffer();
            Random random = new Random();
            // 参数length,表示生成几位随机数
            for (int i = 0; i < length; i++) {
                String charOrNum = random.nextInt(2) % 2 == 0 ? "char" : "num";
                // 输出字母还是数字
                if ("char".equalsIgnoreCase(charOrNum)) {
                    // 输出是大写字母还是小写字母
                    int temp = random.nextInt(2) % 2 == 0 ? 65 : 97;
                    sb.append((char) (random.nextInt(26) + temp));
                } else if ("num".equalsIgnoreCase(charOrNum)) {
                    sb.append(String.valueOf(random.nextInt(10)));
                }
            }
    
            try {
                return new String(sb.toString().getBytes(), "UTF-8");
            } catch (UnsupportedEncodingException e) {
                log.error(e.getMessage(), e);
            }
            return "mapabc2014214yxj";
        }
    
        public static void main(String[] args) {
            //AES.sKey = getKey(16);
            AESUtil.isAES = true;
            try {
                //String str = AES.encrypt("你好1.2#3:4//5_6,1 2&3?4a/bc5=6");
                //String str = AES.encrypt("{"account":"ez","password":"123456"}");
                String str = AESUtil.encrypt("{"cityId":"110000","cityType":"1"}");
                System.out.println(str);
                String str1 = AESUtil.decrypt(str);
                System.out.println(str1);
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
        }
    
    }

    这样功能就实现了,欢迎大家一期交流。

  • 相关阅读:
    paip.云计算以及分布式计算的区别
    paip.索引的种类以及实现attilax 总结
    paip.分布式应用系统java c#.net php的建设方案
    paip.提升性能--多核编程中的java .net php c++最佳实践 v2.0 cah
    paip.中文 分词 ---paoding 3.1 的使用
    paip.2013年技术趋势以及热点 v2.0 cae
    paip.为什么使用多线程的原因.
    paip.提升性能--多核cpu中的java/.net/php/c++编程
    paip.重装系统需要备份的资料总结..v2.0 cad
    paip.禁用IKAnalyzer 的默认词库.仅仅使用自定义词库.
  • 原文地址:https://www.cnblogs.com/barrywxx/p/6984370.html
Copyright © 2011-2022 走看看