Spring Authorization Server登出说明与实践
本章内容概览
Spring Security
提供的/logout
登出接口做了什么与如何自定义。Spring Authorization Server
提供的/connect/logout
登出接口做了什么与如何自定义。Spring Authorization Server
提供的/oauth2/revoke
撤销token接口做了什么与如何自定义。
前言
既然系统中有登录功能,那么必然也会有登出的需要,登出的效果一般都是清除认证相关的Session
,同时也要让access token
无效化,换而言之就是清除当前用户认证相关的状态,使用户在项目中回到未认证状态,因为表单登录以后存储在Session
中的状态和请求携带access token
访问后端时都代表着用户的认证信息,有了这些认证信息才代表着用户登录过,可以继续接下来的操作。
本章基本上是理论与实验性的内容,编码内容很少,内容可能也会比较多,请大家耐心观看。
Spring Security
提供的/logout
访问方式
浏览器直接访问http://127.0.0.1:8080/logout
(地址栏直接输入该地址后按回车)
其中127.0.0.1
是认证服务所在服务器的ip,8080
是认证服务对外提供服务的端口。
分析
该接口是Security
提供的一个接口,该接口是过滤器LogoutFilter
拦截处理的,在过滤器内分别调用了LogoutHandler
与LogoutSuccessHandler
来处理登出的逻辑和登出成功的逻辑,跟踪源码可知具体处理登出的是SecurityContextLogoutHandler
,在该类中根据当前请求获取Http Session
并销毁,之后清除SecurityContextRepository
中保存的认证信息,之后就是登出成功的处理了,处理登出成功的是SimpleUrlLogoutSuccessHandler
,该类中会默认重定向至defaultTargetUrl
属性的值(应该为url),默认情况下启动时在加载LogoutFilter
时会初始化一个SimpleUrlLogoutSuccessHandler
的实例给登出过滤器使用,默认会设置defaultTargetUrl
属性的值为/login?logout
;大致逻辑就是这样。
自定义
根据上边的分析可知有两个很明显的扩展点,一个是登出处理,一个是登录成功处理,大部分情况下只需要自定义登录成功处理即可,那么该如何配置?请看下方示例代码
在认证相关的过滤器中添加如下代码
// 自定义登出配置
http.logout(logout -> logout// 定义登出路径.logoutUrl("/logout")// 登出时同步撤销Token.addLogoutHandler(new RevokeAccessTokenLogoutHandler(serverProperties))// 自定义登出成功响应处理.logoutSuccessHandler(new JsonLogoutSuccessHandler())
);
RevokeAccessTokenLogoutHandler
的具体实现
package com.example.authorization.handler;import com.example.model.Result;
import com.example.util.JsonUtils;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.http.*;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings;
import org.springframework.security.web.authentication.logout.LogoutHandler;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.ObjectUtils;
import org.springframework.web.client.RestTemplate;import java.nio.charset.StandardCharsets;/*** 登出处理-撤销token** @author vains*/
@Slf4j
@RequiredArgsConstructor
public class RevokeAccessTokenLogoutHandler implements LogoutHandler {private final ServerProperties serverProperties;private final AuthorizationServerSettings authorizationServerSettings;private final RestTemplate restTemplate = new RestTemplate();@Override@SneakyThrowspublic void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {// 获取token(可以是Access Token,也可以是Refresh Token)String token = request.getParameter(OAuth2ParameterNames.TOKEN);if (ObjectUtils.isEmpty(token)) {// 写回json数据Result<String> result = Result.error("token is empty");response.setCharacterEncoding(StandardCharsets.UTF_8.name());response.setContentType(MediaType.APPLICATION_JSON_VALUE);response.getWriter().write(JsonUtils.objectCovertToJson(result));response.getWriter().flush();response.getWriter().close();return;}// 撤销token逻辑Integer port = serverProperties.getPort();// 撤销token地址String revokeUrl = "http://127.0.0.1:"+ (port == null ? "8080" : port)// 默认是/oauth2/revoke+ authorizationServerSettings.getTokenRevocationEndpoint();MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();formData.add(OAuth2ParameterNames.TOKEN, token);// 准备请求的headerHttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);headers.add(HttpHeaders.AUTHORIZATION, "Basic " + HttpHeaders.encodeBasicAuth("messaging-client", "123456", StandardCharsets.UTF_8));// 封装请求HttpEntity<MultiValueMap<String, String>> entity = new HttpEntity<>(formData, headers);// 撤销token,默认无响应try {ResponseEntity<String> responseEntity = restTemplate.postForEntity(revokeUrl, entity, String.class);if (responseEntity.getStatusCode().is2xxSuccessful()) {log.info("revoked access token");}} catch (Exception e) {log.warn("revoked access token failed, cause: {}", e.getMessage());// 撤销token失败写回json数据Result<String> result = Result.error("revoked access token failed, cause: " + e.getMessage());response.setCharacterEncoding(StandardCharsets.UTF_8.name());response.setContentType(MediaType.APPLICATION_JSON_VALUE);response.getWriter().write(JsonUtils.objectCovertToJson(result));response.getWriter().flush();response.getWriter().close();}}}
JsonLogoutSuccessHandler
的具体实现,可以在该类中响应json或自己实现重定向逻辑
package com.example.authorization.handler;import com.example.model.Result;
import com.example.util.JsonUtils;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;import java.io.IOException;
import java.nio.charset.StandardCharsets;/*** 登出成功自定义处理** @author vains*/
@Slf4j
public class JsonLogoutSuccessHandler implements LogoutSuccessHandler {@Overridepublic void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {log.info("onLogoutSuccessHandler");// 写回json数据Result<String> result = Result.success();response.setCharacterEncoding(StandardCharsets.UTF_8.name());response.setContentType(MediaType.APPLICATION_JSON_VALUE);response.getWriter().write(JsonUtils.objectCovertToJson(result));response.getWriter().flush();// 或重定向至某个url// 重定向操作...略}}
这样就可以在销毁当前Session的情况下撤销token了,如图
未带token参数示例,如图
现在就完成了销毁Session与撤销token的步骤。
Spring Authorization Server
提供的/connect/logout
该接口是Openid Connect 1.0 协议中规定的一个接口。
访问方式
浏览器直接访问http://127.0.0.1:8080/connect/logout?id_token_hint={id_token}&post_logout_redirect_uri={客户端信息中配置的post_logout_redirect_uri}
(地址栏直接输入该地址后按回车)
参数说明:
参数 | 描述 | 描述 |
---|---|---|
id_token_hint | OAuth2授权登录以后获取的id token | 协议中是推荐传入,但是在Authorization Server中必填 |
post_logout_redirect_uri | 客户端信息中配置的post_logout_redirect_uri | 登出后重定向的地址,不传会走默认登出处理 |
更多参数说明详见:spec openid-connect-rpinitiated-1_0 RPLogout
其中127.0.0.1
是认证服务所在服务器的ip,8080
是认证服务对外提供服务的端口。
分析
该接口是Spring Authorization Server
基于Openid Connect 1.0
协议提供的一个OIDC登出接口,接口由OidcLogoutEndpointFilter
拦截处理,在拦截器中先调用OidcLogoutAuthenticationConverter
获取请求入参并转成OidcLogoutAuthenticationToken
返回,之后过滤器再调用AuthenticationManager(ProviderManager)
来做登出处理,根据OidcLogoutAuthenticationToken
最终由OidcLogoutAuthenticationProvider
处理具体的登出逻辑,在该provider中没有针对Session
或者access token
做什么操作,先根据id_token_hint
参数查询oauth2登录生成的认证信息,之后针对认证信息与Session做一些校验,限制了必须是登录时的Session才可以调用登出;之后就是登出成功处理了,上述所说的登出后跳转路径以及销毁当前Session
都是在这个登出成功处理中操作的,如果当前Session存在并且获取到表单登录生成的认证信息则调用SecurityContextLogoutHandler
处理,这个和上边的/logout
登出使用的LogoutHandler
一样,逻辑是一样的,都是销毁当前Session与认证信息,接下来是跳转的操作,如果请求/connect/logout
时携带了post_logout_redirect_uri
参数,则会跳转到该url,如果没有携带该参数,则会通过SimpleUrlLogoutSuccessHandler
跳转到根目录。
自定义
通过上述流程可以发现这个是与/oauth2/token
和/oauth2/authorize
类似的一个接口,或者说Spring Authorization Server
提供的内置端点都是这个流程,支持自定义的地方基本就是Converter
、Provider
、成功响应和失败响应处理,详见文档oidc-logout-endpoint
在端点的过滤器链配置中添加如下配置
http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)// 开启OpenID Connect 1.0协议相关端点.oidc(oidc -> oidc.logoutEndpoint(logoutEndpoint -> logoutEndpoint.logoutResponseHandler((request, response, authorization) -> {})))
具体的实现就不写了,大家知道入口以后根据自己的业务实现登出即可。
注意:如果要使用这个接口,并自定义logoutResponseHandler
逻辑请注销Session
,因为默认的Converter
和Provider
都没有注销当前的Session
!
注意:如果要使用这个接口,并自定义logoutResponseHandler
逻辑请注销Session
,因为默认的Converter
和Provider
都没有注销当前的Session
!
注意:如果要使用这个接口,并自定义logoutResponseHandler
逻辑请注销Session
,因为默认的Converter
和Provider
都没有注销当前的Session
!
如果想在Provider中注销Session也可以,也可以在里边撤销token(撤销token代码请参考上边的RevokeAccessTokenLogoutHandler
),提供了很多配置入口,自由度也是比较高的。
不带post_logout_redirect_uri
参数访问效果,会清除Session并跳转到根目录/
,没有放行直接跳转到登录页面了(代表着认证信息与Session都被清除了)
带post_logout_redirect_uri
参数访问效果,会清除Session并跳转到post_logout_redirect_uri
参数的值(一个url)。
请注意,这个url必须要在客户端信息配置中存在,否则会提示错误!
请注意,这个url必须要在客户端信息配置中存在,否则会提示错误!
请注意,这个url必须要在客户端信息配置中存在,否则会提示错误!
如果集成了十九章的内容,将客户端信息存储在redis,则改代码后重启即可,如果是存储在数据库的请在重启后检查数据库中的数据是否被修改。
Spring Authorization Server
提供的/oauth2/revoke
该接口是基于RFC 7009实现的一个接口。
访问方式
curl --location --globoff --request POST 'http://127.0.0.1:8080/oauth2/revoke?token={access token或者refresh token}' \
--header 'Authorization: Basic bWVzc2FnaW5nLWNsaWVudDoxMjM0NTY='
token参数是想撤销的token(access token\refresh token
)
其中127.0.0.1
是认证服务所在服务器的ip,8080
是认证服务对外提供服务的端口。
访问时记得添加basic认证
请求头,username
和password
分别代表客户端的id和密钥
更多参数及参数的详细说明见RFC 7009 Revocation Request
分析
该接口是Spring Authorization Server
基于OAuth2.1
协议提供的一个token撤销接口,接口由OAuth2TokenRevocationEndpointFilter
拦截处理,在过滤器内的逻辑与上边提到的OidcLogoutEndpointFilter
过滤器的大致流程一致,流程是:通过Converter
转换请求参数,然后由Provider
将token的状态改为无效状态,最后是处理成功的handler;根据源码可知是OAuth2TokenRevocationAuthenticationConverter
来将撤销请求的参数转为OAuth2TokenRevocationAuthenticationToken
,然后ProviderManager
将生成的OAuth2TokenRevocationAuthenticationToken
交由OAuth2TokenRevocationAuthenticationProvider
处理,在该provider
内将token的状态改为无效状态,默认的成功处理只设置了http 200
的状态码,无任何响应。
这个接口在讲上边的登出接口时都有提过,上边两个接口主要目的是清除认证状态
与销毁当前Session
,但是oauth2登录生成access token/refresh token
还可以继续使用,所以需要调用当前接口来将token无效化。
自定义
跟上边的OidcLogoutEndpointFilter
过滤器一样,可以自定义Converter
、Provider
、成功响应和失败响应处理,详见文档oauth2-token-revocation-endpoint
为避免贴大量代码我这边就只自定义一个成功响应处理,在端点的过滤器链配置中添加如下代码
http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)// 开启OpenID Connect 1.0协议相关端点.oidc(Customizer.withDefaults())// 自定义token撤销断点配置入口.tokenRevocationEndpoint(tokenRevocationEndpoint -> tokenRevocationEndpoint// 撤销成功响应.revocationResponseHandler(new TokenRevocationSuccessHandler()));
TokenRevocationSuccessHandler
实现如下,成功后响应json
package com.example.authorization.handler;import com.example.model.Result;
import com.example.util.JsonUtils;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;import java.io.IOException;
import java.nio.charset.StandardCharsets;/*** token撤销成功处理** @author vains*/
@Slf4j
public class TokenRevocationSuccessHandler implements AuthenticationSuccessHandler {@Overridepublic void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {log.info("Token revocation success");// 写回json数据Result<String> result = Result.success();response.setCharacterEncoding(StandardCharsets.UTF_8.name());response.setContentType(MediaType.APPLICATION_JSON_VALUE);response.getWriter().write(JsonUtils.objectCovertToJson(result));response.getWriter().flush();}
}
携带access token访问测试
前后端分离中想用axios请求/logout
和/connect/logout
?
这种方式仅适用于使用Spring Session
将前后端的Session一同管理,前后端共享Session以后才能使用这种方式,并且初始化axios时需要添加withCredentials: true
配置,使其在跨域请求时带上cookie,这样后端才能获取到登录时的Session并进行销毁。(未测试,应该可行)
如果没有使用Spring Session
将前后端的Session一同管理,推荐使用文中的方式,打开一个新标签页并访问登出接口,因为在上边的分析中都讲过是获取当前Session并销毁,如果使用axios访问那获取不到登录时的Session则会跳过销毁Session的步骤。
Jwt token为什么撤销了以后还能继续使用?
因为jwt是无状态的,资源服务器解析时不会从认证服务查询token的状态,所以在解析时不能知道jwt token的状态,如果想在撤销token以后使jwt token失效可以在redis中添加一个黑名单,解析时查看jwt类型的access token是否在黑名单中,以防止撤销后的token继续使用。
最后
到此就说明了两个用户登出和一个token撤销的接口,里边的逻辑有些可能没有讲到,但是处理请求的类,以及具体逻辑的处理,相关的类我基本上都贴出来,大家可以熟悉一下源码,然后看看怎么结合自己业务来实现登出相关的内容。
附录
新仓库地址
spec openid-connect-rpinitiated-1_0 RPLogout
oidc-logout-endpoint
RFC 7009
RFC 7009 Revocation Request
oauth2-token-revocation-endpoint
相关文章:

Spring Authorization Server登出说明与实践
本章内容概览 Spring Security提供的/logout登出接口做了什么与如何自定义。Spring Authorization Server提供的/connect/logout登出接口做了什么与如何自定义。Spring Authorization Server提供的/oauth2/revoke撤销token接口做了什么与如何自定义。 前言 既然系统中有登录功…...

浏览器报错 | 代理服务器可能有问题,或地址不正确
1 问题描述 Windows连网情况下,浏览器访问地址显示“你尚未连接,代理服务器可能有问题,或地址不正确。”出现如下画面: 2 解决方法 途径1 控制面板-->网络与internet-->internet选项-->Internet属性-->连接-->…...

泷羽sec:shell编程(9)不同脚本的互相调用和重定向操作
声明: 学习视频来自B站up主 泷羽sec 有兴趣的师傅可以关注一下,如涉及侵权马上删除文章,笔记只是方便各位师傅的学习和探讨,文章所提到的网站以及内容,只做学习交流,其他均与本人以及泷羽sec团队无关&#…...

Milvus×OPPO:如何构建更懂你的大模型助手
01. 背景 AI业务快速增长下传统关系型数据库无法满足需求。 2024年恰逢OPPO品牌20周年,OPPO也宣布正式进入AI手机的时代。超千万用户开始通过例如通话摘要、新小布助手、小布照相馆等搭载在OPPO手机上的应用体验AI能力。 与传统的应用不同的是,在AI驱动的…...

单片机几大时钟源
在单片机中,MSI、HSI和HSE通常指的是用于内部晶振配置的不同功能模块: MSI (Master Oscillator System Interface):这是最低级的一种时钟源管理单元,它控制着最基本的系统时钟(SYSCLK),一般由外…...

reverse学习总结(12)
一.[FlareOn4]IgniteMe1 https://files.buuoj.cn/files/02b39b8efca02367af23aa279c81cbec/attachment.zip 根据汇编语言分析 查看需要返回为1的函数 int sub_401050() {int v1; // [esp0h] [ebp-Ch]int i; // [esp4h] [ebp-8h]unsigned int j; // [esp4h] [ebp-8h]char v4; …...

基于“微店 Park”模式下 2+1 链动模式商城小程序的创新发展与应用研究
摘要:本文以“微店 Park”从“开店工具”向“众创平台”的转型为背景,深入探讨 21 链动模式商城小程序在该平台情境下的应用潜力与创新发展路径。通过剖析“微店 Park”的运营模式,包括灵活承租、低成本入驻、多元流量引流等特点,…...

C++11:【列表初始化】【右值引用和移动语义】
目录 一.列表初始化 1.1 C98传统的{} 1.2C11中的{} 1.3C中的std::initializer_list 二.右值引用和移动语义 2.1左值和右值 2.2左值引用和右值引用 2.3引用延长生命周期 2.4左值和右值的参数匹配 2.5右值引用和移动语义的使用场景 2.5.1左值引用主要使用场景 2.5.2移…...

Zookeeper的通知机制是什么?
大家好,我是锋哥。今天分享关于【Zookeeper的通知机制是什么?】面试题。希望对大家有帮助; Zookeeper的通知机制是什么? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Zookeeper的通知机制主要通过Watcher实现,它是Zookeeper客…...

嵌入式蓝桥杯学习1 电量LED
cubemx配置 1.新建一个STM32G431RBT6文件 2.在System-Core中点击SYS,找到Debug(设置为Serial Wire) 3.在System-Core中点击RCC,找到High Speed Clock(设置为Crystal/Ceramic Resonator) 4.打开Clock Configuration ࿰…...

bsmap输出结果解释
关于, , -, --的解释 对应着参考基因组的正链(有义链,非模板链,即hg38的序列,watson链); -代表正链的互补链(正常情况下正链的互补链是负链,但在重硫酸盐处理后正链和负链并不互补…...

【java-数据结构篇】揭秘 Java LinkedList:链表数据结构的 Java 实现原理与核心概念
我的个人主页 我的专栏:Java-数据结构,希望能帮助到大家!!!点赞❤ 收藏❤ 目录 1. Java LinkedList 基础 1.1 LinkedList 简介 1.2 LinkedList 的实现原理 1.3 LinkedList 与 ArrayList 的区别 2. 链表基础 2.1 链…...

macOS运行amd64的镜像
在macOS上运行amd64(x86_64)架构的镜像,通常通过虚拟化或仿真工具来实现。例如,如果你使用的是基于Apple Silicon(M1或M2等)芯片的Mac,那么你的处理器是ARM架构的,而amd64是x86架构&…...

轻量的基于图结构的RAG方案LightRAG
LightRAG出自2024年10月的论文《LIGHTRAG: SIMPLE AND FASTRETRIEVAL-AUGMENTED GENERATION》(github),也是使用图结构来索引和搜索相关文本。 LightRAG作者认为已有的RAG系统有如下两个限制,导致难以回答类似"How does the rise of electric vehi…...

计算机的错误计算(一百七十三)
摘要 给定多项式 在 MATLAB 中计算 的值。输出是错误结果。 例1. 已知 计算 直接贴图吧: 这样,MATLAB 输出了错误结果。因为准确值为 0.2401e-16 . 注:可参看计算机的错误计算(六)。...

【力扣】—— 二叉树的前序遍历、字典序最小回文串
Hi~!这里是奋斗的明志,很荣幸您能阅读我的文章,诚请评论指点,欢迎欢迎 ~~ 🌱🌱个人主页:奋斗的明志 🌱🌱所属专栏:数据结构 📚本系列文章为个人学…...

linux替换更高版本gcc
实际使用时对与gcc版本有很多要求, 需要在centos上安装更高版本的gcc 1、安装centos-release-scl sudo yum install centos-release-scl2、安装devtoolset,注意,如果想安装7.版本的,就改成devtoolset-7-gcc,以此类推 sudo yum …...

在Java中使用Apache POI导入导出Excel(六)
本文将继续介绍POI的使用,上接在Java中使用Apache POI导入导出Excel(五) 使用Apache POI组件操作Excel(六) 43、隐藏和取消隐藏行 使用 Excel,可以通过选择该行(或行)来隐藏工作表…...

`uni.setClipboardData` 是 uni-app 提供的一个 API 设置系统剪贴板的内容
uni.setClipboardData是uni-app提供的一个API,用于设置系统剪贴板的内容。 使用说明: 使用此API可以将指定的文本内容复制到系统剪贴板,使用户能够在其他应用或页面中粘贴这些内容。 uni.setClipboardData({data: , // 需要复制的内容 suc…...

【大模型微调】pdf转markdown
目前市面上大部分都是pdf文档,要想转换成能训练的文本,调研了各种工具。 觉得MinerU确实不错。 参考此链接进行操作 MinerU/docs/README_Ubuntu_CUDA_Acceleration_en_US.md at master opendatalab/MinerU GitHub 需要注意的几个点: 1. 使用root账户安装的,配置文件在…...

Vue 3 结合 TypeScript基本使用
Vue 3 结合 TypeScript 使用可以提供更加强大的类型检查和开发体验。以下是一些基本的步骤来开始使用 Vue 3 和 TypeScript: 1. 创建项目 你可以使用 Vue CLI 来快速创建一个支持 TypeScript 的 Vue 项目。首先确保你已经安装了 Node.js 和 npm。然后全局安装或更…...

Trotter steps的复杂性分析
总结 • 我们开发了使用汉密尔顿系数结构执行 Trotter 步骤的递归方法,超越了顺序方法。 • #Gate/Step 在汉密尔顿项数上是次线性的,而 #Step 仍然保持交换子缩放。 • 新结果给出了实空间中第二量化电子结构汉密尔顿的最快量子模拟。对第一量化量子模…...

mean,median,mode,var,std,min,max函数
剩余的函数都放在这篇里面吧 m e a n mean mean函数可以求平均值 a a a为向量时, m e a n ( a ) mean(a) mean(a)求向量中元素的平均值 a a a为矩阵时, m e a n ( a , 1 ) mean(a,1) mean(a,1)求矩阵中各列元素的平均值; m e a n ( a , 2 )…...

JavaScript实现tab栏切换
JavaScript实现tab栏切换 代码功能概述 这段代码实现了一个简单的选项卡(Tab)切换功能。它通过操作 HTML 元素的类名(class)来控制哪些选项卡(Tab)和对应的内容板块显示,哪些隐藏。基本思路是先…...

精确电压输出,家电和工业设备的完美选择,宽输入电压线性稳压器
WD5201线性稳压器的核心内容概述: 主要特点 • 高精度输出电压:2%精度。 • 输出电压可调:支持5V、3.3V、2.7V三档输出。 • 优化控制方式:提升效率。 • 宽输入电压范围:80305VAC。 • 无需功率电感和输入高压电…...

深入理解定时器:优先队列与时间轮实现
文章目录 1. 线程池概述线程池的基本特点: 2. 使用线程池的优先队列定时器实现2.1 优先队列定时器实现2.2 解释: 3. 使用时间轮的线程池定时器实现3.1 时间轮定时器实现 4. 总结 在定时器设计中,使用线程池来执行定时任务可以有效提高程序的性…...

autogen-agentchat 0.4.0.dev8版本的安装
1. 安装命令 pip install autogen-agentchat0.4.0.dev8 autogen-ext[openai]0.4.0.dev82. 版本检查 import autogen_agentchat print(autogen_agentchat.__version__)0.4.0.dev8import autogen_ext print(autogen_ext.__version__)0.4.0.dev83. 第一个案例 使用 autogen-age…...

JAVA |日常开发中读写XML详解
JAVA |日常开发中读写XML详解 前言一、XML 简介二、在 Java 中读取 XML2.1 使用 DOM(Document Object Model)方式读取 XML2.2 使用 SAX(Simple API for XML)方式读取 XML 三、在 Java 中写入 XML3.1 使用 DOM 方式写入…...

React 路由与组件通信:如何实现路由参数、查询参数、state和上下文的使用
🤍 前端开发工程师、技术日更博主、已过CET6 🍨 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 🕠 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 🍚 蓝桥云课签约作者、上架课程《Vue.js 和 E…...

帮我写一篇关于AI搜索网页上编写的文章是否存在版权问题的文章, 字数在 3000 字左右。文心一言提问, 记录后用.
AI搜索网页上编写的文章是否存在版权问题? 在当今科技飞速发展的时代,AI搜索工具如雨后春笋般涌现,为人们获取信息提供了极大的便利。然而,随之而来的问题是,AI搜索案例中常常出现很多内容缺乏依据,这引发…...