当前位置: 首页 > news >正文

基于Spring Security 6的OAuth2 系列之九 - 授权服务器--token的获取

之所以想写这一系列,是因为之前工作过程中使用Spring Security OAuth2搭建了网关和授权服务器,但当时基于spring-boot 2.3.x,其默认的Spring Security是5.3.x。之后新项目升级到了spring-boot 3.3.0,结果一看Spring Security也升级为6.3.0。无论是Spring Security的风格和以及OAuth2都做了较大改动,里面甚至将授权服务器模块都移除了,导致在配置同样功能时,花费了些时间研究新版本的底层原理,这里将一些学习经验分享给大家。

注意由于框架不同版本改造会有些使用的不同,因此本次系列中使用基本框架是 spring-boo-3.3.0(默认引入的Spring Security是6.3.0),JDK版本使用的是19,本系列OAuth2的代码采用Spring Security6.3.0框架,所有代码都在oauth2-study项目上:https://github.com/forever1986/oauth2-study.git

目录

  • 1 OAuth2TokenEndpointFilter原理
    • 1.1 使用Postman获取token
    • 1.2 三种token的作用及内容
    • 1.3 OAuth2TokenEndpointFilter原理
    • 1.4 OAuth2TokenGenerator(token生成器)
    • 1.5 Opaque Token 和 JWT Token
  • 2 自定义JWT加密方式

前面我们对Spring Authrization Server的授权码模式都做了比较详细的解析,也知道通过/oauth2/token接口,可以获取到token,其处理是OAuth2TokenEndpointFilter过滤器,本章我们来更详细说一下OAuth2TokenEndpointFilter过滤器以及token。

1 OAuth2TokenEndpointFilter原理

1.1 使用Postman获取token

之前我们都是使用代码方式的客户端访问授权服务器,现在我们使用非代码方式,一步步看看授权码模式下如何获得token。

1)启动lesson04子模块的授权服务器
2)GET方式访问授权码:http://localhost:9000/oauth2/authorize?client_id=oidc-client&redirect_uri=http://localhost:8080/login/oauth2/code/oidc-client&response_type=code&scope=openid profile 如下图

注意:这里会跳转到登录界面。里面以一个_csrf的value,拷贝下来,登录时需要。

在这里插入图片描述

3)登录授权服务器,把步骤2)中的_csrf复制到此,作为请求body中的一个参数,POST请求:http://localhost:9000/login

注意:这里跳转到授权页面,有一个state返回值,拷贝下来,下一步获取授权code需要传入

在这里插入图片描述

4)获得授权码之前,先将Postman设置为不自动跳转,如下图

在这里插入图片描述

5)获得授权码,将步骤3)中的state拷贝过来作为入参。POST请求访问:http://localhost:9000/oauth2/authorize

注意:这里会获得授权码code,在返回的header的Location属性中,将code拷贝下来,请求token需要

在这里插入图片描述

6)获得token,将步骤5)中的授权码code拷贝过来,访问如下两个图。POST请求:http://localhost:9000/oauth2/token

注意:

  • 设置Body参数,分别是grant_type、code、client_id、redirect_uri
  • 设置Authorization为Basic Auth,因为我们配置的是client_secret_basic;

在这里插入图片描述

设置Authorization的Basic Auth

在这里插入图片描述

7)这时候得到access_token,就是我们需要的最终认证token,我们使用jwt在线解析,就可以看到Header、Payload以及私钥。

关于JWT的相关信息,可以参考《Spring Security 6 系列之集成JWT》

在这里插入图片描述

1.2 三种token的作用及内容

我们从上面步骤6中可以看到返回由三种token:

  • access_token:这个就是我们拥有从资源服务器获取资源需要的token
  • refresh_token:这个是用于刷新access_token使用的token,因为我们默认access_token只有5分钟有效期,需要刷新token才行
  • id_token:这个是基于OIDC1.0协议身份验证的一个token,后面会详细讲OIDC1.0,它是使用JWT格式的。

其中我们来说一下access_token的内容

字段说明
iss (Issuer Identifier)提供认证信息者的唯一标识。一般是一个https的URL
aud (Audience)标识 id_token 的受众。必须包含OAuth2的client_id
nbftoken在该时间之前无效,一般设置签发的时间
scope授权范围
exp (Expiration time)过期时间,超过此时间的id_token会作废不再被验证通过
iat (Issued At Time)token使用JWT发布的时间
auth_time (AuthenticationTime)用户完成认证的时间。如果客户端发送AuthN请求的时候携带max_age的参数,则此Claim是必须的
nonce客户端发送请求的时候提供的随机字符串,用来减缓重放攻击,也可以来关联ID Token和RP本身的Session信息
acr (Authentication Context Class Reference)身份验证上下文类参考
amr (Authentication Methods References)身份验证上下文类参考
azp (Authorized party)被授权方 - 向其颁发 id_token 的一方

1.3 OAuth2TokenEndpointFilter原理

从上面流程知道获取token需要访问/oauth2/token接口,从《系列之八-授权服务器–Spring Authrization Server的基本原理》中得知OAuth2TokenEndpointFilter过滤器是用于拦截/oauth2/token接口的。

1)那么我们先从OAuth2TokenEndpointFilter的doFilter入手,看到是通过authenticationManager,那就是熟悉使用ProviderManager中代理了OAuth2AuthorizationCodeAuthenticationProvider

在这里插入图片描述

2)从OAuth2AuthorizationCodeAuthenticationProvider中,我们看到如下图代码,就是使用tokenGenerator生成token

在这里插入图片描述

3)tokenGenertor也是一个代理DelegatingOAuth2TokenGenerator,里面有多个tokenGenertor。这里默认使用的是JwtGenerator

在这里插入图片描述

4)JwtGenerator中使用jwtEncoder进行生成真正JWT的token

在这里插入图片描述

5)从上面整个流程可以看出,主要是使用tokenGenertor进行生成

1.4 OAuth2TokenGenerator(token生成器)

从上面流程可以知道,最终token都是使用OAuth2TokenGenerator生成器生成,以下是授权服务器常见的生成器
在这里插入图片描述

下面介绍一下不同的token生成器:

  • DelegatingOAuth2TokenGenerator:token生成器代理,用于循环选择适合的token生成器,默认情况下,自动加载3个tokenGenerator生成器,如下图:
    在这里插入图片描述

  • JwtGenerator:生成JWT格式的access_token和id_token,如果客户端配置中oauth2_registered_client表中字段token_settings配置为self-contained时,access_token和id_token由JwtGenerator生成,也就是会生成JWT格式的token
    在这里插入图片描述

  • OAuth2AccessTokenGenerator:生成BASE64的access_token,长度为128,如果客户端配置中oauth2_registered_client表中字段token_settings配置为reference时,access_token和id_token由OAuth2AccessTokenGenerator生成,也就生成BASE64格式的token

  • OAuth2RefreshTokenGenerator:生成刷新refresh_token,也是基于BASE64,长度为128

1.5 Opaque Token 和 JWT Token

我们从上面知道,access_token是可以根据token_settings的配置决定生成的方式,当值为self-contained时,使用JWT Token,当值为reference时,使用BASE64格式。而这种BASE64也称为Opaque Token。大家可以尝试一下,把token_settings配置为reference,token就会是一个无意义的字符串,而JWT Token则是可以解析其中存储的信息。这Opaque Token其实是为了安全,不暴露用户信息。因此如果只是内部系统之间使用,推荐使用JWT Token,如果是共用的,推荐Opaque Token。

2 自定义JWT加密方式

我们从源码OAuth2AuthorizationServerJwtAutoConfiguration可以看到默认情况下是自动生成一个RSA非对称的加密,如下图:

在这里插入图片描述

但是如果使用默认的情况会有2个问题:

  • 安全问题:我们知道密钥是经常需要轮换的,如果使用默认我们就无法定时轮换,当然重新启动就能切换
  • 集群问题:如果我们的授权服务器是一个集群,那么每个服务器的密钥都是不一样,无法实现集群效果

因此我们只需要自定义jwkSource,就可以自己使用自己生成的RSA密钥。

代码参考lesson05子模块

1)生成自己的RSA密钥对,这个可以使用keytool

生成jks,在命令行模式下,执行下面语句
keytool -genkeypair -alias demo -keyalg RSA -keypass linmoo -storepass linmoo -keysize 2048 -keystore demo.jks
这时候会在目录下生成一个demo.jks文件,该文件包括私钥和公钥 。该文件拷贝到项目resources文件下面,供签名使用
在这里插入图片描述

2)新建lesson05子模块,其代码拷贝lesson04子模块的src和resources目录,以及其pom依赖

3)拷贝过来之后,注意:yaml文件中的这2处需要修改,不然mybatis-plus会加载不了entity和handler
在这里插入图片描述

4)SecurityConfig配置jwkSource、jwtDecoder以及读取密钥对的方法

@Configuration
public class SecurityConfig {// 自定义授权服务器的Filter链@Bean@Order(Ordered.HIGHEST_PRECEDENCE)SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)// oidc配置.oidc(withDefaults());// 资源服务器默认jwt配置http.oauth2ResourceServer((resourceServer) -> resourceServer.jwt(withDefaults()));// 异常处理http.exceptionHandling((exceptions) -> exceptions.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login")));return http.build();}// 自定义Spring Security的链路。如果自定义授权服务器的Filter链,则原先自动化配置将会失效,因此也要配置Spring Security@Bean@Order(SecurityProperties.BASIC_AUTH_ORDER)SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {http.authorizeHttpRequests((authorize) -> authorize.requestMatchers("/demo", "/test").permitAll().anyRequest().authenticated()).formLogin(withDefaults());return http.build();}/*** 访问令牌签名*/@Beanpublic JWKSource<SecurityContext> jwkSource() {KeyPair keyPair = generateRsaKey();RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();RSAKey rsaKey = new RSAKey.Builder(publicKey).privateKey(privateKey).keyID(UUID.randomUUID().toString()).build();JWKSet jwkSet = new JWKSet(rsaKey);return new ImmutableJWKSet<>(jwkSet);}/*** 其 key 在启动时生成,用于创建上述 JWKSource*/private static KeyPair generateRsaKey() {KeyStoreKeyFactory factory = new KeyStoreKeyFactory(new ClassPathResource("demo.jks"), "linmoo".toCharArray());KeyPair keyPair = factory.getKeyPair("demo", "linmoo".toCharArray());return keyPair;}
}

5)当然,这个部分我们还可以改进,就是把密钥对放到nacos或者redis上面,这样我们可以手动更新。

结语:本章我们讲解了OAuth2的token以及Spring Security如何实现的底层原理,并自定义jwkSource来实现使用自己的RSA的密钥对。其中还有一个点没有讲,就是token的刷新。下一章我们将详细讲一下如何刷新token以及其代码原理。

相关文章:

基于Spring Security 6的OAuth2 系列之九 - 授权服务器--token的获取

之所以想写这一系列&#xff0c;是因为之前工作过程中使用Spring Security OAuth2搭建了网关和授权服务器&#xff0c;但当时基于spring-boot 2.3.x&#xff0c;其默认的Spring Security是5.3.x。之后新项目升级到了spring-boot 3.3.0&#xff0c;结果一看Spring Security也升级…...

【思维导图】redis

学习计划&#xff1a;将目前已经学的知识点串成一个思维导图。在往后的学习过程中&#xff0c;不断往思维导图里补充&#xff0c;形成自己整个知识体系。对于思维导图里的每个技术知识&#xff0c;自己用简洁的话概括出来&#xff0c; 训练自己的表达能力。...

【Git】使用笔记总结

目录 概述安装Git注册GitHub配置Git常用命令常见场景1. 修改文件2. 版本回退3. 分支管理 常见问题1. git add [中文文件夹] 无法显示中文问题2. git add [文件夹] 文件名中含有空格3. git add 触发 LF 回车换行警告4. git push 提示不存在 Origin 仓库5. Git与GitHub中默认分支…...

cf div3 998 E(并查集)

E : 给出两个简单无向图 &#xff08;没有重边和自环&#xff09;f g . 可以对f 进行 删边 和加边 的操作。问至少操作多少次 &#xff0c;使得 f 和 g 的 点的联通情况相同&#xff08;并查集的情况相同&#xff09; 首先思考删边 &#xff1a; 对于 我 f 图存在边 e &#x…...

【C++】string类(上):string类的常用接口介绍

文章目录 前言一、C中设计string类的意义二、string类的常用接口说明1. string类对象的常见构造2. string类对象的容量操作2.1 size、capacity 和 empty的使用2.2 clear的使用2.3 reserve的使用2.4 resize的使用 3. string类对象的访问及遍历操作3.1 下标[ ] 和 at3.2 迭代器it…...

[SAP ABAP] ABAP SQL跟踪工具

事务码ST05 操作步骤 步骤1&#xff1a;使用事务码ST05之前&#xff0c;将要检测的程序生成的页面先呈现出来&#xff0c;这里我们想看下面程序的取数操作&#xff0c;所以停留在选择界面 步骤2&#xff1a; 新建一个GUI窗口&#xff0c;输入事务码ST05&#xff0c;点击 Acti…...

OpenGL学习笔记(六):Transformations 变换(变换矩阵、坐标系统、GLM库应用)

文章目录 向量变换使用GLM变换&#xff08;缩放、旋转、位移&#xff09;将变换矩阵传递给着色器坐标系统与MVP矩阵三维变换绘制3D立方体 & 深度测试&#xff08;Z-buffer&#xff09;练习1——更多立方体 现在我们已经知道了如何创建一个物体、着色、加入纹理。但它们都还…...

PHP 常用函数2025.02

PHP implode() 函数 语法 implode(separator,array) 参数描述separator可选。规定数组元素之间放置的内容。默认是 ""&#xff08;空字符串&#xff09;。array必需。要组合为字符串的数组。 技术细节 返回值&#xff1a;返回一个由数组元素组合成的字符串。PHP 版…...

17.3.4 颜色矩阵

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 17.3.4.1 矩阵基本概念 矩阵&#xff08;Matrix&#xff09;是一个按照长方阵列排列的复数或实数集合&#xff0c;类似于数组。 由…...

1. 【.NET 8 实战--孢子记账--从单体到微服务--转向微服务】--前言

在我们的专栏《单体开发》中&#xff0c;我们实现了一个简单的记账软件的服务端&#xff0c;并且成功上线。随着用户数量的不断增长&#xff0c;问题逐渐开始显现。访问量逐渐增加&#xff0c;服务端的压力也随之加大。随着访问量的攀升&#xff0c;服务端的响应时间变得越来越…...

02.04 数据类型

请写出以下几个数据的类型&#xff1a; 整数 a ----->int a的地址 ----->int* 存放a的数组b ----->int[] 存放a的地址的数组c ----->int*[] b的地址 ----->int* c的地址 ----->int** 指向printf函数的指针d ----->int (*)(const char*, ...) …...

WPS动画:使图形平移、围绕某个顶点旋转一定角度

1、平移 案例三角形如下图&#xff0c;需求&#xff1a;该三角形的A点平移至原点 &#xff08;1&#xff09;在预想动画结束的位置绘制出图形 &#xff08;2&#xff09;点击选中原始图像&#xff0c;插入/动画/绘制自定义路径/直线 &#xff08;3&#xff09;十字星绘制的直线…...

想表示消息返回值为Customer集合

道奈特(240***10) 14:34:55 EA中序列图。我想表示消息返回值为 Customer 集合。目前只有一个Customer实体类&#xff0c;我需要另外新建一个CustomerList 类吗&#xff1f; 潘加宇(35***47) 17:01:26 不需要。如果是分析&#xff0c;在类的操作中&#xff0c;定义一个参数&…...

93,【1】buuctf web [网鼎杯 2020 朱雀组]phpweb

进入靶场 页面一直在刷新 在 PHP 中&#xff0c;date() 函数是一个非常常用的处理日期和时间的函数&#xff0c;所以应该用到了 再看看警告的那句话 Warning: date(): It is not safe to rely on the systems timezone settings. You are *required* to use the date.timez…...

五、定时器实现呼吸灯

5.1 定时器与计数器简介 定时器是一种通过对内部时钟脉冲计数来测量时间间隔的模块。它的核心是一个递增或递减的寄存器&#xff08;计数器值&#xff09;。如果系统时钟为 1 MHz&#xff0c;定时器每 1 μs 计数一次。 计数器是一种对外部事件&#xff08;如脉冲信号&#xff…...

顺序打印数字的进一步理解

之前博客写了篇博文&#xff0c;面试时要求使用多线程顺序打印ABC循环20次&#xff0c;这是我当时使用join函数实现代码&#xff1a; public class TestABCJoin {public static void main(String[] args) {// 创建任务Runnable taskA () -> {for (int i 0; i < 5; i) …...

使用React和Material-UI构建TODO应用的前端UI

