`
zweichxu
  • 浏览: 132164 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

spring mvc框架增加对消息的加密/解密

 
阅读更多

 开发中会遇到要求对http传输的数据进行加密传输,我们可以重写spring mvc的MappingJackson2HttpMessageConverter类,实现对加密解密的支持。代码如下:

package com.hzwei.spring.messageconvert.ext;

import java.io.*;
import java.lang.reflect.Type;

import org.springframework.http.*;
import org.springframework.http.converter*;
import org.springframework.http.converter.json.*;
import org.springframework.util.TypeUtils;

import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.core.util.*;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.ser.FilterProvider;
import com.jsecode.platform.util.EncryptDecrypt;

/**
 * 扩展MappingJackson2HttpMessageConverter类,增加对消息的解密/加密支持处理(支持spring-web-4.3.x)
 */
public class EncryptMappingJackson2HttpMessageConverter extends MappingJackson2HttpMessageConverter {
    private static final MediaType TEXT_EVENT_STREAM = new MediaType("text", "event-stream");
    private PrettyPrinter ssePrettyPrinter;
    private boolean needEncryptOutputMessage = false;
    private boolean needDecryptInputMessage = false;

    protected void init(ObjectMapper objectMapper){
        super.init(objectMapper);

        DefaultPrettyPrinter prettyPrinter = new DefaultPrettyPrinter();
        prettyPrinter.indentObjectsWith(new DefaultIndenter("  ", "\ndata:"));
        this.ssePrettyPrinter = prettyPrinter;
    }

    public boolean isNeedEncryptOutputMessage(){
        return needEncryptOutputMessage;
    }

    public void setNeedEncryptOutputMessage(boolean needEncryptOutputMessage){
        this.needEncryptOutputMessage = needEncryptOutputMessage;
    }

    public boolean isNeedDecryptInputMessage(){
        return needDecryptInputMessage;
    }

    public void setNeedDecryptInputMessage(boolean needDecryptInputMessage){
        this.needDecryptInputMessage = needDecryptInputMessage;
    }

    @Override
    protected Object readInternal(Class<?> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException{
        JavaType javaType = getJavaType(clazz, null);
        return readJavaType(javaType, inputMessage);
    }

    public Object read(Type type, Class<?> contextClass, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException{
        JavaType javaType = getJavaType(type, contextClass);
        return readJavaType(javaType, inputMessage);
    }

    private Object readJavaType(JavaType javaType, HttpInputMessage inputMessage){
        try{
            if(inputMessage instanceof MappingJacksonInputMessage){
                Class<?> deserializationView = ((MappingJacksonInputMessage)inputMessage).getDeserializationView();
                if(deserializationView != null){
                    return this.objectMapper.readerWithView(deserializationView)
                                            .forType(javaType)
                                            .readValue(getInputStreamData(inputMessage.getBody()));
                }
            }
            return this.objectMapper.readValue(getInputStreamData(inputMessage.getBody()), javaType);
        }catch(JsonProcessingException ex){
            throw new HttpMessageNotReadableException("JSON parse error: " + ex.getOriginalMessage(), ex);
        }catch(IOException ex){
            throw new HttpMessageNotReadableException("I/O error while reading input message", ex);
        }
    }

    private byte[] getInputStreamData(InputStream in) throws IOException{
        ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
        byte[] buff = new byte[1024];
        int offset = 0;
        while((offset = in.read(buff)) > 0){
            swapStream.write(buff, 0, offset);
        }

        byte[] bytes = swapStream.toByteArray();
        if(needDecryptInputMessage){
            // 对bytes进行解密
            bytes = EncryptDecrypt.AESFastDecrypt2(bytes); //TODO 此处换上您的解密算法
        }
        return bytes;
    }

    @Override
    protected void writeInternal(Object object, Type type, HttpOutputMessage outputMessage)
            throws IOException, HttpMessageNotWritableException{
        if(needEncryptOutputMessage){
            writeInternalEncrypt(object, type, outputMessage);
        }else{
            super.writeInternal(object, type, outputMessage);
        }
    }

    // 对返回值进行序列化并使用AES加密
    protected void writeInternalEncrypt(Object object, Type type, HttpOutputMessage outputMessage)
            throws IOException, HttpMessageNotWritableException{
        MediaType contentType = outputMessage.getHeaders().getContentType();
        JsonEncoding encoding = getJsonEncoding(contentType);
        JsonFactory factory = this.getObjectMapper().getFactory();
        ByteArrayBuilder bb = new ByteArrayBuilder(factory._getBufferRecycler());
        JsonGenerator generator = factory.createGenerator(bb, encoding);
        writeToJsonGenerator(object, type, generator, contentType);

        try{
            //TODO 此处换上您自己的加密算法
            byte[] byteData = EncryptDecrypt.AESFastEncrypt(bb.toByteArray());
            outputMessage.getBody().write(byteData);
        }catch(Exception ex){
            throw new HttpMessageNotWritableException("Could not encrypt and write message: " + ex.getMessage(), ex);
        }
    }

    // 保持MappingJackson2HttpMessageConverter原滋原味的序列化方法
    protected void writeToJsonGenerator(Object object, Type type, JsonGenerator generator, MediaType contentType)
            throws IOException, HttpMessageNotWritableException{
        try{
            writePrefix(generator, object);

            Class<?> serializationView = null;
            FilterProvider filters = null;
            Object value = object;
            JavaType javaType = null;
            if(object instanceof MappingJacksonValue){
                MappingJacksonValue container = (MappingJacksonValue)object;
                value = container.getValue();
                serializationView = container.getSerializationView();
                filters = container.getFilters();
            }
            if(type != null && value != null && TypeUtils.isAssignable(type, value.getClass())){
                javaType = getJavaType(type, null);
            }
            ObjectWriter objectWriter;
            if(serializationView != null){
                objectWriter = this.objectMapper.writerWithView(serializationView);
            }else if(filters != null){
                objectWriter = this.objectMapper.writer(filters);
            }else{
                objectWriter = this.objectMapper.writer();
            }
            if(javaType != null && javaType.isContainerType()){
                objectWriter = objectWriter.forType(javaType);
            }
            SerializationConfig config = objectWriter.getConfig();
            if(contentType != null && contentType.isCompatibleWith(TEXT_EVENT_STREAM)
                    && config.isEnabled(SerializationFeature.INDENT_OUTPUT)){
                objectWriter = objectWriter.with(this.ssePrettyPrinter);
            }
            objectWriter.writeValue(generator, value);

            writeSuffix(generator, object);
            generator.flush();

        }catch(JsonProcessingException ex){
            throw new HttpMessageNotWritableException("Could not write JSON: " + ex.getOriginalMessage(), ex);
        }
    }
}

   在spring mvc项目中,替换MappingJackson2HttpMessageConverter为EncryptMappingJackson2HttpMessageConverter

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics