springboot3 集成spring-authorization-server (一 基础篇)

官方文档

Spring Authorization Server

环境介绍

java:17

SpringBoot:3.2.0

SpringCloud:2023.0.0

引入maven配置

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth2-authorization-server</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>

AuthorizationServerConfig认证中心配置类

package com.auth.config;

import com.jilianyun.exception.ServiceException;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.RSAKey;
import com.nimbusds.jose.jwk.source.ImmutableJWKSet;
import com.nimbusds.jose.jwk.source.JWKSource;
import com.nimbusds.jose.proc.SecurityContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.server.authorization.client.JdbcRegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer;
import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings;
import org.springframework.security.oauth2.server.authorization.settings.ClientSettings;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher;

import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.UUID;

/**
 * <p>认证中心配置类</p>
 *
 * @author By: chengxuyuanshitang
 * Ceate Time 2024-05-07 11:42
 */

@Slf4j
@EnableWebSecurity
@Configuration(proxyBeanMethods = false)
public class AuthorizationServerConfig {

    /**
     * Security过滤器链,用于协议端点
     *
     * @param http HttpSecurity
     * @return SecurityFilterChain
     */
    @Bean
    public SecurityFilterChain authorizationServerSecurityFilterChain (HttpSecurity http) throws Exception {
        OAuth2AuthorizationServerConfiguration.applyDefaultSecurity (http);
        http.getConfigurer (OAuth2AuthorizationServerConfigurer.class)
                //启用OpenID Connect 1.0
                .oidc (Customizer.withDefaults ());
        http
                // 未从授权端点进行身份验证时重定向到登录页面
                .exceptionHandling ((exceptions) -> exceptions
                        .defaultAuthenticationEntryPointFor (
                                new LoginUrlAuthenticationEntryPoint ("/login"),
                                new MediaTypeRequestMatcher (MediaType.TEXT_HTML)
                        )
                )
                //接受用户信息和/或客户端注册的访问令牌
                .oauth2ResourceServer ((resourceServer) -> resourceServer
                        .jwt (Customizer.withDefaults ()));

        return http.build ();
    }

    /**
     * 用于认证的Spring Security过滤器链。
     *
     * @param http HttpSecurity
     * @return SecurityFilterChain
     */
    @Bean
    public SecurityFilterChain defaultSecurityFilterChain (HttpSecurity http) throws Exception {
        http.authorizeHttpRequests ((authorize) -> authorize
                        .requestMatchers (new AntPathRequestMatcher ("/actuator/**"),
                                new AntPathRequestMatcher ("/oauth2/**"),
                                new AntPathRequestMatcher ("/**/*.json"),
                                new AntPathRequestMatcher ("/**/*.css"),
                                new AntPathRequestMatcher ("/**/*.html")).permitAll ()
                        .anyRequest ().authenticated ()
                )
                .formLogin (Customizer.withDefaults ());
        return http.build ();
    }

    /**
     * 配置密码解析器,使用BCrypt的方式对密码进行加密和验证
     *
     * @return BCryptPasswordEncoder
     */
    @Bean
    public PasswordEncoder passwordEncoder () {
        return new BCryptPasswordEncoder ();
    }

    @Bean
    public UserDetailsService userDetailsService () {
        UserDetails userDetails = User.withUsername ("chengxuyuanshitang")
                .password (passwordEncoder ().encode ("chengxuyuanshitang"))
                .roles ("admin")
                .build ();
        return new InMemoryUserDetailsManager (userDetails);
    }

    /**
     * RegisteredClientRepository 的一个实例,用于管理客户端
     *
     * @param jdbcTemplate    jdbcTemplate
     * @param passwordEncoder passwordEncoder
     * @return RegisteredClientRepository
     */
    @Bean
    public RegisteredClientRepository registeredClientRepository (JdbcTemplate jdbcTemplate, PasswordEncoder passwordEncoder) {
        RegisteredClient registeredClient = RegisteredClient.withId (UUID.randomUUID ().toString ())
                .clientId ("oauth2-client")
                .clientSecret (passwordEncoder.encode ("123456"))
                // 客户端认证基于请求头
                .clientAuthenticationMethod (ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
                // 配置授权的支持方式
                .authorizationGrantType (AuthorizationGrantType.AUTHORIZATION_CODE)
                .authorizationGrantType (AuthorizationGrantType.REFRESH_TOKEN)
                .authorizationGrantType (AuthorizationGrantType.CLIENT_CREDENTIALS)
                .redirectUri ("https://www.baidu.com")
                .scope ("user")
                .scope ("admin")
                // 客户端设置,设置用户需要确认授权
                .clientSettings (ClientSettings.builder ().requireAuthorizationConsent (true).build ())
                .build ();
        JdbcRegisteredClientRepository registeredClientRepository = new JdbcRegisteredClientRepository (jdbcTemplate);
        RegisteredClient repositoryByClientId = registeredClientRepository.findByClientId (registeredClient.getClientId ());
        if (repositoryByClientId == null) {
            registeredClientRepository.save (registeredClient);
        }
        return registeredClientRepository;
    }


    /**
     * 用于签署访问令牌
     *
     * @return JWKSource
     */
    @Bean
    public 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);
    }

    /**
     * 创建RsaKey
     *
     * @return KeyPair
     */
    private static KeyPair generateRsaKey () {
        KeyPair keyPair;
        try {
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance ("RSA");
            keyPairGenerator.initialize (2048);
            keyPair = keyPairGenerator.generateKeyPair ();
        } catch (Exception e) {
            log.error ("generateRsaKey Exception", e);
            throw new ServiceException ("generateRsaKey Exception");
        }
        return keyPair;
    }

    /**
     * 解码签名访问令牌
     *
     * @param jwkSource jwkSource
     * @return JwtDecoder
     */
    @Bean
    public JwtDecoder jwtDecoder (JWKSource<SecurityContext> jwkSource) {
        return OAuth2AuthorizationServerConfiguration.jwtDecoder (jwkSource);
    }

    @Bean
    public AuthorizationServerSettings authorizationServerSettings () {
        return AuthorizationServerSettings.builder ().build ();
    }

}

详细介绍

SecurityFilterChain authorizationServerSecurityFilterChain (HttpSecurity http) 

Spring Security的过滤器链,用于协议端点

SecurityFilterChain defaultSecurityFilterChain (HttpSecurity http)
 Security的过滤器链,用于Security的身份认证

PasswordEncoder passwordEncoder ()
 配置密码解析器,使用BCrypt的方式对密码进行加密和验证

UserDetailsService userDetailsService ()

用于进行用户身份验证

RegisteredClientRepository registeredClientRepository (JdbcTemplate jdbcTemplate, PasswordEncoder passwordEncoder)
用于管理客户端

JWKSource<SecurityContext> jwkSource () 
用于签署访问令牌

 KeyPair generateRsaKey ()
创建RsaKey

 JwtDecoder jwtDecoder (JWKSource<SecurityContext> jwkSource)
解码签名访问令牌

 AuthorizationServerSettings authorizationServerSettings () 

配置Spring Authorization Server的AuthorizationServerSettings实例

初始化自带的数据表

自带的表在spring-security-oauth2-authorization-server-1.2.0.jar 中 下面是对应的截图

对应的SQL

-- 已注册的客户端信息表
CREATE TABLE oauth2_registered_client
(
    id                            varchar(100)                            NOT NULL,
    client_id                     varchar(100)                            NOT NULL,
    client_id_issued_at           timestamp     DEFAULT CURRENT_TIMESTAMP NOT NULL,
    client_secret                 varchar(200)  DEFAULT NULL,
    client_secret_expires_at      timestamp     DEFAULT NULL,
    client_name                   varchar(200)                            NOT NULL,
    client_authentication_methods varchar(1000)                           NOT NULL,
    authorization_grant_types     varchar(1000)                           NOT NULL,
    redirect_uris                 varchar(1000) DEFAULT NULL,
    post_logout_redirect_uris     varchar(1000) DEFAULT NULL,
    scopes                        varchar(1000)                           NOT NULL,
    client_settings               varchar(2000)                           NOT NULL,
    token_settings                varchar(2000)                           NOT NULL,
    PRIMARY KEY (id)
);

-- 认证授权表
CREATE TABLE oauth2_authorization_consent
(
    registered_client_id varchar(100)  NOT NULL,
    principal_name       varchar(200)  NOT NULL,
    authorities          varchar(1000) NOT NULL,
    PRIMARY KEY (registered_client_id, principal_name)
);
/*
IMPORTANT:
    If using PostgreSQL, update ALL columns defined with 'blob' to 'text',
    as PostgreSQL does not support the 'blob' data type.
*/
-- 认证信息表
CREATE TABLE oauth2_authorization
(
    id                            varchar(100) NOT NULL,
    registered_client_id          varchar(100) NOT NULL,
    principal_name                varchar(200) NOT NULL,
    authorization_grant_type      varchar(100) NOT NULL,
    authorized_scopes             varchar(1000) DEFAULT NULL,
    attributes                    blob          DEFAULT NULL,
    state                         varchar(500)  DEFAULT NULL,
    authorization_code_value      blob          DEFAULT NULL,
    authorization_code_issued_at  timestamp     DEFAULT NULL,
    authorization_code_expires_at timestamp     DEFAULT NULL,
    authorization_code_metadata   blob          DEFAULT NULL,
    access_token_value            blob          DEFAULT NULL,
    access_token_issued_at        timestamp     DEFAULT NULL,
    access_token_expires_at       timestamp     DEFAULT NULL,
    access_token_metadata         blob          DEFAULT NULL,
    access_token_type             varchar(100)  DEFAULT NULL,
    access_token_scopes           varchar(1000) DEFAULT NULL,
    oidc_id_token_value           blob          DEFAULT NULL,
    oidc_id_token_issued_at       timestamp     DEFAULT NULL,
    oidc_id_token_expires_at      timestamp     DEFAULT NULL,
    oidc_id_token_metadata        blob          DEFAULT NULL,
    refresh_token_value           blob          DEFAULT NULL,
    refresh_token_issued_at       timestamp     DEFAULT NULL,
    refresh_token_expires_at      timestamp     DEFAULT NULL,
    refresh_token_metadata        blob          DEFAULT NULL,
    user_code_value               blob          DEFAULT NULL,
    user_code_issued_at           timestamp     DEFAULT NULL,
    user_code_expires_at          timestamp     DEFAULT NULL,
    user_code_metadata            blob          DEFAULT NULL,
    device_code_value             blob          DEFAULT NULL,
    device_code_issued_at         timestamp     DEFAULT NULL,
    device_code_expires_at        timestamp     DEFAULT NULL,
    device_code_metadata          blob          DEFAULT NULL,
    PRIMARY KEY (id)
);

application.yml中数据库配置

spring:
  profiles:
    active: dev

  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://192.168.0.1:3306/auth?characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true
    username: auth
    password: 12345

启动AuthServerApplication

启动完成后查看数据库的oauth2_registered_client表中有一条数据;

查看授权服务配置

地址:http://127.0.0.1:8801/.well-known/openid-configuration

访问/oauth2/authorize前往登录页面

地址:ip/端口/oauth2/authorize?client_id=app-client&response_type=code&scope=user&redirect_uri=https://www.baidu.com

实例:

http://127.0.0.1:8801/oauth2/authorize?client_id=app-client&response_type=code&scope=user&redirect_uri=https://www.baidu.com

浏览器跳转到:http://127.0.0.1:8801/login

输入上面配置的密码和账号。我这里都是:chengxuyuanshitang 点击提交。跳转

跳转到

网址栏的地址:https://www.baidu.com/?code=S73PUvl26OSxBc-yBbRRPJMTzcvE2x-VFZGXFPjpvOXHrecbY3Thsj6aOxPdN31H4a6GUgujSc1D4lj9D1ApIUAfZi55YJLqiRLpCivb-Is_4h3grILgR8H8M9UWyhJt

code的值就是=后面的

code=S73PUvl26OSxBc-yBbRRPJMTzcvE2x-VFZGXFPjpvOXHrecbY3Thsj6aOxPdN31H4a6GUgujSc1D4lj9D1ApIUAfZi55YJLqiRLpCivb-Is_4h3grILgR8H8M9UWyhJt

获取token

请求地址:http://127.0.0.1:8801/oauth2/token?grant_type=authorization_code&redirect_uri=https://www.baidu.com&code=S73PUvl26OSxBc-yBbRRPJMTzcvE2x-VFZGXFPjpvOXHrecbY3Thsj6aOxPdN31H4a6GUgujSc1D4lj9D1ApIUAfZi55YJLqiRLpCivb-Is_4h3grILgR8H8M9UWyhJt

用postman请求

添加header参数

header中的 Authorization参数:因为我们用的客户端认证方式 为  client_secret_basic ,这个需要传参,还有一些其他的认证方式,
client_secret_basic: 将 clientId 和 clientSecret 通过 : 号拼接,并使用 Base64 进行编码得到一串字符,再在前面加个 注意有个 Basic   前缀(Basic后有一个空格), 即得到上面参数中的 Basic 。

我的是:app-client:123456

Base64 进行编码:YXBwLWNsaWVudDoxMjM0NTY=

返回:

{
    "access_token": "eyJraWQiOiI2ZTJmYTA5ZS0zMmYzLTQ0MmQtOTM4Zi0yMzJjNDViYTM1YmMiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJjaGVuZ3h1eXVhbnNoaXRhbmciLCJhdWQiOiJhcHAtY2xpZW50IiwibmJmIjoxNzE1MDcxOTczLCJzY29wZSI6WyJ1c2VyIl0sImlzcyI6Imh0dHA6Ly8xMjcuMC4wLjE6ODgwMSIsImV4cCI6MTcxNTA3MjI3MywiaWF0IjoxNzE1MDcxOTczLCJqdGkiOiI0MWI4ZGZmZS03MTI2LTQ4NWYtODRmYy00Yjk4OGE0N2ZlMzUifQ.VxP2mLHt-eyXHZOI36yhVlwC2UQEdAtaRBKTWwJn1bFup0ZjGbZfgxENUb1c03yjcki2H-gCW4Jgef11BMNtjyWSnwMHVWLB9fcT3rRKDQWwoWqBYAcULS8oC5n8qTZwffDSrnjepMEbw4CblL3oH7T9nLProTXQP326RIE1RczsUYkteUCkyIvKTSs3ezOjIVR1GyCs_Cl1A_3OllmkGnSO2q-NKkwasrQjMuuPTY3nhDyDGiefYlfDEcmzz1Yk_FE42P7PEeyqmZwAj7vUnE4brQuNqipaMsS7INe_wTE1kJv-arfbnUo_zQdipHxIhsDgoLaPlSSecQ31QgwEHA",
    "refresh_token": "TqJyWbLWe5Yww6dOV89zDbO0C3YEBA__0TJU_GclmQTAH92SSQ2OvdMChIdln97u1WsA7G7n3BqzNZBjPRU7xmkRooa5ifsMBJ-d3C4kPmuPQI-Bmbq20pck-QEk0Dqt",
    "scope": "user",
    "token_type": "Bearer",
    "expires_in": 300
}

访问接口/userinfo

请求地址:http://127.0.0.1:8801/userinfo

添加header参数:Authorization: Bearer +空格+ ${access_token}




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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

TMS320F280049 CLB模块--LUT4 OUTLUT(4)

LUT4 示意图如下&#xff1a; OUTLUT 示意图如下&#xff1a; 寄存器 参考文档&#xff1a; TMS320F28004x Real-Time Microcontrollers Technical Reference Manual (Rev. G)

2024第十六届“中国电机工程学会杯”数学建模A题思路分析

文章目录 1 赛题思路2 比赛日期和时间3 竞赛信息4 建模常见问题类型4.1 分类问题4.2 优化问题4.3 预测问题4.4 评价问题 5 建模资料 1 赛题思路 (赛题出来以后第一时间在CSDN分享) https://blog.csdn.net/dc_sinor?typeblog 2 比赛日期和时间 报名截止时间&#xff1a;2024…

Apache ECharts

Apache ECharts介绍&#xff1a; Apache ECharts 是一款基于 Javascript 的数据可视化图表库&#xff0c;提供直观&#xff0c;生动&#xff0c;可交互&#xff0c;可个性化定制的数据可视化图表。 官网地址&#xff1a;https://echarts.apache.org/zh/index.html Apache ECh…

上线了《學點笔录》,更方便翻阅笔录

大家好&#xff0c;我是学点&#xff0c;整理了一下自己笔记、摘要、记录《學點笔录》并且上线了为更方便翻阅 https://code.yellowcan.cn 欢迎来我的學點笔录网站&#xff01;笔录会关于与编程有关&#xff0c;比如bug记录、bug解决过程、编程笔记等等&#xff0c;帮助回忆阅…

示例六、湿敏传感器

通过以下几个示例来具体展开学习,了解湿敏传感器原理及特性&#xff0c;学习湿敏传感器的应用&#xff1a; 示例六、湿敏传感器 一、基本原理&#xff1a;随着人们生活水平的不断提高&#xff0c;湿度监控逐步提到议事日程上。由于北方地区秋冬季干燥&#xff0c;需要控制室内…

mamba复现—mamba+yolov8魔改(win)

Mamba复现出现的问题 安装下列步骤一步步走 一、 注&#xff1a;若是Windows环境下python一定是3.10版本的&#xff0c;要不然trition无法安装 conda create -n mamba python3.10 conda activate mamba conda install cudatoolkit11.8 -c nvidia pip install torch2.1.1 t…

在MyBatis中,如何将数据库中的字符串类型映射为枚举类型?

在MyBatis中&#xff0c;如何将数据库中的字符串类型映射为枚举类型&#xff1f; 网上看了很多教程。说了很多&#xff0c;但是都没说到重点&#xff01; 很简单&#xff0c;xml文件中&#xff0c; 使用resultType&#xff0c;而不是使用resultMap就可以了。 resultType"…

示例七、超声波传感器测距

通过以下几个示例来具体展开学习,了解超声波传感器原理及特性&#xff0c;学习超声波传感器的应用&#xff1a; 示例七、超声波传感器测距 一、基本原理&#xff1a; 1、超声波测距仪的系统结构 利用超声测距原理测量物体之间的距离&#xff0c;当此距离小于某一设定值时&…

信创 | 高效信创项目管理:关键步骤与实用技巧!

高效信创项目管理的关键步骤与实用技巧可以从多个维度进行分析和总结。首先&#xff0c;建立有效的工程管理体系是确保信创项目顺利实施的基础&#xff0c;这包括项目管理、质量管理、成本控制等方面的工作。其次&#xff0c;实现项目全流程精细化管理&#xff0c;如信息的及时…

028.实现 strStr()

题意 给你两个字符串 haystack 和 needle &#xff0c;请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标&#xff08;下标从 0 开始&#xff09;。如果 needle 不是 haystack 的一部分&#xff0c;则返回 -1 。 难度 简单 示例 例 1 输入&#xff1a;hays…

Day 44 完全背包理论基础 518. 零钱兑换 II 377. 组合总和 Ⅳ

完全背包理论基础 ​ 完全背包和0-1背包的最大区别在于完全背包里的每个物品的数量都是无限个&#xff0c;而0-1背包每个物品只有一个&#xff1b; 内嵌循环遍历顺序 ​ 回顾一维数组0-1背包的遍历递推公式&#xff1a; for (int i 0&#xff1b; i < weight.size(); i)…

线程知识点

一、线程 1.定义 线程&#xff1a;是一个进程并发执行多种任务的机制。 串行&#xff1a;多个任务有序执行&#xff0c;一个任务执行完毕后&#xff0c;再去执行下一个任务 并发&#xff1a;多个任务在单个CPU上运行&#xff0c;同一个时间片上只能运行一个任务&#xff0c;c…

漫谈AI时代的手机

以chatGPT 为代表的大语言的横空出世使人们感受到AI 时代的到来&#xff0c;大语言模型技术的最大特点是机器开始”懂人话“&#xff0c;”说人话“了。如同任何一个革命性工具的出现一样&#xff0c;它必将改变人类生活和工作。 在这里。我谈谈AI时代的手机。 语音通信的历史…

如何将Hyper-V转VMware?反之亦可

为何要在Hyper-V和VMware之间进行转换呢&#xff1f; 尽管VMware和Microsoft Hyper-V都是当前流行的一类虚拟机监控程序&#xff0c;但它们并不相互兼容。VMware产品使用VMDK格式创建虚拟磁盘&#xff0c;而Hyper-V则使用VHD或VHDX格式创建虚拟磁盘。 有时您可能需要进行这种转…

找不到msvcp120dll,无法继续执行代码的多种解决方法分享

在计算机使用过程中&#xff0c;我们经常会遇到一些错误提示&#xff0c;其中之一就是“msvcp120.dll丢失”。这个错误通常会导致某些应用程序无法正常运行。为了解决这个问题&#xff0c;我们需要采取一些措施来修复丢失的msvcp120.dll文件。本文将介绍6种常见的解决方法&…

cubic 相比 bbr 并非很糟糕

迷信 bbr 的人是被它的大吞吐所迷惑&#xff0c;我也不想再解释&#xff0c;但我得反过来说一下 cubic 并非那么糟。 想搞大吞吐的&#xff0c;看看我这个 pixie 算法&#xff1a;https://github.com/marywangran/pixie&#xff0c;就着它的思路改就是了。 cubic 属于 aimd-ba…

c++ STL 之栈—— stack 详解

vector 是 stl 的一个关联容器,名叫“栈”&#xff0c;何为“栈”&#xff1f;其实就是一个数组&#xff0c;但有了数组何必还需栈&#xff0c;这是一个高深的问题。 一、简介 1. 定义 栈&#xff0c;是一个柔性数组&#xff08;可变长数组&#xff09;&#xff0c;可以变大变小…

【qt】纯代码界面设计

界面设计目录 一.界面设计的三种方式1.使用界面设计器2.纯代码界面设计3.混合界面设计 二.纯代码进行界面设计1.代码界面设计的总思路2.创建项目3.设计草图4.添加组件指针5.初始化组件指针6.添加组件到窗口①水平布局②垂直布局③细节点 7.定义槽函数8.初始化信号槽9.实现槽函数…

最新!TOP200高校!5月ESI排名,公布!

【SciencePub学术】5月9日&#xff0c;ESI数据库更新了2024年5月最新ESI数据。据统计&#xff0c;全球共有9019家科研机构上榜&#xff0c;其中有449所中国内地高校。 ESI&#xff08;基本科学指标数据库&#xff09;是目前世界范围内普遍用以评价高校、学术机构、国家或地区国…

JavaScript 动态网页实例 —— 事件处理应用

前言 事件处理的应用很广泛。在事件处理的应用中,鼠标事件的应用是最常用到的。本章给出几个鼠标事件处理应用的示例,包括:页面预览、图像切换、点亮文本、鼠标跟随、鼠标感应和禁用鼠标按键。在这些示例中,有的可以直接拿来应用,有的则只提供了一种应用的方法,稍加拓展,…