使用React和Material-UI构建TODO应用的前端UI 引言环境准备代码解析1. 导入必要的模块2. 创建React组件3. 定义函数3.1 获取TODO列表3.2 创建TODO项3.3 更新TODO项3.4 删除TODO项3.5 处理编辑点击事件3.6 关闭编辑对话框3.7 保存编辑内容 4. 使用Effect钩子5. 渲染组件 功能实现…...

开屏广告-跳过神器

给大家介绍一款超实用的软件——SKIP&#xff0c;它堪称李跳跳的最佳平替&#xff01;这款软件已经在Github开源免费&#xff0c;完全无需担心内置源问题&#xff0c;也无需导入任何规则。安装完成后&#xff0c;即可直接使用&#xff0c;非常便捷&#xff01; 首次打开软件时…...

bat脚本实现自动化漏洞挖掘

bat脚本 BAT脚本是一种批处理文件&#xff0c;可以在Windows操作系统中自动执行一系列命令。它们可以简化许多日常任务&#xff0c;如文件操作、系统配置等。 bat脚本执行命令 echo off#下面写要执行的命令 httpx 自动存活探测 echo off httpx.exe -l url.txt -o 0.txt nuc…...

如何运行Composer安装PHP包 安装JWT库

1. 使用Composer Composer是PHP的依赖管理工具&#xff0c;它允许你轻松地安装和管理PHP包。对于JWT&#xff0c;你可以使用firebase/php-jwt这个库&#xff0c;这是由Firebase提供的官方库。 安装Composer&#xff08;如果你还没有安装的话&#xff09;&#xff1a; 访问Co…...

(回溯递归dfs 电话号码的字母组合 remake)leetcode 17

只找边界条件和非边界条件&#xff0c;剩下的交给数学归纳法就行&#xff0c;考虑子问题的重复性 [class Solution {vector<string>str { "","","abc","def","ghi","jkl","mno","pqrs"…...

it基础使用--5---git远程仓库

文章目录 it基础使用--5---git远程仓库1. 按顺序看2. 什么是远程仓库3. Gitee操作3.1 新建远程仓库3.2 远程操作基础命令3.3 查看当前所有远程地址别名 git remote -v3.4 创建远程仓库别名 git remote add 别名 远程地址3.4 推送本地分支到远程仓库 git push 别名 分支3.5 拉取…...

Git 的起源与发展

序章&#xff1a;版本控制的前世今生 在软件开发的漫长旅程中&#xff0c;版本控制犹如一位忠诚的伙伴&#xff0c;始终陪伴着开发者们。它的存在&#xff0c;解决了软件开发过程中代码管理的诸多难题&#xff0c;让团队协作更加高效&#xff0c;代码的演进更加有序。 简单来…...

c++提取矩形区域图像的梯度并拟合直线

c提取旋转矩形区域的边缘最强梯度点&#xff0c;并拟合直线 #include <opencv2/opencv.hpp> #include <iostream> #include <vector>using namespace cv; using namespace std;int main() {// 加载图像Mat img imread("image.jpg", IMREAD_GRAYS…...

【PyQt】超级超级笨的pyqt计算器案例

计算器 1.QT Designer设计外观 1.pushButton2.textEdit3.groupBox4.布局设计 2.加载ui文件 导入模块&#xff1a; sys&#xff1a;用于处理命令行参数。 QApplication&#xff1a;PyQt5 应用程序类。 QWidget&#xff1a;窗口基类。 uic&#xff1a;用于加载 .ui 文件。…...

每日一题——小根堆实现堆排序算法

小根堆实现堆排序算法 堆排序的基本思想堆排序的步骤 实现步骤1. 构建小根堆2. 删除最小元素并调整堆 C语言实现输出示例代码解释1. percolateDown 函数2. buildMinHeap 函数3. heapSort 函数4. printArray函数 排序过程详解步骤1&#xff1a;构建小根堆步骤2&#xff1a;删除堆…...

k8s集群

文章目录 项目描述项目环境系统与软件版本概览项目步骤 环境准备IP地址规划关闭selinux和firewall配置静态ip地址修改主机名添加hosts解析 项目步骤一、使用kubeadm安装k8s单master的集群环境&#xff08;1个master2个node节点&#xff09;1、互相之间建立免密通道2.关闭交换分…...

