最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

一文教你如何使用AES對(duì)接口參數(shù)進(jìn)行加密

 更新時(shí)間:2023年08月13日 11:11:01   作者:Bummon  
這篇文章主要是想為大家介紹一下如何使用AES實(shí)現(xiàn)對(duì)接口參數(shù)進(jìn)行加密,文中的示例代碼簡(jiǎn)潔易懂,具有一定的借鑒價(jià)值,需要的小伙伴可以了解一下

前言

我們作為程序猿,在瀏覽網(wǎng)站的時(shí)候偶爾也會(huì)打開(kāi)控制臺(tái)看看請(qǐng)求的接口,我們會(huì)發(fā)現(xiàn)有些接口的傳輸是 "亂碼" ,那么這個(gè)亂碼究竟是什么呢?為什么要這么做?

其實(shí)這個(gè)所謂的 "亂碼" 其實(shí)是一種加密后的密文,其原理是前后端提前約定好一種協(xié)議,在該協(xié)議下進(jìn)行加解密的處理,例如:前端將數(shù)據(jù)加密后發(fā)送給后端,后端接收到參數(shù)后,第一時(shí)間先在約定好的協(xié)議下將密文解密成可識(shí)別的對(duì)象,再進(jìn)行邏輯處理,最后將結(jié)果加密返回給前端,前端獲取到密文后,同樣依照約定好的協(xié)議對(duì)密文進(jìn)行解密,最后將解密出來(lái)的數(shù)據(jù)拿來(lái)使用。

那么我們想實(shí)現(xiàn)同樣的效果,應(yīng)該如何做呢?別急,聽(tīng)哥們給你一一道來(lái)。

介紹

一般來(lái)說(shuō)加密算法會(huì)分為兩種:對(duì)稱加密算法 和 非對(duì)稱加密算法 。

對(duì)稱加密算法

摘自百度百科: 采用單鑰密碼系統(tǒng)的加密方法,同一個(gè)密鑰可以同時(shí)用作信息的加密和解密,這種加密方法稱為對(duì)稱加密,也稱為單密鑰加密。

非對(duì)稱加密算法

摘自百度百科: 不對(duì)稱加密算法使用兩把完全不同但又是完全匹配的一對(duì)鑰匙—公鑰和私鑰。在使用不對(duì)稱加密算法加密文件時(shí),只有使用匹配的一對(duì)公鑰和私鑰,才能完成對(duì)明文的加密和解密過(guò)程。

經(jīng)過(guò)百度百科中的簡(jiǎn)單概要,我們已經(jīng)知道了對(duì)稱加密算法非對(duì)稱加密算法 都是什么,但它們中間又有什么不同呢?早就猜到你會(huì)這么問(wèn)了,所以我已經(jīng)把它們的區(qū)別一一列出來(lái)了。

區(qū)別

密鑰

對(duì)稱加密: 一共只有一種密鑰,并將該密鑰同時(shí)用來(lái)加解密。

非對(duì)稱加密: 共有兩種密鑰:公鑰私鑰 ,使用公鑰來(lái)加密,使用私鑰來(lái)解密。

速度

對(duì)稱加密: 算法簡(jiǎn)單且加解密容易,所以執(zhí)行效率高、速度快。

非對(duì)稱加密: 由于加密算法比較復(fù)雜,所以加解密的效率很低,速度遠(yuǎn)不如 對(duì)稱加密 。

安全性

對(duì)稱加密: 由于加解密均使用的為同一個(gè)密鑰,那么若密鑰泄露則有被破解密文的風(fēng)險(xiǎn)。

非對(duì)稱加密: 由于使用了兩種密鑰,且公鑰是可公開(kāi)的密鑰,使用私鑰來(lái)進(jìn)行解密,消除了用戶交換密鑰的條件,極大程度上保證了數(shù)據(jù)安全。

實(shí)現(xiàn)

在這里給大家介紹一下 AES + CBC + PKCS5Padding 的加密方式,具體實(shí)現(xiàn)如下:

引入依賴

<dependency>
            <groupId>org.apache.directory.studio</groupId>
            <artifactId>org.apache.commons.codec</artifactId>
            <version>1.8</version>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.13.0</version>
        </dependency>

編寫(xiě)密鑰荷載

注意:這里的 AES_KEYAES_IV 可以自定義,但 必須是16位的。

/**
 * @author Bummon
 * @description 荷載
 * @date 2023-08-12 10:27
 */
public class Common {
    /**
     * AES密鑰
     */
    public static final byte[] AES_KEY = "Ct9x5IUNHlhq0siZ".getBytes();
    /**
     * AES偏移
     */
    public static final byte[] AES_IV = "MIIBIjANBgkqhkiG".getBytes();
}

編寫(xiě)AES工具類

import com.test.constant.Common;
import org.apache.commons.codec.binary.Base64;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
/**
 * @author Bummon
 * @description AES工具類
 * @date 2023-08-12 09:26
 */
public class AESUtils {
    private static final String ALGORITHMSTR = "AES/CBC/PKCS5Padding";
    /**
     * @param content 加密內(nèi)容
     * @return {@link String}
     * @date 2023-08-12 09:27
     * @author Bummon
     * @description 加密
     */
    public static String encrypt(String content) {
        String encode = null;
        try {
            Cipher cipher = initCipher(Cipher.ENCRYPT_MODE);
            byte[] encodeBytes = cipher.doFinal(content.getBytes());
            encode = Base64.encodeBase64String(encodeBytes);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return encode;
    }
    public static String decrypt(String encryptStr) {
        String decode = null;
        try {
            Cipher cipher = initCipher(Cipher.DECRYPT_MODE);
            byte[] encodeBytes = Base64.decodeBase64(encryptStr);
            byte[] decodeBytes = cipher.doFinal(encodeBytes);
            decode = new String(decodeBytes);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return decode;
    }
    /**
     * @param cipherMode 操作類型 加密/解密
     * @return {@link Cipher}
     * @date 2023-08-12 09:42
     * @author Bummon
     * @description 初始化Cipher
     */
    private static Cipher initCipher(int cipherMode) throws Exception {
        KeyGenerator kgen = KeyGenerator.getInstance("AES");
        kgen.init(128);
        Cipher cipher = Cipher.getInstance(ALGORITHMSTR);
        SecretKeySpec keySpec = new SecretKeySpec(Common.AES_KEY, "AES");
        IvParameterSpec ivParam = new IvParameterSpec(Common.AES_IV);
        cipher.init(cipherMode, keySpec, ivParam);
        return cipher;
    }
    public static void main(String[] args) {
        String encrypt = AESUtils.encrypt("Hello World");
        String decrypt = AESUtils.decrypt(encrypt);
        System.out.println(encrypt);
        System.out.println(decrypt);
    }
}

自定義注解

該注解作用于接口上,可以對(duì)接口的加密或者解密實(shí)現(xiàn)更加粒子化的控制,默認(rèn)入?yún)⒔饷?,出參加密?/p>

import org.springframework.web.bind.annotation.Mapping;
import java.lang.annotation.*;
/**
 * @author Bummon
 * @description AES加解密注解
 * @date 2023-08-12 09:44
 */
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Mapping
@Documented
public @interface AES {
    /**
     * 入?yún)⑹欠窠饷?,默認(rèn)解密
     */
    boolean inDecode() default true;
    /**
     * 出參是否加密,默認(rèn)加密
     */
    boolean outEncode() default true;
}

DecodeRequestBodyAdvice

import com.test.anno.AES;
import com.test.util.pwd.AESUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Type;
/**
 * @author Bummon
 * @date 2023-08-12 10:22
 * @description 請(qǐng)求數(shù)據(jù)解密
 */
@Slf4j
@ControllerAdvice(basePackages = "com.test.controller")
public class DecodeRequestBodyAdvice implements RequestBodyAdvice {
    @Override
    public boolean supports(MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
        return true;
    }
    @Override
    public Object handleEmptyBody(Object body, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
        return body;
    }
    @Override
    public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) throws IOException {
        try {
            boolean encode = false;
            if (methodParameter.getMethod().isAnnotationPresent(AES.class)) {
                //獲取注解配置的包含和去除字段
                AES aes = methodParameter.getMethodAnnotation(AES.class);
                //入?yún)⑹欠裥枰饷?
                encode = aes.decode();
            }
            if (encode) {
                log.info("對(duì)方法method :【" + methodParameter.getMethod().getName() + "】返回?cái)?shù)據(jù)進(jìn)行解密");
                return new MyHttpInputMessage(inputMessage);
            } else {
                return inputMessage;
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("對(duì)方法method :【" + methodParameter.getMethod().getName() + "】返回?cái)?shù)據(jù)進(jìn)行解密出現(xiàn)異常:" + e.getMessage());
            return inputMessage;
        }
    }
    @Override
    public Object afterBodyRead(Object body, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
        return body;
    }
    class MyHttpInputMessage implements HttpInputMessage {
        private HttpHeaders headers;
        private InputStream body;
        public MyHttpInputMessage(HttpInputMessage inputMessage) throws Exception {
            this.headers = inputMessage.getHeaders();
            String param = IOUtils.toString(inputMessage.getBody(), "UTF-8");
            //去除請(qǐng)求數(shù)據(jù)中的轉(zhuǎn)義字符
            String encryptStr = easpString(param).replace("\"", "");
            String decrypt = AESUtils.decrypt(encryptStr);
            this.body = IOUtils.toInputStream(decrypt, "UTF-8");
        }
        @Override
        public InputStream getBody() throws IOException {
            return body;
        }
        @Override
        public HttpHeaders getHeaders() {
            return headers;
        }
        /**
         * @param param
         * @return
         */
        public String easpString(String param) {
            if (param != null && !param.equals("")) {
                String s = "{\"param\":";
                //去除param中的轉(zhuǎn)義字符
                String data = param.replaceAll("\\s*|\r|\n|\t", "");
                if (!data.startsWith(s)) {
                    throw new RuntimeException("參數(shù)【param】缺失異常!");
                } else {
                    int closeLen = data.length() - 1;
                    int openLen = "{\"param\":".length();
                    String substring = StringUtils.substring(data, openLen, closeLen);
                    return substring;
                }
            }
            return "";
        }
    }
}

EncodeResponseBodyAdvice

import com.fasterxml.jackson.databind.ObjectMapper;
import com.test.anno.AES;
import com.test.util.pwd.AESUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
/**
 * @author Bummon
 * @date 2023-08-12 10:36
 * @description 返回參數(shù)加密
 */
@Slf4j
@ControllerAdvice(basePackages = "com.test.controller")
public class EncodeResponseBodyAdvice implements ResponseBodyAdvice {
    @Override
    public boolean supports(MethodParameter methodParameter, Class aClass) {
        return true;
    }
    @Override
    public Object beforeBodyWrite(Object body,
                                  MethodParameter methodParameter,
                                  MediaType mediaType,
                                  Class aClass,
                                  ServerHttpRequest serverHttpRequest,
                                  ServerHttpResponse serverHttpResponse) {
        boolean encode = false;
        if (methodParameter.getMethod().isAnnotationPresent(AES.class)) {
            //獲取注解配置的包含和去除字段
            AES aes = methodParameter.getMethodAnnotation(AES.class);
            //出參是否需要加密
            encode = aes.encode();
        }
        if (encode) {
            log.info("對(duì)方法method :【" + methodParameter.getMethod().getName() + "】返回?cái)?shù)據(jù)進(jìn)行加密");
            ObjectMapper objectMapper = new ObjectMapper();
            try {
                String result = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(body);
                return AESUtils.encrypt(result);
            } catch (Exception e) {
                e.printStackTrace();
                log.error("對(duì)方法method :【" + methodParameter.getMethod().getName() + "】返回?cái)?shù)據(jù)進(jìn)行解密出現(xiàn)異常:" + e.getMessage());
            }
        }
        return body;
    }
}

編寫(xiě)測(cè)試控制器

import java.util.HashMap;
import java.util.Map;
/**
 * @author Bummon
 * @description
 * @date 2023-08-12 10:37
 */
@RestController
public class TestController {
    @AES(decode = false)
    @GetMapping("/getSecret")
    public Object getSecret() {
        Map<String, Object> map = new HashMap<>();
        map.put("name", "Bummon");
        map.put("homeUrl", "https://www.bummon.com/");
        map.put("blogUrl", "https://blog.bummon.com/");
        return map;
    }
    @AES(encode = false)
    @PostMapping("/getBySecret")
    public Object getBySecret(@RequestBody Map<String, Object> map) {
        return map;
    }
}

我們?cè)谶@里編寫(xiě)了兩個(gè)接口,其中 getSecret 接口不對(duì)入?yún)⑦M(jìn)行解密,對(duì)出參進(jìn)行加密,也就是前端傳明文,后端返回為密文。getBySecret 接口是對(duì)入?yún)⑦M(jìn)行解密,不對(duì)出參加密,也就是前端傳密文,后端返回為明文。

我們的測(cè)試思路就是先測(cè)試getSecret 接口,同時(shí)也獲取到了密文,在測(cè)試getBySecret 接口時(shí)將getSecret 接口返回的密文作為參數(shù)傳進(jìn)去。

測(cè)試

我們通過(guò)getSecret 接口拿到了密文,接下來(lái)將該密文作為參數(shù)調(diào)用getBySecret 接口。

可以看到我們成功將密文解析了出來(lái),并且對(duì)接口入?yún)](méi)有影響。

到此這篇關(guān)于一文教你如何使用AES對(duì)接口參數(shù)進(jìn)行加密的文章就介紹到這了,更多相關(guān)AES接口參數(shù)加密內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java集合類知識(shí)點(diǎn)總結(jié)

    Java集合類知識(shí)點(diǎn)總結(jié)

    本文把Java集合類的相關(guān)知識(shí)點(diǎn)做了總結(jié),并把Java常用集合類之間的區(qū)別做了分析,一起參考學(xué)習(xí)下。
    2018-02-02
  • 詳解Java中方法重寫(xiě)與重載的區(qū)別(面試高頻問(wèn)點(diǎn))

    詳解Java中方法重寫(xiě)與重載的區(qū)別(面試高頻問(wèn)點(diǎn))

    這篇文章主要介紹了Java中方法重寫(xiě)與重載的區(qū)別(面試高頻問(wèn)點(diǎn)),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-03-03
  • 深入解析Spring?AI框架如何在Java應(yīng)用中實(shí)現(xiàn)智能化交互的關(guān)鍵

    深入解析Spring?AI框架如何在Java應(yīng)用中實(shí)現(xiàn)智能化交互的關(guān)鍵

    本文詳細(xì)介紹了SpringAI框架在Java應(yīng)用中的應(yīng)用,包括實(shí)體類映射、函數(shù)回調(diào)等核心功能的實(shí)現(xiàn),通過(guò)源碼分析,幫助開(kāi)發(fā)者更好地理解和使用這些高級(jí)特性,提升業(yè)務(wù)效率,感興趣的朋友跟隨小編一起看看吧
    2024-11-11
  • Java中的collection集合類型總結(jié)

    Java中的collection集合類型總結(jié)

    Java的集合類型都是對(duì)java.util包中Collection接口的繼承,這里我們主要介紹依賴于collection的一些主分支,一起來(lái)看一下Java中的collection集合類型總結(jié)
    2016-05-05
  • 淺談Java方法的重載

    淺談Java方法的重載

    方法重載是指在一個(gè)類中定義多個(gè)同名的方法,但要求每個(gè)方法具有不同的參數(shù)的類型或參數(shù)的個(gè)數(shù)。調(diào)用重載方法時(shí),Java編譯器能通過(guò)檢查調(diào)用的方法的參數(shù)類型和個(gè)數(shù)選擇一個(gè)恰當(dāng)?shù)姆椒ā7椒ㄖ剌d通常用于創(chuàng)建完成一組任務(wù)相似但參數(shù)的類型或參數(shù)的個(gè)數(shù)不同的方法。
    2016-04-04
  • Java基礎(chǔ)之Bean的創(chuàng)建、定位和使用

    Java基礎(chǔ)之Bean的創(chuàng)建、定位和使用

    這篇文章主要介紹了Java基礎(chǔ)之Bean的創(chuàng)建、定位和使用,文中有非常詳細(xì)的圖文示例及代碼,對(duì)正在學(xué)習(xí)java基礎(chǔ)的小伙伴們有很好地幫助,需要的朋友可以參考下
    2021-05-05
  • Java中的數(shù)組使用詳解及練習(xí)

    Java中的數(shù)組使用詳解及練習(xí)

    數(shù)組是Java程序中最常見(jiàn)的一種數(shù)據(jù)結(jié)構(gòu),它能夠?qū)⑾嗤愋偷臄?shù)據(jù)用一個(gè)標(biāo)識(shí)符封裝到一起,構(gòu)成一個(gè)對(duì)象序列或基本數(shù)據(jù)類型,這篇文章主要給大家介紹了關(guān)于Java中數(shù)組使用詳解及練習(xí)的相關(guān)資料,需要的朋友可以參考下
    2024-03-03
  • 基于Spring Batch 配置重試邏輯

    基于Spring Batch 配置重試邏輯

    這篇文章主要介紹了Spring Batch 配置重試邏輯,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • java基本教程之線程休眠 java多線程教程

    java基本教程之線程休眠 java多線程教程

    本文對(duì)javaThread中sleep()方法進(jìn)行介紹,sleep() 的作用是讓當(dāng)前線程休眠,即當(dāng)前線程會(huì)從“運(yùn)行狀態(tài)”進(jìn)入到“休眠(阻塞)狀態(tài)”,大家參考使用吧
    2014-01-01
  • Java中如何正確遍歷刪除List中的元素

    Java中如何正確遍歷刪除List中的元素

    刪除List中元素這個(gè)場(chǎng)景很場(chǎng)景,很多人可能直接在循環(huán)中直接去刪除元素,這樣做對(duì)嗎?下面小編就來(lái)和大家一起討論如何正確遍歷刪除List中的元素,文中有詳細(xì)的代碼示例供大家參考,需要的朋友可以參考下
    2023-11-11

最新評(píng)論

宜良县| 临沭县| 商水县| 五大连池市| 台南县| 屯门区| 肇东市| 武陟县| 高平市| 宜州市| 广元市| 城口县| 嘉峪关市| 朝阳区| 宾阳县| 元谋县| 湘西| 荥阳市| 连城县| 乌兰浩特市| 灯塔市| 开江县| 临沂市| 丹阳市| 清涧县| 绩溪县| 叙永县| 潢川县| 平乡县| 德阳市| 彭山县| 祥云县| 海淀区| 垫江县| 孟州市| 宁海县| 凤城市| 高青县| 清流县| 抚顺县| 柳州市|