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);
            }
        }
    
    }

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

  • 相关阅读:
    UVALive 7509 Dome and Steles
    HDU 5884 Sort
    Gym 101194H Great Cells
    HDU 5451 Best Solver
    HDU 5883 The Best Path
    HDU 5875 Function
    卡特兰数
    UVa 11729 Commando War 突击战
    UVa 11292 The Dragon of Loowater 勇者斗恶龙
    Spark Scala Flink版本对应关系
  • 原文地址:https://www.cnblogs.com/barrywxx/p/6984370.html
Copyright © 2011-2022 走看看