数据分析系列--[11] RapidMiner,K-Means聚类分析(含数据集)

一、数据集 二、导入数据 三、K-Means聚类 数据说明:提供一组数据,含体重、胆固醇、性别。 分析目标:找到这组数据中需要治疗的群体供后续使用。 一、数据集 点击下载数据集 二、导入数据 三、K-Means聚类 Ending, congratulations, youre done....

技术架构师成长路线(2025版)

目录 通用知识 计算机原理&#xff08;1 - 2 个月&#xff09; 数据结构&#xff08;2 - 3 个月&#xff09; 网络编程&#xff08;1 - 2 个月&#xff09; 软件工程&#xff08;1 个月&#xff09; 基础知识 Java 编程语言基础&#xff08;2 - 3 个月&#xff09; JVM&…...

NetLify账号无法登录解决办法

本文收录在【建站】专栏内&#xff0c;专栏目录&#xff1a;【建站】专栏目录 用github账号登录时&#xff0c;说校验失败 Authentication Error Authenticating failed due to the following error: Your account requires additional verification. Please check your email…...

linux本地部署deepseek-R1模型

国产开源大模型追平甚至超越了CloseAI的o1模型&#xff0c;大国崛起时刻&#xff01;&#xff01;&#xff01; DeepSeek R1 本地部署指南   在人工智能技术飞速发展的今天&#xff0c;本地部署AI模型成为越来越多开发者和企业关注的焦点。本文将详细介绍如何在本地部署DeepS…...

集合通讯概览

集合通信概览 &#xff08;1&#xff09;通信的算法 是根据通讯的链路组成的 &#xff08;2&#xff09;因为通信链路 跟硬件强相关&#xff0c;所以每个CCL的库都不一样 芯片与芯片、不同U之间是怎么通信的 多卡训练&#xff1a;多维并行&#xff08;xxx并行在上一期已经讲述…...

如何解决云台重力补偿?

如何解决云台重力补偿? 最近在调试步兵云台的时候,由于枪管、图传、摄像头等重力的原因,pitch轴的参数尤其难以调整,又不想抬升和降低使用两套不同的参数,所以使用了重力补偿,效果也是比较理想的,于是整理为一篇文章记录一下 一、问题根源:枪管重力在“搞事情” 想象…...

【LeetCode 刷题】回溯算法(4)-排列问题

此博客为《代码随想录》二叉树章节的学习笔记&#xff0c;主要内容为回溯算法排列问题相关的题目解析。 文章目录 46.全排列47.全排列 II 46.全排列 题目链接 class Solution:def permute(self, nums: List[int]) -> List[List[int]]:res, path [], []used [0] * len(n…...

FPGA|IP核PLL调用测试:建立工程

闲来无事&#xff0c;测试下FPGA的IP核调用 一、生成工程 1、打开软件新建工程 2、命名为PLL_test 3、选择芯片型号 4、生成工程如图...

数据的表示和运算

一-定点数的表示 1-定点数和浮点数 定点数&#xff1a;小数点的位置固定&#xff08;常规计数&#xff09; 浮点数&#xff1a;小数点的位置不固定&#xff08;科学计数法&#xff09; 2-定点数的表示 ①无符号数 整个机器字长的全部二进制位均为数值位&#xff0c;没有符号…...

文字显示省略号

多行文本溢出显示省略号...

22.Word:小张-经费联审核结算单❗【16】

目录 NO1.2 NO3.4​ NO5.6.7 NO8邮件合并 MS搜狗输入法 NO1.2 用ms打开文件&#xff0c;而不是wps❗不然后面都没分布局→页面设置→页面大小→页面方向→上下左右&#xff1a;页边距→页码范围&#xff1a;多页&#xff1a;拼页光标处于→布局→分隔符&#xff1a;分节符…...

鲸鱼算法 matlab pso

算法原理 鲸鱼优化算法的核心思想是通过模拟座头鲸的捕食过程来进行搜索和优化。座头鲸在捕猎时会围绕猎物游动并产生气泡网&#xff0c;迫使猎物聚集。这一行为被用来设计搜索策略&#xff0c;使算法能够有效地找到全局最优解。 算法步骤 ‌初始化‌&#xff1a;随机生成一…...

c++之模板进阶

