B093-springsecurity整合jwt和RSA

目录

      • 前后端分离后springsecurity核心filter的应用场景介绍
      • JWT令牌的组成部分
      • JWT案例
        • 导包
        • TestJwt
      • RSA
        • RsaUtils
        • TestRSA
        • 分析图
      • JWT+RSA
        • 导包
        • JwtUtils
        • TestRSAJWT
      • 完善spring-security整合后且不连数据库的代码案例
      • 流程
        • 分析图

前后端分离后springsecurity核心filter的应用场景介绍

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
账号密码经过UsernamePasswordAuthenticationFilter封装为UsernamePasswordAuthenticationToken之后密码为二进制就拿不到也无法解密了

/login 由Security框架处理
在这里插入图片描述
用户登录之后的权限列表可以存在JWT里

JWT令牌的组成部分

头部:头部用于描述关于该JWT的最基本的信息,例如其类型以及签名所用的算法等。这也可以被表示成一个JSON对象。

载荷:装数据的地方,

签名:放秘钥的地方,这个部分需要base64加密后的header和base64加密后的payload使用.连接组成的字符串,然后通过header中声明的加密方式进行加盐secret组合加密,然后就构成了jwt的第三部分。

JWT案例

可以携带数据,可以解密

导包

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!-- 单独使用jwt所需的环境:导入jwt使用的依赖坐标-->
<dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>3.4.0</version>
</dependency>
<!-- 工具类-->
<dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId>
</dependency>
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId>
</dependency>
<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.68</version>
</dependency>

TestJwt

