欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

spring mvc框架增加对消息的加密/解密 博客分类: spring mvc笔记

程序员文章站 2024-03-13 18:49:51
...

 开发中会遇到要求对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