在前面的文章中&#xff0c;我们已经简单的了解了模板的使用&#xff0c;在这篇文章中&#xff0c;我们将继续深入探讨模板 1.模板的特化 1.1 概念 通常情况下&#xff0c;使用模板可以实现一些与类型无关的代码&#xff0c;但对于一些特殊类型的可能会得到一些错误的结果&a…...

C语言中的信号量

信号是操作系统中用来传递特定消息的机制。操作系统可以使用这种方式将程序运行过程中发生的各类特殊情况发送给程序&#xff0c;并按照其指定的逻辑进行处理。信号名称都以 “SIG” 作为前缀&#xff0c;如程序访问非法内存时&#xff0c;会产生名为 SIGSEGV 的信号。 程序需…...

AI主流大模型介绍和API价格比较

主流的大模型系列 ###1. OpenAI: GPT-4&#xff0c;GPT-4 Turbo&#xff0c; GPT-4o OpenAI 的介绍&#xff1a; 全称&#xff1a;Open Artificial Intelligence&#xff0c;简称OpenAI。性质&#xff1a;起初为非营利性组织&#xff0c;后转变为由营利性公司OpenAI LP及非营…...

自主Shell命令行解释器

什么是命令行 我们一直使用的"ls","cd","pwd","mkdir"等命令&#xff0c;都是在命令行上输入的&#xff0c;我们之前对于命令行的理解&#xff1a; 命令行是干啥的&#xff1f;是为我们做命令行解释的。 命令行这个东西实际上是我们…...

git笔记-简单入门

git笔记 git是一个分布式版本控制系统&#xff0c;它的优点有哪些呢&#xff1f;分为以下几个部分 与集中式的版本控制系统比起来&#xff0c;不用担心单点故障问题&#xff0c;只需要互相同步一下进度即可。支持离线编辑&#xff0c;每一个人都有一个完整的版本库。跨平台支持…...

重新刷题求职2-DAY1

DAY1 1.704. 二分查找 给定一个 n 个元素有序的&#xff08;升序&#xff09;整型数组 nums 和一个目标值 target &#xff0c;写一个函数搜索 nums 中的 target&#xff0c;如果目标值存在返回下标&#xff0c;否则返回 -1。 最普通的二分查找&#xff0c;查用的习惯左闭右…...

浅析DDOS攻击及防御策略

DDoS&#xff08;分布式拒绝服务&#xff09;攻击是一种通过大量计算机或网络僵尸主机对目标服务器发起大量无效或高流量请求&#xff0c;耗尽其资源&#xff0c;从而导致服务中断的网络攻击方式。这种攻击方式利用了分布式系统的特性&#xff0c;使攻击规模更大、影响范围更广…...

路径规划之启发式算法之二十九:鸽群算法(Pigeon-inspired Optimization, PIO)

鸽群算法(Pigeon-inspired Optimization, PIO)是一种基于自然界中鸽子群体行为的智能优化算法,由Duan等人于2014年提出。该算法模拟了鸽子在飞行过程中利用地标、太阳和磁场等导航机制的行为,具有简单、高效和易于实现的特点,适用于解决连续优化问题。 更多的仿生群体算法…...

SwiftUI 在 Xcode 预览修改视图 FetchedResults 对象的属性时为什么会崩溃?

概览 从 SwiftUI 诞生那天起&#xff0c;让秃头码农们又爱又恨的 Xcode 预览就在界面调试中扮演了及其重要的角色。不过&#xff0c;就是这位撸码中的绝对主角却尝尝在关键时刻“掉链子”。 比如当修改 SwiftUI 视图中 FetchedResults 对象的属性时&#xff0c;Xcode 预览可能…...

pytorch实现基于Word2Vec的词嵌入

PyTorch 实现 Word2Vec&#xff08;Skip-gram 模型&#xff09; 的完整代码&#xff0c;使用 中文语料 进行训练&#xff0c;包括数据预处理、模型定义、训练和测试。 1. 主要特点 支持中文数据&#xff0c;基于 jieba 进行分词 使用 Skip-gram 进行训练&#xff0c;适用于小数…...

MVC 文件夹:架构之美与实际应用

MVC 文件夹:架构之美与实际应用 引言 MVC(Model-View-Controller)是一种设计模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种架构模式不仅提高了代码的可维护性和可扩展性,而且使得开发流程更加清晰。本文将深入探讨MVC文…...