范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

SpringBoot接口加解密全过程详解

  一、接口为什么要加密
  接口加密传输,主要作用:  敏感数据防止泄漏、  保护隐私、  防伪装攻击、  防篡改攻击、  防重放攻击  等等…  4个字概括: 保护数据!
  当然不是说接口加密后,就能完完全全的保护我们的数据,但至少能防一部分人拿到我们的数据。
  而且接口加密感觉逼格是不是高过一点!!!  二、加密思路1、加密简介
  加密算法有很多,在能加密又能解密的算法可分为:  非对称加密算法,常见: RSA  、 DSA  、 ECC
  特点:算法复杂,加解密速度慢,但安全性高,一般与对称加密结合使用(对称加密对内容加密,非对称对对称所使用的密钥加密)  对称加密算法,常见: DES  、 3DES  、 AES  、 Blowfish  、 IDEA  、 RC5  、 RC6
  特点:加密解密效率高,速度快,适合进行大数据量的加解密  2、加密流程
  思路:
  假设现在客户端是A,服务端是B,现在A要去B请求接口  1、A要向B发送信息,A和B都要产生一对用于加密的非对称加密公私钥(AB各自生成自己的公私钥)  2、A的私钥保密,A的公钥告诉B;B的私钥保密,B的公钥告诉A。(AB互换公钥)  3、A要给B发送信息时,A用B的公钥加密信息,因为A知道B的公钥。(公钥加密只有私钥能解)  4、A将这个消息发给B(已经用B的公钥加密消息)。  5、B收到这个消息后,B用自己的私钥解密A的消息。其他人收到这个报文都无法解密,因为只有B才有B的私钥。
  虽然这样就实现了接口的加密方式,但是呢,非对称加密的加解密速度相比对称加密速度很慢,当传输的数据很大时就更加明显了。
  所以我们对称与非对称一起用,理解上面的流程之后,我们在其基础稍微改下:  在A给B发信息的时候,随机生成一个对称加密的密钥,然后用刚生成的密钥加密信息,然后用B的公钥加密刚生成的对称密钥。  A把加密的两个信息发送给B。B收到数据之后,先用自己的私钥解开得到对称密钥,然后再用解开的对称密钥解开对称加密的信息,最终得到A传来的信息。  三、代码实现在当下Java还是SpringBoot为主流框架工作面试必备,今天还是以它来举例。  加解密代码怎么写,这个时候网上已经有很多现成的库了,不用我们操心,我们想的是如何在接口加解密的时候不影响我们自己的业务,也就是不用更改我们已经写好的代码。  很多人的第一反应应该就是AOP吧,对的没错可以使用AOP进行环绕增强。也可以使用 @ControllerAdvice   对Controller进行增强(本文以它来做为例子)。  Spring 提供两个接口 RequestBodyAdvice  、 ResponseBodyAdvice  。实现它们,即可对 Controller  进行增强,第一个是在controller之前增强,第二个就是对controller 的返回值进行增强。  在spring启动的时候会对 RequestMappingHandlerAdapter  的 initControllerAdviceCache()  方法进行初始化。会去把有 @ControllerAdvice  的类进行注入。  1、自定义类
  下面就来实现上面的两个接口实现类代码  EncryptRequestAdvice.java这个类的功能就是在请求到controller之前就把前端传上来的数据解密好  我们还要校验是否有必要解密  @ControllerAdvice(basePackages = {"top.lrshuai.encrypt.controller"}) public class EncryptRequestAdvice implements RequestBodyAdvice {      @Autowired     private KeyConfig keyConfig;      /**      * 是否需要解码      */     private boolean isDecode;      @Override     public boolean supports(MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {         // 方法或类上有注解         if (Utils.hasMethodAnnotation(methodParameter,new Class[]{Encrypt.class,Decode.class})) {             isDecode=true;             // 这里返回true 才支持             return true;         }         return false;     }      @Override     public HttpInputMessage beforeBodyRead(HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) throws IOException {         if(isDecode){             return new DecodeInputMessage(httpInputMessage, keyConfig);         }         return httpInputMessage;     }      @Override     public Object afterBodyRead(Object obj, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {         // 这里就是已经读取到body了,obj就是         return obj;     }      @Override     public Object handleEmptyBody(Object obj, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {         // body 为空的时候调用         return obj;     }  } 在上面实现类中需要重写: supports()  、 beforeBodyRead()  、 afterBodyRead()  、 handleEmptyBody()   方法  只有在 supports()   返回 true   后面的方法才会支持执行。在 RequestResponseBodyAdviceChain  有判断  我们可以在 beforeBodyRead()  这个方法进行解密处理。  在上面的代码中,我加了自定义注解,因为可能需求是这样的,有些接口加密有些接口不加密,用自定义注解比较方便。  然后 DecodeInputMessage   这个类是自定义实现了 HttpInputMessage  接口,解码逻辑都在里面。如下:  DecodeInputMessage.java
  这个类就是具体的解码逻辑了  public class DecodeInputMessage implements HttpInputMessage {      private HttpHeaders headers;      private InputStream body;      public DecodeInputMessage(HttpInputMessage httpInputMessage, KeyConfig keyConfig) {         // 这里是body 读取之前的处理         this.headers = httpInputMessage.getHeaders();         String encodeAesKey = "";         List keys = this.headers.get(Result.KEY);         if (keys != null && keys.size() > 0) {             encodeAesKey = keys.get(0);         }         try {             // 1、解码得到aes 密钥             String decodeAesKey = RsaUtils.decodeBase64ByPrivate(keyConfig.getRsaPrivateKey(), encodeAesKey);             // 2、从inputStreamReader 得到aes 加密的内容             String encodeAesContent = new BufferedReader(new InputStreamReader(httpInputMessage.getBody())).lines().collect(Collectors.joining(System.lineSeparator()));             // 3、AES通过密钥CBC解码             String aesDecode = AesUtils.decodeBase64(encodeAesContent, decodeAesKey, keyConfig.getAesIv().getBytes(), AesUtils.CIPHER_MODE_CBC_PKCS5PADDING);             if (!StringUtils.isEmpty(aesDecode)) {                 // 4、重新写入到controller                 this.body = new ByteArrayInputStream(aesDecode.getBytes());             }         } catch (Exception e) {             e.printStackTrace();         }     }      @Override     public InputStream getBody() throws IOException {         return body;     }      @Override     public HttpHeaders getHeaders() {         return headers;     } } 上面的代码注释我觉得都写的清楚了,不多介绍。  EncryptResponseAdvice.java这个类的主要功能就是对返回值进行加密操作  直接在 beforeBodyWrite()  里面执行具体的加密操作即可  supports()  方法也是需要返回 true  ,在 RequestResponseBodyAdviceChain.processBody()  中有个判断只有 supports()  返回 true  才会执行 beforeBodyWrite()   @Slf4j @ControllerAdvice(basePackages = {"top.lrshuai.encrypt.controller"}) public class EncryptResponseAdvice implements ResponseBodyAdvice {      @Autowired     private KeyConfig keyConfig;      @Override     public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {         // return true 有效         return true;     }      /**      * 返回结果加密      * @param obj 接口返回的对象      * @param methodParameter method      * @param mediaType  mediaType      * @param aClass HttpMessageConverter class      * @param serverHttpRequest request      * @param serverHttpResponse response      * @return obj      */     @Override     public Object beforeBodyWrite(Object obj, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {         // 方法或类上有注解         if (Utils.hasMethodAnnotation(methodParameter,new Class[]{Encrypt.class, Encode.class})) {             // 这里假设已经定义好返回的model就是Result             if (obj instanceof Result) {                 try {                     // 1、随机aes密钥                     String randomAesKey = AesUtils.generateSecret(256);                     // 2、数据体                     Object data = ((Result) obj).getData();                     // 3、转json字符串                     String jsonString = JSON.toJSONString(data);                     // 4、aes加密数据体                     String aesEncode = AesUtils.encodeBase64(jsonString, randomAesKey,keyConfig.getAesIv().getBytes(),AesUtils.CIPHER_MODE_CBC_PKCS5PADDING);                     // 5、重新设置数据体                     ((Result) obj).put(Result.DATA,aesEncode);                     // 6、使用前端的rsa公钥加密 aes密钥 返回给前端                     ((Result) obj).put(Result.KEY,RsaUtils.encodeBase64PublicKey(keyConfig.getFrontRsaPublicKey(),randomAesKey));                     // 7、返回                     return obj;                 } catch (Exception e) {                    log.error("加密失败:",e);                 }             }         }         return obj;     } }
  看代码注释,不说了。  2、加密工具类
  加密工具类,我在网上收集整理了一下,搞了个jar。直接在pom.xml 引入即可。如下:   	top.lrshuai.encryption 	encryption-tools 	1.0.3 
  自此核心代码都讲完了,这里只是给出了个demo,可以参考一下(代码写的也不是很好,很多地方也没有封装),加密方式多种多样,都是可以自由更改,这种加密方式不喜欢就改。
  差点忘记了,前端代码呢。  3、前端代码
  前端也是在Github分别找了两个库:  jsencrypt
  这个是RSA加密库,这个是在原版的 jsencrypt  进行增强修改,原版的我用过太长数据加密失败,多此加密解密失败,所以就用了这个库。  CryptoJS
  AES加密库,这个库是Google开源的,有AES、MD5、SHA 等加密方法
  然后我使用的是Vue写的简单页面(业余前端)  html            请求              
字段: Value:
userId:
userName:
age:
info:
AES密钥:
AES向量:
  

要发送的数据:{{parameter}}

加密后的数据:{{encodeContent}}   

收到服务端的内容:{{result}}

解密服务端AES密钥内容:{{decodeAes}}

最终拿到服务端的内容:{{decodeContent}}   主要看 testRequest() 这个方法就行了,都有代码注释。 注意点后端需要注意的就是,controller参数需要用 @RequestBody 包起来,如下: @PostMapping ( "/test1" )   @ResponseBody   public Object test1( @RequestBody (required = false) TestDto dto){   System.out.println( "dto=" +dto);   return Result.ok(dto);   } 而前端传上来的时候header 需要设置"Content-Type": "application/json;charset=utf-8" 最终效果   在上面的postman中 data :里面的数据就是aes加密后的数据 key :里面就是前端RSA公钥加密后的AES密钥(前端需要用私钥解密得到aes密钥,然后再用密钥解开data里面的数据) status :这个是状态码,如果报错了就不是200,不然报错了返回的数据,前端解几百年都解不开。 4、源码地址https://gitee.com/rstyro/spring-boot/tree/master/Springboot2-api-encrypt作者:rstyro 来源: https://rstyro.github.io/blog/2020/10/22/Springboot2接口加解密全过程详解(含前端代码)/


暗黑破坏神不朽圣教军全攻略实用技能与装备流派搭配指南暗黑破坏神不朽的圣教军是一个能抗能输出的职业,拥有强力的AOE与增伤技能。下面请看由Kekays带来的暗黑破坏神不朽圣教军Build全攻略,包含圣教军实用技能与装备流派搭配,希望对异度神剑3打破英国地区系列最佳首销记录看起来任天堂与Monolith工作室合作的异度神剑3有望取得异度系列游戏最佳销量。根据英国数据统计机构给出的信息显示,这款游戏在英国地区的首发销量达到了异度系列游戏的最高峰。在GF世界赛要凉了?V5到底为何临阵换将,xlb真的比karsa强吗随着V5再次将卡萨放入替补席,有关于首发打野xlb的讨论声也逐渐变的越来越大,那么本期玩咖宝典就和大家一起讨论一下V5的季后赛形式,以及xlb与karsa的轮换到底是什么情况。得力众望所归!守望归来全新战令让玩家大呼我可以在守望先锋归来宣布全网免费的时候,就已经有玩家在猜测,接下来是否就应该再出个类似通行证的系统,这样才能够保证游戏的持续收入。果不其然,归来很快就宣布了战令系统的推出计划,并且简单地原神这些4星角色在须弥会有新体验!坐上须弥快车,练起来派蒙新版本整新活?冻梨不能浪费设计师的成果,将其利益最大化菲谢尔,这是目前来看4星之中在须弥混得最好的角色,没有之一。主要是坐上了草雷激化这架大车,并且在多个计算贴中发现,低配的刻香克斯心态爆炸,把自己ID修改为beichu?暗示悲伤真的不行这个赛季里面,除了一些排名靠前的队伍,比较受到大家关注之外,还有一些排名比较靠后的队伍也是如此,因为在这个赛季当中,有一支队伍非常的有趣,那就是WE战队。曾经这支队伍是LPL御三家毁誉参半的暗黑破坏神不朽揭开了动视暴雪的窘境暗黑破坏神不朽国服已于7月25日正式上线!一方面,这款暴雪酝酿了4年之久的暗黑系列第一款手游达到了3500万玩家的预约。在海外上线不到两个月,收入突破1亿美元,成为了吸金速度最快的正能量激励早安图片语录全力以赴,你会很酷无论你年龄多大,无论你学历多高,无论你有没有颜值,都可以去努力实现梦想。不要担忧未来,不要担心跟别人相差太远,只要你开始行动就一切都来得及!周三,早安!行动是成功的阶梯,行动越多,王印祥儿歌歌词二首童年文王印祥童年,童年,你是新绿的春天,花儿的笑脸。童年,童年,你像鲜艳的桃园,美丽着明天。童年,童年,你是燃烧的杜鹃,花儿的梦幻。童年,童年,你像尖尖的小荷,灿烂着明天。啦啦啦,爬满藤蔓的小院今年酷夏,火日炙人,热稍狂,透青天者,久悬火中。虽过三伏节后,目犹光耀,意若曝干,使人闷绝。热中,忽跃出一日凉爽。于是热心欲下楼散步。乘梯步于林阴间,行至隔壁宿墙边,见藤蔓密簇,野句子摘抄生活在阴沟里,依然有仰望星空的权利1人要甘于平凡,但不能在平凡中沉沦。如果别人朝你扔石头,就不要扔回去了,留作你建高楼的基石。运动中的赛跑,是在有限的路程内看你跑了多少时间人生中的赛跑是在有限的时间内看你跑了多少路
能中选?苏群曾凡博或被第二轮选中提前祝福他圆梦NBA曾凡博与北京首钢队签订了对赌协议,一旦没有被选中,下赛季将代表球队出战CBA联赛。还有两天,一年一度的NBA选秀大会就将举行,中国有3名球员曾凡博余嘉豪和郭昊文参选,其中曾凡博备受温网女单资格赛袁悦先丢一盘收获对手退赛礼幸运晋级决赛轮直播吧6月23日讯2022赛季第三项大满贯赛事温布尔登网球公开赛进入到资格赛第3个比赛日的争夺。女单第二轮比赛当中,15号种子袁悦在3653的情况下收获了对手费兰多的退赛大礼,幸运Cba27年广东24次进入季后赛四强,27年全部进入季后赛,辽宁呢?Cba27年,总决赛粤辽有机会相遇三次,三次都被广东踩踏着尸体蹬上冠军宝座,大侄子两次被广东打到哭得死去活来,辽宁一朝得志拿了个冠军就狂到飞上天了?花无千日红,广东早几年不是平淡了又是他!年过35依然是泰山队的定海神针费莱尼用表现征服球迷中超第一轮的首循环已经全部结束,泰山队虽然在开赛阶段比较迷茫,但是随着球队状态的慢慢回归,球队也豪取3连胜,以12个积分高居联赛第3的位置,而老将莫伊塞斯贡献了3球1助,金敬道同样卡特豪宅遭入室盗窃损失10万美元妻子和孩子藏在衣柜里避险直播吧6月23日讯据美媒报道,前NBA巨星文斯卡特在亚特兰大的豪宅遭遇入室盗窃,幸好家人没有受伤,但10万美元被盗。当地时间上周日午夜前,亚特兰大警方在市西北部的国王路上发现一起入巴黎被耍,夺冠拼图不来,接近官宣却泡汤,提供2500万年薪不管用导读在转会市场上,巴黎圣日耳曼频繁掀起波澜,不管是皇家马德里的猎物,还是巴塞罗那的心仪球员,都遭到了法甲豪门的争抢,不过,目前对于这支劲旅而言,最主要的问题还是敲定主教练人选。在巴正式确定!刘志轩离开辽宁男篮,投奔恩师李楠,加盟江苏队根据准确消息,辽宁媒体导演我躺哪CBA透露,刘志轩将离开辽宁男篮,加盟江苏肯帝亚男篮,投奔李楠。其实最近几年休赛期都有关于刘志轩要离开辽宁队的消息,刘志轩与辽宁队的合同已经到期,此只看总冠军MVP等荣誉,CBA十大外援排名是怎样的?很多NBA球星都喜欢到CBA来安度晚年,其中不乏麦迪弗朗西斯肯扬马丁阿泰斯特这样曾经在NBA都能排上号的知名球星,不过只看战绩这几位在CBA就比较惨淡了,尤其麦迪在CBA场均25分恭喜!U20双星闪耀欧洲13球夺联赛亚军,官宣加盟德甲不莱梅中超联赛已经落后高水平联赛太多,不管是俱乐部的竞争力,还是比赛节奏,或者是青训发展,都被高水平联赛甩开巨大差距。因此,优秀的本土球员注定难以在国内联赛取得实质性持续的进步,青训梯队30岁以上球员身价榜萨拉赫居首,梅西在列,C罗本泽马落榜30岁以上的球员在绿茵场上依然凶猛,但在足球转会市场上却在明显地走下坡路。日前,著名的德国转会市场网站更新了30岁以上球员身价榜,没有一名球员身价过亿,萨拉赫以9000万欧元排名榜这八位顶流明星被央视封杀,曾经有多红,现在就有多惨众所周知,央视在我们大多数人眼里是一个最有分量,最有权威的媒体,是不可小觑的平台,也是大众接收新闻,电影电视剧纪录片动画片体育赛事等各类重要信息的平台。对于能登上央视的那些明星,都