import com.alibaba.fastjson.JSONObject;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import org.apache.commons.lang3.time.DateUtils;
import org.example.domain.User;
import org.junit.Test;
import java.util.Date;public class TestJwt {@Testpublic void createJwt(){String sign = JWT.create()//.withHeader()可以不给,默认即可//添加jwt的载荷信息,使用的api方法withClaim(),这个方法在添加数据是以 key-value键值对格式进行添加//本质上,载荷中的信息类似于一个map类型.withClaim("account", "135123123").withClaim("userId", "uuid").withClaim("age", 12)//jwt可以对载荷中的信息,进行有效时间的设置。下面的设置表示:当前jwt令牌有效时间:3分钟.withExpiresAt(DateUtils.addMinutes(new Date(), 3))//设置的值即为  密钥.sign(Algorithm.HMAC256("##@@!!"));System.out.println(sign);//eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9 头部信息经过base64转码之后的字符串// .eyJleHAiOjE2MTkwNTc2OTIsInVzZXJJZCI6InV1aWQiLCJhY2NvdW50IjoiMTM1MTIzMTIzIiwiYWdlIjoxMn0 载荷进行base64加密之后字符串// .JCagRTvVd_dshxGF214TpbGDNIvsj3Lift9x2ZZ-vZw 签证base64加密之后的字符串}@Testpublic void 解析jwt的载荷(){String jwt = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2OTM3OTg3MzgsInVzZXJJZCI6InV1aWQiLCJhY2NvdW50IjoiMTM1MTIzMTIzIiwiYWdlIjoxMn0.AuyeuCeB3OSbmUKjz66tOXrP3yi9uosJdBQOgF2mSuY";//##@@!! 它就是生成jwt时的密钥JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256("##@@!!")).build();//先验签DecodedJWT verify = jwtVerifier.verify(jwt);System.out.println(verify.getClaim("account").asString());System.out.println(verify.getClaim("userId").asString());System.out.println(verify.getClaim("age").asInt());}@Test //传对象public void createJwt2() {//jwt需要保存user对象的信息User user = new User();user.setUserName("admin");user.setPassword("123456");user.setAge(22);String sign = JWT.create()//.withHeader()可以不给,默认即可//添加jwt的载荷信息,使用的api方法withClaim(),这个方法在添加数据是以 key-value键值对格式进行添加//本质上,载荷中的信息类似于一个map类型.withClaim("user", JSONObject.toJSONString(user))//jwt可以对载荷中的信息,进行有效时间的设置。下面的设置表示:当前jwt令牌有效时间:3分钟.withExpiresAt(DateUtils.addMinutes(new Date(), 3))//设置的值即为  密钥.sign(Algorithm.HMAC256("##@@!!999"));System.out.println(sign);//eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9 头部信息经过base64转码之后的字符串// .eyJleHAiOjE2MTkwNTc2OTIsInVzZXJJZCI6InV1aWQiLCJhY2NvdW50IjoiMTM1MTIzMTIzIiwiYWdlIjoxMn0 载荷进行base64加密之后字符串// .JCagRTvVd_dshxGF214TpbGDNIvsj3Lift9x2ZZ-vZw 签证base64加密之后的字符串}@Testpublic void 解析jwt的载荷2(){String jwt = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2OTM4MDAxMzYsInVzZXIiOiJ7XCJhZ2VcIjoyMixcInBhc3N3b3JkXCI6XCIxMjM0NTZcIixcInVzZXJOYW1lXCI6XCJhZG1pblwifSJ9.y2Q7osdt1gtUff8yvHBBK1qjMUvA6JvqBSqDiZ7XcQw";//##@@!! 它就是生成jwt时的密钥JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256("##@@!!999")).build();//先验签DecodedJWT verify = jwtVerifier.verify(jwt);System.out.println(verify.getClaim("user").asString());}
}

RSA

jwt在不同系统间交互时需要让对方知道秘钥对方才能解密读取信息,这样还是不够安全,所以需要RSA

RsaUtils

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;public class RsaUtils {private static final int DEFAULT_KEY_SIZE = 2048;/*** @param filename 公钥保存路径,相对于classpath* @return 公钥对象0* @throws Exception*/public static PublicKey getPublicKey(String filename) throws Exception {byte[] bytes = readFile(filename);return getPublicKey(bytes);}/*** 从文件中读取密钥** @param filename 私钥保存路径,相对于classpath* @return 私钥对象* @throws Exception*/public static PrivateKey getPrivateKey(String filename) throws Exception {byte[] bytes = readFile(filename);return getPrivateKey(bytes);}/*** 获取公钥** @param bytes 公钥的字节形式* @return* @throws Exception*/public static PublicKey getPublicKey(byte[] bytes) throws Exception {bytes = Base64.getDecoder().decode(bytes);X509EncodedKeySpec spec = new X509EncodedKeySpec(bytes);KeyFactory factory = KeyFactory.getInstance("RSA");return factory.generatePublic(spec);}/*** 获取密钥** @param bytes 私钥的字节形式* @return* @throws Exception*/public static PrivateKey getPrivateKey(byte[] bytes) throws NoSuchAlgorithmException,InvalidKeySpecException {bytes = Base64.getDecoder().decode(bytes);PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(bytes);KeyFactory factory = KeyFactory.getInstance("RSA");return factory.generatePrivate(spec);}/*** 根据密文,生存rsa公钥和私钥,并写入指定文件** @param publicKeyFilename  公钥文件路径* @param privateKeyFilename 私钥文件路径* @param secret             生成密钥的密文*/public static void generateKey(String publicKeyFilename, String privateKeyFilename, Stringsecret, int keySize) throws Exception {KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");SecureRandom secureRandom = new SecureRandom(secret.getBytes());keyPairGenerator.initialize(Math.max(keySize, DEFAULT_KEY_SIZE), secureRandom);KeyPair keyPair = keyPairGenerator.genKeyPair();// 获取公钥并写出byte[] publicKeyBytes = keyPair.getPublic().getEncoded();publicKeyBytes = Base64.getEncoder().encode(publicKeyBytes);writeFile(publicKeyFilename, publicKeyBytes);// 获取私钥并写出byte[] privateKeyBytes = keyPair.getPrivate().getEncoded();privateKeyBytes = Base64.getEncoder().encode(privateKeyBytes);writeFile(privateKeyFilename, privateKeyBytes);}private static byte[] readFile(String fileName) throws Exception {return Files.readAllBytes(new File(fileName).toPath());}private static void writeFile(String destPath, byte[] bytes) throws IOException {File dest = new File(destPath);if (!dest.exists()) {dest.createNewFile();}Files.write(dest.toPath(), bytes);}
}

TestRSA

import org.example.utils.RsaUtils;
import org.junit.Test;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;public class TestRSA {@Testpublic void testpass(){BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();String encode = passwordEncoder.encode("123456");System.out.println(encode);}@Testpublic void 创建公私钥对() throws Exception {//String privateFilePath = ResourceUtils.getFile("classpath:rsa").getPath();//String publicFilePath = ResourceUtils.getFile("classpath:rsa.pub").getPath();String privateFilePath = "D:\\(课件 Xmind 图 代码) (总结) (原理)(题目) (预习)\\093-springsecurity整合jwt和RSA\\rsa.pri";String publicFilePath = "D:\\(课件 Xmind 图 代码) (总结) (原理)(题目) (预习)\\093-springsecurity整合jwt和RSA\\rsa.pub";//生成密钥对的公共方法。这个方法需要传入4个参数/*参数1:生成公钥的存储位置参数2:生成私钥的存储位置参数3:生成密钥对的密钥参数3:生成密钥对的长度*/RsaUtils.generateKey(publicFilePath, privateFilePath, "itsource", 2048);//获取私钥System.out.println(RsaUtils.getPrivateKey(privateFilePath));//获取公钥System.out.println(RsaUtils.getPublicKey(publicFilePath));}
}

分析图

在这里插入图片描述

JWT+RSA

导包

<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-api</artifactId><version>0.10.7</version>
</dependency>
<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-impl</artifactId><version>0.10.7</version>
</dependency>
<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-jackson</artifactId><version>0.10.7</version>
</dependency>

JwtUtils

import com.alibaba.fastjson.JSONObject;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.*;/*** 生成token以及校验token相关方法*/
public class JwtUtils {private static final String JWT_PAYLOAD_USER_KEY = "user";/*** 私钥加密token** @param userInfo   载荷中的数据* @param privateKey 私钥* @param expire     过期时间,单位分钟* @return JWT*/public static String generateTokenExpireInMinutes(Object userInfo, PrivateKey privateKey, int expire) {//计算过期时间Calendar c = Calendar.getInstance();c.add(Calendar.MINUTE, expire);return Jwts.builder().claim(JWT_PAYLOAD_USER_KEY, JSONObject.toJSONString(userInfo)).setId(new String(Base64.getEncoder().encode(UUID.randomUUID().toString().getBytes()))).setExpiration(c.getTime()).signWith(privateKey, SignatureAlgorithm.RS256).compact();}/*** 私钥加密token** @param userInfo   载荷中的数据* @param privateKey 私钥* @param expire     过期时间,单位秒* @return JWT*/public static String generateTokenExpireInSeconds(Object userInfo, PrivateKey privateKey, int expire) {//计算过期时间Calendar c = Calendar.getInstance();c.add(Calendar.SECOND, expire);return Jwts.builder().claim(JWT_PAYLOAD_USER_KEY, JSONObject.toJSONString(userInfo)).setId(new String(Base64.getEncoder().encode(UUID.randomUUID().toString().getBytes()))).setExpiration(c.getTime()).signWith(privateKey, SignatureAlgorithm.RS256).compact();}/*** 获取token中的用户信息** @param token     用户请求中的令牌* @param publicKey 公钥* @return 用户信息*/public static Object getInfoFromToken(String token, PublicKey publicKey, Class userType) {//解析tokenJws<Claims> claimsJws = Jwts.parser().setSigningKey(publicKey).parseClaimsJws(token);Claims body = claimsJws.getBody();String userInfoJson = body.get(JWT_PAYLOAD_USER_KEY).toString();return JSONObject.parseObject(userInfoJson, userType);}
}

TestRSAJWT

import org.example.utils.JwtUtils;
import org.example.utils.RsaUtils;
import org.junit.Test;
import org.springframework.util.ResourceUtils;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.HashMap;
import java.util.Map;public class TestRSAJWT {@Test //创建基于RSA的jwt令牌public void rsaCreateTest() throws Exception{//生成jwt令牌的载荷信息Map userinfo = new HashMap() {{ //新写法:jdk1.8新特性put("account", "jack");put("auth", "a,b,c,d");}};//获取私钥:将生成的私钥保存的文件转换为私钥路径对象String path = ResourceUtils.getFile("classpath:rsa.pri").getPath();//构建私钥对象 根据路径转换为私钥对象PrivateKey privateKey = RsaUtils.getPrivateKey(path);//下面的方法,在生成jwt令牌的信息时,是通过RSA的私钥生成String token = JwtUtils.generateTokenExpireInMinutes(userinfo, privateKey, 3);System.out.println(token);// eyJhbGciOiJSUzI1NiJ9// .eyJ1c2VyIjoie1wiYXV0aFwiOlwiYSxiLGMsZFwiLFwiYWNjb3VudFwiOlwiamFja1wifSIsImp0aSI6IlpUQmhPVGMwWmpBdFpESmtaUzAwTkdSaExXRmpOVGd0TVRWbE9UZzVOV0ptWm1GayIsImV4cCI6MTYxOTA1OTUzNH0// .gohQiN6Dg9x0FnyHJw1ecJLCjnijSG3mFXYGC52ewH7F-xvuiCY7Hr9DF_NtWAdk0LkNg8NUYECnOQicmgBG6kDw56NqiHwn1qT003U83gGaGfM0_fCrSrx-J-Kx9qnHASvULbFPPymgrp3vI7KdAM89fORk8j43sJ-G4ASbEC3R-BkIvlNjNUK3WEQIQ5Yahk4ckHYQQZY0DpxyI-gsRGBB1bf1x0YBTrtM0XTlR2NcIZ6LPPCm84ck8ADsJxrQlG8VgOHUjrO4JAwpNOOGaSrAz37-zoEz4qDwfEKVE5HD7kXWb33bHjCRbipOdSopGz9uezHZyn1HloApiQiFDA}@Test //将生成的基于RSA的JWT进行解密,获取载荷的数据public void rsaRead() throws Exception{//解析tokenString token = "eyJhbGciOiJSUzI1NiJ9.eyJ1c2VyIjoie1wiYXV0aFwiOlwiYSxiLGMsZFwiLFwiYWNjb3VudFwiOlwiamFja1wifSIsImp0aSI6IlpESXpNV1F3TURrdE9HSmhZUzAwT0RZNExXRmtOemN0TURBM1lqaGpPREJqWVdGaSIsImV4cCI6MTY5MzgyNTc2Nn0.4NUlipqCiibS2rm0xwFPzCPLwe8go8Ycs9ZGV6UdtS-bdgoa-ZHX2n1q1NajeiRva1koknpVVYnuX-ImRl6WM1JPsZVV8w_WpOvpsohi2OqAo4sAljAx0N7Qo-pLEuUyS6n3zwpgSW-0Z1NNVvCZfPtQZIGHIwk6Cani35EkXMaLhYlec8VGJxdiJKUV4xZDtsa-5-xl5JmLeCA6vjuUcusoGwIjO8j3-0Fd0TCPOwqFYuXA5vcxKM6JfUMjdmKp-BnKsr_65PgP8RtGLjhn037xNjsOLZrxtP2ZjH6rfBCpYE4RPWgt_rV3CA-0n6h_jiyqxYmgm8b4Q6OdSBuhQA";//获取公钥路径String path1 = ResourceUtils.getFile("classpath:rsa.pub").getPath();//构建公钥对象PublicKey publicKey = RsaUtils.getPublicKey(path1);Map infoFromToken = (Map) JwtUtils.getInfoFromToken(token, publicKey, Map.class);System.out.println(infoFromToken.get("account"));System.out.println(infoFromToken.get("auth"));}
}

完善spring-security整合后且不连数据库的代码案例

见代码

流程

config,sevice&filter,注解

分析图

在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/67902.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java设计模式:四、行为型模式-09:模板模式

文章目录 一、定义&#xff1a;模板模式二、模拟场景&#xff1a;模板模式三、改善代码&#xff1a;模板模式3.0 引入依赖3.1 工程结构3.2 模板模式结构图3.3 爬取商品生成海报实现3.3.1 HTTP获取连接类3.3.2 定义执行顺序的抽象类3.3.3 当当爬取抽象实现类3.3.4 京东爬取抽象实…

分享2款微课录制软件,保证让你满意!

“录微课用什么软件呀&#xff0c;真的服了&#xff0c;平台自带的录屏画质太差了&#xff0c;完全看不清讲的内容&#xff0c;而且音质也不是很好&#xff0c;大家有没有微课录制的软件推荐&#xff0c;谢谢啦” 随着教育方式的转型和技术的发展&#xff0c;微课程成为了一种…

422规范详解

概述&#xff1a; 全称为EIA-TIA-422-B&#xff0c;于1994年发布。 典型电路由一个发送器和N个接收器以及一个中断匹配电阻组成。 发送器&#xff1a; 差分输出电压值在2V~10V之间。 4.1.1 发送器输出阻抗 要求A/B之间的差分阻抗≤100Ω。 4.1.2 开路特性 要求差分电压≤…

从过滤器初识责任链设计模式

下面用的过滤器都是注解方式 可以使用非注解方式,就是去web.xml配置映射关系 上面程序的执行输出是 再加一个过滤器 下面来看一段程序 输出结果 和过滤器是否非常相识 但是上面这段程序存在的问题:在编译阶段已经完全确定了调用关系,如果你想改变他们的调用顺序或者继续添加一…

时序预测 | MATLAB实现TCN-BiLSTM时间卷积双向长短期记忆神经网络时间序列预测

时序预测 | MATLAB实现TCN-BiLSTM时间卷积双向长短期记忆神经网络时间序列预测 目录 时序预测 | MATLAB实现TCN-BiLSTM时间卷积双向长短期记忆神经网络时间序列预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 1.MATLAB实现TCN-BiLSTM时间卷积双向长短期记忆神…

淘宝API接口:提高电商运营效率与用户体验的利器(淘宝API接口使用指南)

淘宝API接口&#xff1a;提高电商运营效率与用户体验的利器 随着电商行业的快速发展&#xff0c;淘宝作为国内最大的电商平台之一&#xff0c;不断探索和创新&#xff0c;以满足不断变化的用户需求和商家需求。其中&#xff0c;淘宝API接口便是其创新的一个重要方面。本文将深…

【代码实现】DETR原文解读及代码实现细节

1 模型总览 宏观上来说&#xff0c;DETR主要包含三部分&#xff1a;以卷积神经网络为主的骨干网&#xff08;CNN Backbone&#xff09;、以TRM(Transformer)为主的特征抽取及交互器以及以FFN为主的分类和回归头&#xff0c;如DETR中build()函数所示。DETR最出彩的地方在于&…

[羊城杯 2020] easyphp

打开题目&#xff0c;源代码 <?php$files scandir(./); foreach($files as $file) {if(is_file($file)){if ($file ! "index.php") {unlink($file);}}}if(!isset($_GET[content]) || !isset($_GET[filename])) {highlight_file(__FILE__);die();}$content $_GE…

Spring 6.0和SpringBoot 3.0新特性

目录 主要更新内容是以下几个&#xff1a; AOT编译 Spring Native GraalVM SpringBoot3生成二进制可执行文件底层流程 主要更新内容是以下几个&#xff1a; A Java 17 baselineSupport for Jakarta EE 10 with an EE 9 baselineSupport for generating native images with…

【Sentinel】核心API-Entry与Context

文章目录 一、Entry1、Entry的声明2、使用API自定义资源3、基于SentinelResource注解标记资源 二、Context1、Context介绍2、Context的初始化3、AbstractSentinelInterceptor4、ContextUtil 一、Entry 1、Entry的声明 默认情况下&#xff0c;Sentinel会将controller中的方法作…

46、TCP的“三次握手”

在上一节中&#xff0c;TCP首部常用的几个选项&#xff0c;有些选项的参数就是在通信双方在建立TCP连接的时候进行确定和协商的。所以在学习过TCP报文首部之后&#xff0c;下面我们开始学习TCP的连接建立。 TCP的一个特点是提供可靠的传输机制&#xff0c;还有一个特点就是TCP…

Spring MVC 五 - DispatcherServlet初始化过程(续)

今天的内容是SpringMVC的初始化过程&#xff0c;其实也就是DispatcherServilet的初始化过程。 Special Bean Types DispatcherServlet委托如下一些特殊的bean来处理请求、并渲染正确的返回。这些特殊的bean是Spring MVC框架管理的bean、按照Spring框架的约定处理相关请求&…

leetcode56. 合并区间(java)

合并区间 题目描述贪心算法代码演示 题目描述 难度 - 中等 leetcode56. 合并区间 以数组 intervals 表示若干个区间的集合&#xff0c;其中单个区间为 intervals[i] [starti, endi] 。请你合并所有重叠的区间&#xff0c;并返回 一个不重叠的区间数组&#xff0c;该数组需恰好…

Elasticsearch 对比传统数据库:深入挖掘 Elasticsearch 的优势

当你为项目选择数据库或搜索引擎时&#xff0c;了解每个选项的细微差别至关重要。 今天&#xff0c;我们将深入探讨 Elasticsearch 的优势&#xff0c;并探讨它与传统 SQL 和 NoSQL 数据库的比较。 1. Elasticsearch简介 Elasticsearch 以强大的 Apache Lucene 库为基础&#…

算法通关村第9关【白银】| 二分查找与搜索树高频问题

基于二分查找的拓展问题 1.山脉数组的峰顶索引 思路&#xff1a;二分查找 山峰有三种状态&#xff1a;需要注意数组边界 1.顶峰&#xff1a;arr[mid]>arr[mid1]&&arr[mid]>arr[mid-1] 2.上坡&#xff1a;arr[mid]<arr[mid1] 3.下坡&#xff1a;arr[mid]…

l8-d6 socket套接字及TCP的实现框架

一、socket套接字 /*创建套接字*/ int socket(int domain, int type, int protocol); /*绑定通信结构体*/ int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); /*监听套接字*/ int listen(int sockfd, int backlog); /*处理客户端发起的连接&#xff0…

智能合约安全,著名的区块链漏洞:双花攻击

智能合约安全&#xff0c;著名的区块链漏洞&#xff1a;双花攻击 介绍: 区块链技术通过提供去中心化和透明的系统彻底改变了各个行业。但是&#xff0c;与任何技术一样&#xff0c;它也不能免受漏洞的影响。一个值得注意的漏洞是双花攻击。在本文中&#xff0c;我们将深入研究…

【数据结构练习】栈的面试题集锦

目录 前言&#xff1a; 1.进栈过程中可以出栈的选择题 2.将递归转化为循环 3.逆波兰表达式求值 4.有效的括号 5. 栈的压入、弹出序列 6. 最小栈 前言&#xff1a; 数据结构想要学的好&#xff0c;刷题少不了&#xff0c;我们不仅要多刷题&#xff0c;还要刷好题&#x…

16-MyCat

一 Mycat概述 1 什么是Mycat 什么是Mycat Mycat是数据库中间件&#xff0c;所谓数据库中间件是连接Java应用程序和数据库中间的软件。 为什么要用Mycat 遇到问题&#xff1a; Java与数据库的紧耦合高访问量高并发对数据库的压力读写请求数据不一致 2 Mycat与其他中间件区别 目…

【USRP】调制解调系列6:16APSK、32APSK 、基于labview的实现

APSK APSK是&#xff0c;与传统方型星座QAM&#xff08;如16QAM、64QAM&#xff09;相比&#xff0c;其分布呈中心向外沿半径发散&#xff0c;所以又名星型QAM。与QAM相比&#xff0c;APSK便于实现变速率调制&#xff0c;因而很适合目前根据信道及业务需要分级传输的情况。当然…