JWT整合Gateway实现鉴权(RSA与公私密钥工具类)

一.业务流程

1.使用RSA生成公钥和私钥。私钥保存在授权中心,公钥保存在网关(gateway)和各个信任微服务中。
2.用户请求登录。
3.授权中心进行校验,通过后使用私钥对JWT进行签名加密。并将JWT返回给用户
4.用户携带JWT访问
5.gateway直接通过公钥解密JWT进行验证
 

二.RSA测试Demo

JWT包含三部分数据
header头部分-Payload载荷(包含用户信息身份)-Signature签名


一.工具类

用户基本信息

package entity;/*** 载荷对象*/
public class UserInfo {private Long id;private String username;public UserInfo() {}public UserInfo(Long id, String username) {this.id = id;this.username = username;}public Long getId() {return this.id;}public void setId(Long id) {this.id = id;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}
}

公钥私钥生成读取类

package utils;import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;public class RsaUtils {/*** 从文件中读取公钥** @param filename 公钥保存路径,相对于classpath* @return 公钥对象* @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 {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 Exception {PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(bytes);KeyFactory factory = KeyFactory.getInstance("RSA");return factory.generatePrivate(spec);}/*** 根据密文,生存rsa公钥和私钥,并写入指定文件** @param publicKeyFilename  公钥文件路径* @param privateKeyFilename 私钥文件路径* @param secret             生成密钥的密文* @throws IOException* @throws NoSuchAlgorithmException*/public static void generateKey(String publicKeyFilename, String privateKeyFilename, String secret) throws Exception {KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");SecureRandom secureRandom = new SecureRandom(secret.getBytes());keyPairGenerator.initialize(1024, secureRandom);KeyPair keyPair = keyPairGenerator.genKeyPair();// 获取公钥并写出byte[] publicKeyBytes = keyPair.getPublic().getEncoded();writeFile(publicKeyFilename, publicKeyBytes);// 获取私钥并写出byte[] privateKeyBytes = keyPair.getPrivate().getEncoded();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);}
}

公钥私钥加解密类

package utils;import entity.UserInfo;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.joda.time.DateTime;import java.security.PrivateKey;
import java.security.PublicKey;public class JwtUtils {/*** 私钥加密token** @param userInfo      载荷中的数据* @param privateKey    私钥* @param expireMinutes 过期时间,单位秒* @return* @throws Exception*/public static String generateToken(UserInfo userInfo, PrivateKey privateKey, int expireMinutes) throws Exception {return Jwts.builder().claim(JwtConstans.JWT_KEY_ID, userInfo.getId()).claim(JwtConstans.JWT_KEY_USER_NAME, userInfo.getUsername()).setExpiration(DateTime.now().plusMinutes(expireMinutes).toDate()).signWith(SignatureAlgorithm.RS256, privateKey).compact();}/*** 私钥加密token** @param userInfo      载荷中的数据* @param privateKey    私钥字节数组* @param expireMinutes 过期时间,单位秒* @return* @throws Exception*/public static String generateToken(UserInfo userInfo, byte[] privateKey, int expireMinutes) throws Exception {return Jwts.builder().claim(JwtConstans.JWT_KEY_ID, userInfo.getId()).claim(JwtConstans.JWT_KEY_USER_NAME, userInfo.getUsername()).setExpiration(DateTime.now().plusMinutes(expireMinutes).toDate()).signWith(SignatureAlgorithm.RS256, RsaUtils.getPrivateKey(privateKey)).compact();}/*** 公钥解析token** @param token     用户请求中的token* @param publicKey 公钥* @return* @throws Exception*/private static Jws<Claims> parserToken(String token, PublicKey publicKey) {return Jwts.parser().setSigningKey(publicKey).parseClaimsJws(token);}/*** 公钥解析token** @param token     用户请求中的token* @param publicKey 公钥字节数组* @return* @throws Exception*/private static Jws<Claims> parserToken(String token, byte[] publicKey) throws Exception {return Jwts.parser().setSigningKey(RsaUtils.getPublicKey(publicKey)).parseClaimsJws(token);}/*** 获取token中的用户信息** @param token     用户请求中的令牌* @param publicKey 公钥* @return 用户信息* @throws Exception*/public static UserInfo getInfoFromToken(String token, PublicKey publicKey) throws Exception {Jws<Claims> claimsJws = parserToken(token, publicKey);Claims body = claimsJws.getBody();return new UserInfo(ObjectUtils.toLong(body.get(JwtConstans.JWT_KEY_ID)),ObjectUtils.toString(body.get(JwtConstans.JWT_KEY_USER_NAME)));}/*** 获取token中的用户信息** @param token     用户请求中的令牌* @param publicKey 公钥* @return 用户信息* @throws Exception*/public static UserInfo getInfoFromToken(String token, byte[] publicKey) throws Exception {Jws<Claims> claimsJws = parserToken(token, publicKey);Claims body = claimsJws.getBody();return new UserInfo(ObjectUtils.toLong(body.get(JwtConstans.JWT_KEY_ID)),ObjectUtils.toString(body.get(JwtConstans.JWT_KEY_USER_NAME)));}
}

辅助类:
 

package utils;import org.apache.commons.lang3.StringUtils;/*** 从jwt解析得到的数据是Object类型,转换为具体类型可能出现空指针,* 这个工具类进行了一些转换*/
public class ObjectUtils {public static String toString(Object obj) {if (obj == null) {return null;}return obj.toString();}public static Long toLong(Object obj) {if (obj == null) {return 0L;}if (obj instanceof Double || obj instanceof Float) {return Long.valueOf(StringUtils.substringBefore(obj.toString(), "."));}if (obj instanceof Number) {return Long.valueOf(obj.toString());}if (obj instanceof String) {return Long.valueOf(obj.toString());} else {return 0L;}}public static Integer toInt(Object obj) {return toLong(obj).intValue();}
}
package utils;public abstract class JwtConstans {public static final String JWT_KEY_ID = "id";public static final String JWT_KEY_USER_NAME = "username";
}
二.测试代码
import entity.UserInfo;
import org.junit.Before;
import org.junit.Test;
import utils.JwtUtils;
import utils.RsaUtils;import java.security.PrivateKey;
import java.security.PublicKey;public class JwtTest {private static final String pubKeyPath = "D:\\tmp\\rsa\\rsa.pub";private static final String priKeyPath = "D:\\tmp\\rsa\\rsa.pri";private PublicKey publicKey;private PrivateKey privateKey;@Testpublic void testRsa() throws Exception {RsaUtils.generateKey(pubKeyPath, priKeyPath, "234");}//在运行生成token之前,获取公钥和私钥对象@Beforepublic void testGetRsa() throws Exception {this.publicKey = RsaUtils.getPublicKey(pubKeyPath);this.privateKey = RsaUtils.getPrivateKey(priKeyPath);}//通过私钥加密@Testpublic void testGenerateToken() throws Exception {// 生成tokenString token = JwtUtils.generateToken(new UserInfo(20L, "jack"), privateKey, 5);System.out.println("token = " + token);}//通过公钥解析token@Testpublic void testParseToken() throws Exception {String token = "eyJhbGciOiJSUzI1NiJ9.eyJpZCI6MjsInVzZXJuYW1lIjoiamFjayIsImV4cCI6MTY3MDAzOTI0M30.Y6MstaAuWwgsNenMRYQSBeG-zx9kHmh75PJuGrJuyPPuetebwqS6Xl2NQGmMYx1mQII-Tq6M-vGGMvQJ8q2Dd8GXL1u-RMC9-e7SKkAgVFP0YzwY3YJRgw9q62snWZqZllmNIgp_jFu14HHHktCS49V-bd1HR9W2PMQoWOeWquI";// 解析tokenUserInfo user = JwtUtils.getInfoFromToken(token, publicKey);System.out.println("id: " + user.getId());System.out.println("userName: " + user.getUsername());}
}
三.测试流程


指定路径一定包括rsa







三.Spring Cloud+Gateway+RSA


一.gateway模块:
yml文件

定义白名单(不需要鉴权的路径),公钥地址(解密鉴权),以及cookieName(获取加密的token)

配置类:

获取公钥

package com.yigou.gw.config;import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
import utils.RsaUtils;import javax.annotation.PostConstruct;
import java.security.PublicKey;@ConfigurationProperties(prefix = "yigou.jwt")
@Data
@Slf4j
public class JwtProperties {private String pubKeyPath;// 公钥private PublicKey publicKey; // 公钥private String cookieName;//@PostConstruct注解的方法将会在依赖注入完成后被自动调用。//执行顺序:Constructor >> @Autowired >> @PostConstruct@PostConstructpublic void init(){try {// 获取公钥和私钥this.publicKey = RsaUtils.getPublicKey(pubKeyPath);} catch (Exception e) {log.error("初始化公钥失败!", e);throw new RuntimeException();}}
}

获取定义的白名单对象

package com.yigou.gw.config;import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;import java.util.List;@ConfigurationProperties(prefix = "yigou.filter")
@Data
public class FilterProperties {private List<String> allowPaths;
}
自定义拦截:
package com.yigou.gw.filter;import com.yigou.gw.config.FilterProperties;
import com.yigou.gw.config.JwtProperties;
import entity.UserInfo;
import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.filter.OrderedFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import utils.JwtUtils;import java.util.List;@Component
@EnableConfigurationProperties({JwtProperties.class, FilterProperties.class})
@Slf4j
public class LoginFilter implements GlobalFilter, Ordered {@Autowiredprivate JwtProperties prop;@Autowiredprivate FilterProperties fprop;//核心过滤器方法@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {//设置白名单,白名单里面的请求路径,直接放行String path = exchange.getRequest().getPath().toString();List<String> allowPaths = fprop.getAllowPaths();for (String allowPath : allowPaths) {//判断path是否以allowPath开头if (path.startsWith(allowPath)){//放行return chain.filter(exchange);}}//1.获取请求中的tokenHttpCookie cookie = exchange.getRequest().getCookies().getFirst(prop.getCookieName());String token=null;if (cookie!=null){token=cookie.getValue();}log.info("token:",token);try {//2.解析tokenUserInfo userInfo = JwtUtils.getInfoFromToken(token, prop.getPublicKey());//3.放行if (userInfo!=null){return chain.filter(exchange);}} catch (Exception e) {e.printStackTrace();//如果出现异常,设置异常状态exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);}return exchange.getResponse().setComplete();}//过滤器执行顺序@Overridepublic int getOrder() {return 0;}
}
功能总结:

1.使用yml配置获取公钥存储路径以及白名单路径。
2.通过路径得到公钥,自定义拦截器先去对比是否为白名单路径,若为白名单路径直接放行。
3.若不为白名单  通过cookieName得到存储的token,并使用公钥解析是否可以获得userinfo对象来判断是否放行。

二.鉴权中心模板:
yml文件:
server:port: 8087
spring:application:name: auth-servicecloud:nacos:discovery:server-addr: http://192.168.147.129:8848yigou:jwt:secret: yigou@Login(Auth}*^31)&javaman% # 登录校验的密钥pubKeyPath: D:\\tmp\\rsa\\rsa.pub # 公钥地址priKeyPath: D:\\tmp\\rsa\\rsa.pri # 私钥地址expire: 1800 # 过期时间,单位秒cookieName: YG_TOKENcookieMaxAge: 1800
配置文件:
package com.yigou.auth.config;import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
import utils.RsaUtils;import javax.annotation.PostConstruct;
import java.io.File;
import java.security.PrivateKey;
import java.security.PublicKey;@ConfigurationProperties(prefix = "yigou.jwt")
@Data
@Slf4j
public class JwtProperties {private String secret; // 密钥private String pubKeyPath;// 公钥private String priKeyPath;// 私钥private int expire;// token过期时间private PublicKey publicKey; // 公钥private PrivateKey privateKey; // 私钥private String cookieName;private Integer cookieMaxAge;/*** @PostContruct:在构造方法执行之后执行该方法*/@PostConstructpublic void init(){try {File pubKey = new File(pubKeyPath);File priKey = new File(priKeyPath);if (!pubKey.exists() || !priKey.exists()) {// 生成公钥和私钥RsaUtils.generateKey(pubKeyPath, priKeyPath, secret);}// 获取公钥和私钥this.publicKey = RsaUtils.getPublicKey(pubKeyPath);this.privateKey = RsaUtils.getPrivateKey(priKeyPath);} catch (Exception e) {log.error("初始化公钥和私钥失败!", e);throw new RuntimeException();}}// getter setter ...
}
controller
package com.yigou.auth.controller;import com.yigou.auth.config.JwtProperties;
import com.yigou.auth.service.AuthService;
import com.yigou.common.enums.ExceptionEnum;
import com.yigou.common.exception.YgException;
import com.yigou.common.utils.CookieUtils;
import com.yigou.user.entity.TbUser;
import entity.UserInfo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import utils.JwtUtils;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;@RestController
@EnableConfigurationProperties(JwtProperties.class)
public class AuthController {@Autowiredprivate JwtProperties prop;@Autowiredprivate AuthService authService;//接收用户名和密码,通过密钥加密生成JWT,写入到cookie中保存@PostMapping("/accredit")public ResponseEntity<Void> authentication(@RequestParam("username") String username,@RequestParam("password") String password,HttpServletResponse response,HttpServletRequest request){//1.验证之后,生成JWT-tokenString token=authService.authentication(username,password);//2.如果token是空的,验证失败if(StringUtils.isEmpty(token)){return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();}//3.如果不为空,说明不为空,返回token存放到cookie中CookieUtils.setCookie(request,response,prop.getCookieName(),token,prop.getCookieMaxAge(),true);return ResponseEntity.ok().build();}//验证用户信息,如果用户信息验证成功,返回用户信息@GetMapping("verify")public ResponseEntity<UserInfo> verify(@CookieValue("YG_TOKEN") String token,HttpServletRequest request,HttpServletResponse response){//1.根据token解析获取到的cookie中的tokentry {UserInfo userInfo = JwtUtils.getInfoFromToken(token, prop.getPublicKey());//重新生成tokenString newToken = JwtUtils.generateToken(userInfo, prop.getPrivateKey(), prop.getExpire());//重新把Token设置到cookie中,覆盖原来的cookieCookieUtils.setCookie(request,response,prop.getCookieName(),newToken, prop.getCookieMaxAge());return ResponseEntity.ok(userInfo);} catch (Exception e) {throw new YgException(ExceptionEnum.USER_TOKEN_EXISTS_FALL);}}
}
service:
package com.yigou.auth.service.impI;import com.yigou.auth.client.UserClient;
import com.yigou.auth.config.JwtProperties;
import com.yigou.auth.service.AuthService;
import com.yigou.common.enums.ExceptionEnum;
import com.yigou.common.exception.YgException;
import com.yigou.user.entity.TbUser;
import entity.UserInfo;
import lombok.ToString;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import utils.JwtUtils;@Service
public class AuthServiceImpl implements AuthService {@Autowiredprivate UserClient userClient;@Autowiredprivate JwtProperties prop;//验证用户名和密码之后,生成jwt-token@Overridepublic String authentication(String username, String password) {//1.通过用户名,密码验证是否存在TbUser user = userClient.getUserInfo(username, password);if (user==null){return null;}//2.生成tokenUserInfo userInfo = new UserInfo();userInfo.setId(user.getId());userInfo.setUsername(user.getUsername());try {String token = JwtUtils.generateToken(userInfo, prop.getPrivateKey(), prop.getExpire());return token;} catch (Exception e) {throw new YgException(ExceptionEnum.JWT_TOKEN_CREATE_fALL);}}
}
调用接口
package com.yigou.auth.client;import com.yigou.user.api.UserApi;
import org.springframework.cloud.openfeign.FeignClient;@FeignClient("user-service")
public interface UserClient extends UserApi {
}
三.注意点:
1.使用Feign调用其他模块方法:

将提供模块的对外接口包以及httpclient依赖到调用模块

 <!--httpclient支持--><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId></dependency>

调用模块的接口类继承提供模块对外开放的接口类

注释@FeignClient的参数名和提供模块在注册中心的名相同。

2.提供模块建立对外接口包

对外接口类 所提供方法 要与controller方法行映射

3.调用模块主函数开启FeignClients
package com.yigou.auth;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.cloud.openfeign.FeignClient;@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
@EnableDiscoveryClient
@EnableFeignClients
public class    YgAuthServiceApplication {public static void main(String[] args) {SpringApplication.run(YgAuthServiceApplication.class, args);}}
四.总结

1.登录请求通过网关(登录为白名单 因此不会拦截校验),网关转发到授权中心模块
2.授权中心模块通过前端发送的用户信息feign调用用户模块查询用户信息。根据是否有该用户来判断是否使用该用户信息以及拿到yml定义的私钥路径去生成token存入cookie中。


3.若登陆成功 那么随后每次请求都会携带cookie中的token 在网关进行拦截以及公钥解密。每次鉴权都会在鉴权模块将token重新刷新一遍。

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

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

相关文章

数据库 | 试卷五试卷六试卷七

1. 主码不相同&#xff01;相同的话就不能唯一标识非主属性了 2.从关系规范化理论的角度讲&#xff0c;一个只满足 1NF 的关系可能存在的四方面问题 是&#xff1a; 数据冗余度大&#xff0c;插入异常&#xff0c;修改异常&#xff0c;删除异常 3.数据模型的三大要素是什么&…

15. STUN协议和ICE工作原理

NET介绍 NAT是一种地址转换技术&#xff0c;它可以将IP数据报文头中的IP地址转换为另一个IP地址&#xff0c;并通过转换端口号达到地址重用的目的。 在大多数网络环境中&#xff0c;我们都需要通过 NAT 来访问 Internet。 NAT作为一种缓解IPv4公网地址枯竭的过渡技术&#xff…

AMBA-CHI协议详解(三)

《AMBA 5 CHI Architecture Specification》 AMBA-CHI协议详解&#xff08;一&#xff09; AMBA-CHI协议详解&#xff08;二&#xff09; AMBA-CHI协议详解&#xff08;三&#xff09; AMBA-CHI协议详解&#xff08;四&#xff09; 文章目录 2.3.2 Write transactions2.3.2.1 …

keil5显示内存和存储占用百分比进度条工具

简介 [Keil5_disp_size_bar] 以进度条百分比来显示keil编译后生成的固件对芯片的内存ram和存储flash的占用情况, 并生成各个源码文件对ram和flash的占比整合排序后的map信息的表格和饼图。 原理是使用C语言遍历当前目录找到keil工程和编译后生成的map文件 然后读取工程文件和m…

若依框架自定义开发使用学习笔记(1)

因为我是跳着学的&#xff0c;原理那些都没咋看。 代码自动生成&#xff0c;依赖sql表 在ruoyi数据库中&#xff0c;创建你想要的表&#xff0c;这里我创建了个购物车表&#xff0c;由于空间有限&#xff0c;只能拍到这么多。 然后就可以在前端自动生成代码 点击导入按钮 …

创新入门 | 病毒循环Viral Loop是什么?为何能实现指数增长

今天&#xff0c;很多高速增长的成功创业公司都在采用”病毒循环“的策略去快速传播、并扩大用户基础。究竟什么是“病毒循环”&#xff1f;初创公司的创始人为何需要重视这个策略&#xff1f;这篇文章中将会一一解答与病毒循环有关的各种问题。 一、什么是病毒循环&#xff08…

【Ruby基础01】windows和termux中搭建Ruby开发环境

windows下环境搭建 railsinstaller官方git地址 按照文档安装git、nodejs、yarn&#xff0c;安装教程百度一下。railsinstall可以从release页面下载最新版本4.1.0。 安装完成如下 安装RubyMine 下载RubyMine RubyMine下载地址 安装激活 下载文件&#xff0c;按照里面的流程…

Java 读取Excel导入数据库,形成树状结构

最近开发过程中遇到一个Excel的导入的功能,因为导入的数据结构具有层次结构,经过一番研究,最终得以实现,所有写下该文章,记录过程,供以后参考。 下图是导入Excel的数据结构: 使用POI解析Excel,数据封装然后进行入库。下面是核心代码。 @Overridepublic KnowledgeBase…

示例:WPF中如何不卡顿页面的情况加载大量数据

一、目的&#xff1a;在开发过程中经常会遇到一个ListBox列表里面需要加载大量数据&#xff0c;但是加载过程中会假死卡顿影响用户体验&#xff0c;或者是你的主页面加载了大量控件&#xff0c;或者切换到一个有大量元素的页面都会有这种体验&#xff0c;因为加载的都是UI元素不…

基于matlab的RRT算法路径规划(附带案例源码)

文章中的所有案例均为博主手动复现&#xff0c;用于记录博主学习路径规划的过程&#xff0c;如有不妥&#xff0c;欢迎在评论区交流 目录 1 标准RRT1.1 算法原理1.2 演示 2 GBRRT2.1 算法原理2.2 算法演示 3 RRT-STAR3.1 算法原理3.2 算法演示 4 RRT-CONNECT4.1 算法原理4.2 算…

了解指标体系1:指标是大数据开发中的关键要素

在大数据开发的过程中&#xff0c;指标体系是一个至关重要的概念。本文将介绍什么是指标&#xff0c;为什么它们如此重要&#xff0c;以及如何在大数据项目中有效地构建和应用指标体系。 目录 什么是指标&#xff1f;指标的类型为什么指标如此重要&#xff1f;如何构建有效的指…

Swift开发——存储属性与计算属性

Swift语言开发者建议程序设计者多用结构体开发应用程序。在Swift语言中,结构体具有了很多类的特性(除类的与继承相关的特性外),具有属性和方法,且为值类型。所谓的属性是指结构体中的变量或常量,所谓的方法是指结构体中的函数。在结构体中使用属性和方法是因为:①匹别于结…

每日一练:攻防世界:miao~

给了一张jpg图片 没发现什么特别&#xff0c;放到winhex中查看也没思路。 放到kali里面foremost分离文件试试&#xff0c;结果分离出个wav音频文件 直接放到 audycity看看频谱图 发现字符串&#xff0c;但是没有其他信息。可能是密钥之类的。到这里我就卡住了&#xff0c;看…

镜像拉取失败:[ERROR] Failed to pull docker image

问题描述 执行 bash docker/scripts/dev_start.sh 命令提示错误&#xff1a; permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Post “http://%2Fvar%2Frun%2Fdocker.sock/v1.45/images/create?fromImageregistry.b…

微信小程序-上拉加载和下拉刷新

一.上拉加载 微信小程序的上拉加载使用onReachBottom()&#xff0c;写在.js文件里面的Page方法里面。 onReachBottom(){//上拉自动更新到4&#xff0c;5&#xff0c;6wx.showLoading({title: 数据加载中...,})setTimeout(()>{const lastNumthis.data.numList[this.data.nu…

Ubuntu网络管理命令:nslookup

安装Ubuntu桌面系统&#xff08;虚拟机&#xff09;_虚拟机安装ubuntu桌面版-CSDN博客 nslookup命令主要用来查询域名信息&#xff0c;实际上主要是将域名转换为相应的IP地址&#xff0c;或者将IP地址转换成相应的域名。nslookup命令为用户提供了两种工作模式&#xff0c;分别…

matlab线性多部法求常微分方程数值解

用Adamas内差二步方法&#xff0c;内差三步方法&#xff0c;外差二步方法&#xff0c;外差三步方法这四种方法计算。 中k为1和2. k为2和3 代码 function chap1_adams_methodu0 1; T 2; h 0.1; N T/h; t 0:h:T; solu exact1(t);f f1; u_inter_2s adams_inter_2steps(…

项目训练营第二天

项目训练营第二天 用户登录逻辑 1、账户名不少于4位 2、密码不少于8位 3、数据库表中能够查询到账户、密码 4、密码查询时用同样加密脱敏处理手段处理后再和数据库中取出字段进行对比&#xff0c;如果账户名未查询到&#xff0c;直接返回null 5、后端设置相应的脱敏后用户的s…

就因为没在大屏项目加全屏按钮,早上在地铁挨了领导一顿骂

“嗯嗯”&#xff0c;“嗯嗯”&#xff0c;“那产品也没说加呀”&#xff0c;“按F11不行吗&#xff1f;”&#xff0c;“嗯嗯”&#xff0c;“好的”。 早上在4号线上&#xff0c;我正坐在地铁里&#xff0c;边上站着的妹子&#xff0c;我看他背着双肩包&#xff0c;打着电话…

即时到账支付系统源码第四方支付平台源码(支付宝/QQ钱包/微信二维码收款+附配套软件)

即时到账支付系统源码第四方支付平台源码价值10万&#xff0c;支付宝/QQ钱包/微信二维码收款&#xff0c;附配套软件 开发语言&#xff1a;phpmysql 这个是一个可以跟码支付一样用自己的二维码收款的网站 还可以作为即时到账 代收款 或者易支付使用后台配置好就行&#xff…