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

Spring Boot OAuth 2.0整合—高级配置

一、概述

HttpSecurity.oauth2Login() 为定制OAuth 2.0登录提供了大量的配置选项。主要的配置选项被分组到它们的协议端点对应处。

例如,oauth2Login().authorizationEndpoint() 允许配置授权端点,而 oauth2Login().tokenEndpoint() 允许配置令牌端点。

下面的代码是一个例子。

Advanced OAuth2 Login Configuration

  • Java
@Configuration
@EnableWebSecurity
public class OAuth2LoginSecurityConfig {@Beanpublic SecurityFilterChain filterChain(HttpSecurity http) throws Exception {http.oauth2Login(oauth2 -> oauth2.authorizationEndpoint(authorization -> authorization...).redirectionEndpoint(redirection -> redirection...).tokenEndpoint(token -> token...).userInfoEndpoint(userInfo -> userInfo...));return http.build();}
}

oauth2Login() DSL的主要目标是与规范中定义的命名紧密结合。

OAuth 2.0授权框架对 协议端点 的定义如下。

授权过程使用两个授权服务器端点(HTTP资源)。

  • 授权端点。由客户端使用,通过用户代理重定向从资源所有者那里获得授权。
  • 令牌端点。由客户端使用,以交换授权许可的访问令牌,通常是客户端认证。

授权过程也使用一个客户端点。

  • 重定向端点。由授权服务器使用,通过资源所有者的用户代理将包含授权凭证的响应返回给客户端。

OpenID Connect Core 1.0 规范对 UserInfo端点 的定义如下。

UserInfo端点是一个OAuth 2.0保护资源,用于返回关于已认证最终用户的请求。为了获得关于最终用户的请求,客户端通过使用通过OpenID连接认证获得的访问令牌向UserInfo端点提出请求。这些请求通常由一个JSON对象表示,该对象包含请求的key/value对的集合。

下面的代码显示了 oauth2Login() DSL可用的完整配置选项。

OAuth2 Login Configuration Options

  • Java
@Configuration
@EnableWebSecurity
public class OAuth2LoginSecurityConfig {@Beanpublic SecurityFilterChain filterChain(HttpSecurity http) throws Exception {http.oauth2Login(oauth2 -> oauth2.clientRegistrationRepository(this.clientRegistrationRepository()).authorizedClientRepository(this.authorizedClientRepository()).authorizedClientService(this.authorizedClientService()).loginPage("/login").authorizationEndpoint(authorization -> authorization.baseUri(this.authorizationRequestBaseUri()).authorizationRequestRepository(this.authorizationRequestRepository()).authorizationRequestResolver(this.authorizationRequestResolver())).redirectionEndpoint(redirection -> redirection.baseUri(this.authorizationResponseBaseUri())).tokenEndpoint(token -> token.accessTokenResponseClient(this.accessTokenResponseClient())).userInfoEndpoint(userInfo -> userInfo.userAuthoritiesMapper(this.userAuthoritiesMapper()).userService(this.oauth2UserService()).oidcUserService(this.oidcUserService())));return http.build();}
}

除了 oauth2Login() DSL,还支持XML配置。

下面的代码显示了 security namespace 中可用的完整配置选项。

OAuth2 Login XML Configuration Options

<http><oauth2-login client-registration-repository-ref="clientRegistrationRepository"authorized-client-repository-ref="authorizedClientRepository"authorized-client-service-ref="authorizedClientService"authorization-request-repository-ref="authorizationRequestRepository"authorization-request-resolver-ref="authorizationRequestResolver"access-token-response-client-ref="accessTokenResponseClient"user-authorities-mapper-ref="userAuthoritiesMapper"user-service-ref="oauth2UserService"oidc-user-service-ref="oidcUserService"login-processing-url="/login/oauth2/code/*"login-page="/login"authentication-success-handler-ref="authenticationSuccessHandler"authentication-failure-handler-ref="authenticationFailureHandler"jwt-decoder-factory-ref="jwtDecoderFactory"/>
</http>

下面几节将更详细地介绍每个可用的配置选项。

  • OAuth 2.0 登录页面
  • 重定向端点
  • UserInfo端点
  • ID Token 签名验证
  • OpenID Connect 1.0 注销

二、OAuth 2.0 登录页面

默认情况下,OAuth 2.0登录页面是由 DefaultLoginPageGeneratingFilter 自动生成的。默认的登录页面显示每个配置的OAuth客户端,其 ClientRegistration.clientName 为链接,能够启动授权请求(或OAuth 2.0登录)。

对于 DefaultLoginPageGeneratingFilter 显示配置的OAuth客户端的链接,注册的 ClientRegistrationRepository 需要同时实现 Iterable<ClientRegistration>。请参考 InMemoryClientRegistrationRepository。

每个OAuth客户端的链接的目的地默认为以下内容。

OAuth2AuthorizationRequestRedirectFilter.DEFAULT_AUTHORIZATION_REQUEST_BASE_URI + "/{registrationId}"

下面一行是一个例子。

<a href="/oauth2/authorization/google">Google</a>

要覆盖默认的登录页面,请配置 oauth2Login().loginPage() 和(可选) oauth2Login().authorizationEndpoint().baseUri()。

下面的列表显示了一个例子。

OAuth2 Login Page Configuration

  • Java
@Configuration
@EnableWebSecurity
public class OAuth2LoginSecurityConfig {@Beanpublic SecurityFilterChain filterChain(HttpSecurity http) throws Exception {http.oauth2Login(oauth2 -> oauth2.loginPage("/login/oauth2")....authorizationEndpoint(authorization -> authorization.baseUri("/login/oauth2/authorization")...));return http.build();}
}

你需要提供一个带有 @RequestMapping("/login/oauth2") 的 @Controller,能够渲染自定义的登录页面。

如前所述,配置 oauth2Login().authorizationEndpoint().baseUri() 是可选的。但是,如果你选择自定义,请确保每个OAuth客户端的链接与 authorizationEndpoint().baseUri() 相匹配。

下面一行显示了一个例子。

<a href="/login/oauth2/authorization/google">Google</a>

三、重定向端点

重定向端点由授权服务器使用,用于通过资源所有者用户代理向客户返回授权响应(包含授权凭证)

OAuth 2.0登录利用的是授权码授予。因此,授权凭证就是授权码。

默认的授权响应 baseUri(重定向端点)是 /login/oauth2/code/*,这在 OAuth2LoginAuthenticationFilter.DEFAULT_FILTER_PROCESSES_URI 中定义。

如果你想定制授权响应 baseUri,请按以下方式配置。

Redirection Endpoint Configuration

  • Java
@Configuration
@EnableWebSecurity
public class OAuth2LoginSecurityConfig {@Beanpublic SecurityFilterChain filterChain(HttpSecurity http) throws Exception {http.oauth2Login(oauth2 -> oauth2.redirectionEndpoint(redirection -> redirection.baseUri("/login/oauth2/callback/*")...));return http.build();}
}

你还需要确保 ClientRegistration.redirectUri 与自定义授权响应 baseUri 相匹配。

下面的列表显示了一个例子。

  • Java
return CommonOAuth2Provider.GOOGLE.getBuilder("google").clientId("google-client-id").clientSecret("google-client-secret").redirectUri("{baseUrl}/login/oauth2/callback/{registrationId}").build();

四、UserInfo端点

UserInfo端点包括一些配置选项,在下面的小节中描述。

  • 映射用户权限
  • OAuth 2.0 UserService
  • OpenID Connect 1.0 UserService

1、映射用户权限

在用户成功通过 OAuth 2.0 提供商的认证后,OAuth2User.getAuthorities()(或 OidcUser.getAuthorities())包含一个由 OAuth2UserRequest.getAccessToken().getScopes() 填充的授予权限列表,其前缀为 SCOPE_。这些授权可以被映射到一组新的 GrantedAuthority 实例中,在完成认证时提供给 OAuth2AuthenticationToken。

OAuth2AuthenticationToken.getAuthorities() 用于授权请求,如 hasRole('USER') 或 hasRole('ADMIN') 中。

在映射用户权限时,有几个选项可以选择。

  • 使用 GrantedAuthoritiesMapper
  • 基于Delegation的策略与OAuth2UserService

2、使用 GrantedAuthoritiesMapper

GrantedAuthoritiesMapper 被赋予一个授予权限的列表,其中包含一个类型为 OAuth2UserAuthority 和权限字符串 OAUTH2_USER(或 OidcUserAuthority 和权限字符串 OIDC_USER)的特殊权限。

提供一个 GrantedAuthoritiesMapper 的实现并对其进行配置,如下所示。

Granted Authorities Mapper Configuration

  • Java
@Configuration
@EnableWebSecurity
public class OAuth2LoginSecurityConfig {@Beanpublic SecurityFilterChain filterChain(HttpSecurity http) throws Exception {http.oauth2Login(oauth2 -> oauth2.userInfoEndpoint(userInfo -> userInfo.userAuthoritiesMapper(this.userAuthoritiesMapper())...));return http.build();}private GrantedAuthoritiesMapper userAuthoritiesMapper() {return (authorities) -> {Set<GrantedAuthority> mappedAuthorities = new HashSet<>();authorities.forEach(authority -> {if (OidcUserAuthority.class.isInstance(authority)) {OidcUserAuthority oidcUserAuthority = (OidcUserAuthority)authority;OidcIdToken idToken = oidcUserAuthority.getIdToken();OidcUserInfo userInfo = oidcUserAuthority.getUserInfo();// Map the claims found in idToken and/or userInfo// to one or more GrantedAuthority's and add it to mappedAuthorities} else if (OAuth2UserAuthority.class.isInstance(authority)) {OAuth2UserAuthority oauth2UserAuthority = (OAuth2UserAuthority)authority;Map<String, Object> userAttributes = oauth2UserAuthority.getAttributes();// Map the attributes found in userAttributes// to one or more GrantedAuthority's and add it to mappedAuthorities}});return mappedAuthorities;};}
}

或者,你可以注册一个 GrantedAuthoritiesMapper @Bean,让它自动应用于配置,如下所示。

Granted Authorities Mapper Bean Configuration

  • Java
@Configuration
@EnableWebSecurity
public class OAuth2LoginSecurityConfig {@Beanpublic SecurityFilterChain filterChain(HttpSecurity http) throws Exception {http.oauth2Login(withDefaults());return http.build();}@Beanpublic GrantedAuthoritiesMapper userAuthoritiesMapper() {...}
}

3、基于Delegation的策略与OAuth2UserService

与使用 GrantedAuthoritiesMapper 相比,这种策略是先进的。然而,它也更灵活,因为它让你可以访问 OAuth2UserRequest 和 OAuth2User(当使用OAuth 2.0 UserService)或 OidcUserRequest 和 OidcUser(当使用 OpenID Connect 1.0 UserService)。

OAuth2UserRequest(和 OidcUserRequest)为你提供了对相关 OAuth2AccessToken 的访问,这在 delegator 需要从受保护的资源中获取权限信息,然后再为用户映射自定义权限的情况下非常有用。

下面的例子显示了如何使用OpenID Connect 1.0 UserService实现和配置基于delegation的策略。

OAuth2UserService Configuration

  • Java
@Configuration
@EnableWebSecurity
public class OAuth2LoginSecurityConfig {@Beanpublic SecurityFilterChain filterChain(HttpSecurity http) throws Exception {http.oauth2Login(oauth2 -> oauth2.userInfoEndpoint(userInfo -> userInfo.oidcUserService(this.oidcUserService())...));return http.build();}private OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService() {final OidcUserService delegate = new OidcUserService();return (userRequest) -> {// Delegate to the default implementation for loading a userOidcUser oidcUser = delegate.loadUser(userRequest);OAuth2AccessToken accessToken = userRequest.getAccessToken();Set<GrantedAuthority> mappedAuthorities = new HashSet<>();// TODO// 1) Fetch the authority information from the protected resource using accessToken// 2) Map the authority information to one or more GrantedAuthority's and add it to mappedAuthorities// 3) Create a copy of oidcUser but use the mappedAuthorities insteadoidcUser = new DefaultOidcUser(mappedAuthorities, oidcUser.getIdToken(), oidcUser.getUserInfo());return oidcUser;};}
}

4、OAuth 2.0 UserService

DefaultOAuth2UserService 是一个 OAuth2UserService 的实现,支持标准的OAuth2.0提供者。

OAuth2UserService 从 UserInfo 端点获取最终用户(资源所有者)的用户属性(通过使用授权流程中授予客户端的访问令牌),并以 OAuth2User 的形式返回一个 AuthenticatedPrincipal。

DefaultOAuth2UserService 在UserInfo端点请求用户属性时使用 RestOperations 实例。

如果你需要定制UserInfo请求的预处理,你可以为 DefaultOAuth2UserService.setRequestEntityConverter() 提供一个自定义的 Converter<OAuth2UserRequest, RequestEntity<?>>。默认的实现 OAuth2UserRequestEntityConverter 建立了一个UserInfo请求的 RequestEntity 表示,默认在授权header中设置 OAuth2AccessToken。

在另一端,如果你需要定制 UserInfo 响应的后处理,你需要为 DefaultOAuth2UserService.setRestOperations() 提供一个自定义配置的 RestOperations。默认的 RestOperations 配置如下。

RestTemplate restTemplate = new RestTemplate();
restTemplate.setErrorHandler(new OAuth2ErrorResponseErrorHandler());

OAuth2ErrorResponseErrorHandler 是一个 ResponseErrorHandler,可以处理OAuth2.0错误(400 Bad Request)。它使用一个 OAuth2ErrorHttpMessageConverter 将 OAuth2.0 错误参数转换为 OAuth2Error。

无论你是定制 DefaultOAuth2UserService 还是提供你自己的 OAuth2UserService 的实现,你都需要按以下方式进行配置。

  • Java
@Configuration
@EnableWebSecurity
public class OAuth2LoginSecurityConfig {@Beanpublic SecurityFilterChain filterChain(HttpSecurity http) throws Exception {http.oauth2Login(oauth2 -> oauth2.userInfoEndpoint(userInfo -> userInfo.userService(this.oauth2UserService())...));return http.build();}private OAuth2UserService<OAuth2UserRequest, OAuth2User> oauth2UserService() {...}
}

5、OpenID Connect 1.0 UserService

OidcUserService 是一个 OAuth2UserService 的实现,支持OpenID Connect 1.0提供者。

OidcUserService 在 UserInfo 端点请求用户属性时利用了 DefaultOAuth2UserService。

如果你需要定制UserInfo请求的预处理或UserInfo响应的后处理,你需要向 OidcUserService.setOauth2UserService() 提供一个自定义配置的 DefaultOAuth2UserService。

无论你是定制 OidcUserService 还是为 OpenID Connect 1.0 提供商提供自己的 OAuth2UserService 实现,你都需要按以下方式配置它。

  • Java
@Configuration
@EnableWebSecurity
public class OAuth2LoginSecurityConfig {@Beanpublic SecurityFilterChain filterChain(HttpSecurity http) throws Exception {http.oauth2Login(oauth2 -> oauth2.userInfoEndpoint(userInfo -> userInfo.oidcUserService(this.oidcUserService())...));return http.build();}private OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService() {...}
}

五、ID Token 签名验证

OpenID Connect 1.0认证引入了 ID Token,它是一个安全令牌,包含授权服务器在客户端使用时对终端用户进行认证的要求。

ID令牌被表示为 JSON Web Token(JWT),并且必须使用 JSON Web Signature (JWS)进行签名。

OidcIdTokenDecoderFactory 提供一个用于 OidcIdToken 签名验证的 JwtDecoder。默认算法是 RS256,但在客户端注册时分配的算法可能不同。对于这些情况,你可以配置解析器以返回为特定客户分配的预期 JWS 算法。

JWS算法解析器是一个 Function,它接受 ClientRegistration 并返回客户端预期的 JwsAlgorithm,例如 SignatureAlgorithm.RS256 或 MacAlgorithm.HS256。

下面的代码显示了如何配置 OidcIdTokenDecoderFactory @Bean 为所有 ClientRegistration 实例默认为 MacAlgorithm.HS256。

  • Java
@Bean
public JwtDecoderFactory<ClientRegistration> idTokenDecoderFactory() {OidcIdTokenDecoderFactory idTokenDecoderFactory = new OidcIdTokenDecoderFactory();idTokenDecoderFactory.setJwsAlgorithmResolver(clientRegistration -> MacAlgorithm.HS256);return idTokenDecoderFactory;
}

对于基于MAC的算法(如 HS256、HS384 或 HS512),与 client-id 对应的 client-secret 被用作签名验证的对称密钥。

如果为 OpenID Connect 1.0 认证配置了一个以上的 ClientRegistration,JWS 算法解析器可以评估所提供的 ClientRegistration 来决定返回哪种算法。

六、OpenID Connect 1.0 注销

OpenID Connect会话管理1.0允许通过使用客户端在提供方注销终端用户的能力。其中一个可用的策略是 RP发起的注销。

如果OpenID提供商同时支持会话管理和 Discovery,客户端可以从OpenID提供商的 Discovery Metadata 中获得 end_session_endpoint URL。你可以通过在 ClientRegistration 中配置 issuer-uri 来做到这一点,如下所示。

spring:security:oauth2:client:registration:okta:client-id: okta-client-idclient-secret: okta-client-secret...provider:okta:issuer-uri: https://dev-1234.oktapreview.com

另外,你可以配置 OidcClientInitiatedLogoutSuccessHandler,它实现了RP发起的注销,如下所示。

  • Java
@Configuration
@EnableWebSecurity
public class OAuth2LoginSecurityConfig {@Autowiredprivate ClientRegistrationRepository clientRegistrationRepository;@Beanpublic SecurityFilterChain filterChain(HttpSecurity http) throws Exception {http.authorizeHttpRequests(authorize -> authorize.anyRequest().authenticated()).oauth2Login(withDefaults()).logout(logout -> logout.logoutSuccessHandler(oidcLogoutSuccessHandler()));return http.build();}private LogoutSuccessHandler oidcLogoutSuccessHandler() {OidcClientInitiatedLogoutSuccessHandler oidcLogoutSuccessHandler =new OidcClientInitiatedLogoutSuccessHandler(this.clientRegistrationRepository);// Sets the location that the End-User's User Agent will be redirected to// after the logout has been performed at the ProvideroidcLogoutSuccessHandler.setPostLogoutRedirectUri("{baseUrl}");return oidcLogoutSuccessHandler;}
}

OidcClientInitiatedLogoutSuccessHandler 支持 {baseUrl} 占位符。 如果使用,应用程序的基本URL,如 app.example.org,将在请求时替换它。

相关文章:

Spring Boot OAuth 2.0整合—高级配置

一、概述 HttpSecurity.oauth2Login() 为定制OAuth 2.0登录提供了大量的配置选项。主要的配置选项被分组到它们的协议端点对应处。 例如&#xff0c;oauth2Login().authorizationEndpoint() 允许配置授权端点&#xff0c;而 oauth2Login().tokenEndpoint() 允许配置令牌端点。…...

软考-虚拟专用网原理与应用

本文为作者学习文章&#xff0c;按作者习惯写成&#xff0c;如有错误或需要追加内容请留言&#xff08;不喜勿喷&#xff09; 本文为追加文章&#xff0c;后期慢慢追加 by 2023年10月 虚拟专用网概念 虚拟专用网&#xff08;Virtual Private Network&#xff09;是一种通过…...

clock_property 时钟的常用属性

get_property [get_clocks] property_option 1. period get_property [get_clocks] period 查询所有clock 的周期&#xff0c;如果存在loops会生成CTE_loops.rpt 2.clock_network_pins 查询clock所有的pins 3.generated_clocks_extended 查询clock分频产生的generate…...

平板有必要买触控笔吗?推荐的ipad手写笔

iPad之所以能吸引这么多人&#xff0c;主要是因为它的功能出色。用来画画、做笔记&#xff0c;也是一种不错的体验。但如果只是用来看电视和打游戏的话&#xff0c;那就真的有点大材小用了。如果你不需要昂贵的苹果电容笔&#xff0c;也不需要用来专业的绘图&#xff0c;那你可…...

Qt扫描-QMoive 理论总结

QMoive 理论总结 一、概述二、使用1. 使用2. 信号发出时机 三、控制的相关槽函数四、信号 一、概述 QMovie类是一个使用QImageReader播放 动画 的方便类。这个类用于显示没有声音的简单动画&#xff0c;一般即是 gif 动画。如果要显示视频和媒体内容&#xff0c;请使用Qt Mult…...

类似东郊到家预约家政保洁小程序搭建

随着生活水平的提高&#xff0c;人们对健康养生的需求越来越重视&#xff0c;按摩作为一种传统的养生方式&#xff0c;备受关注。为了方便用户快速、方便地预约按摩服务&#xff0c;本文将介绍一款按摩预约小程序的开发。 首先&#xff0c;我们通过市场调研和分析发现&#xf…...

[补题记录] Atcoder Beginner Contest 325(E、F)

URL&#xff1a;https://atcoder.jp/contests/abc325 目录 E Problem/题意 Thought/思路 Code/代码 F Problem/题意 Thought/思路 Code/代码 E Problem/题意 有一个二维矩阵&#xff0c;D[i][j] 表示从 i 到 j 的距离。从 i 到 j 有两种方式&#xff1a; 坐汽车&…...

1024啊啊啊啊啊啊

1024 程序员节快乐&#xff0c;没什么想发的&#xff0c;只是想要个1024胸章。...

淘宝商品详情API接口(H5端和APP端),淘宝详情页,商品属性接口,商品信息查询

一、接口参数说明&#xff1a;提取淘宝商品详情页各项数据&#xff0c;包含skuid、价格、收藏数、加购数、月销售量、主图、标题、详情页图片等页面上可以看奥的数据都可以拿到。 点击获取key和secret 二、使用场景 1、商品销售情况分析&#xff0c;根据销量调整活动方案&am…...

JVM的几个面试重点

JVM的内存区域划分 JVM类加载机制 前言 Java程序最开始是一个 .java 的文件&#xff0c;JVM把它编译成 .closs 文件&#xff08;字节码文件&#xff09;&#xff0c;运行 Java 程序&#xff0c; JVM 就会读取 .class 文件&#xff0c;把文件内容读取到内存中&#xff0c;构造出…...

[yolo系列:YOLOV7改进-添加CoordConv,SAConv.]

文章目录 概要CoordConvSAConv 概要 CoordConv&#xff08;Coordinate Convolution&#xff09;和SAConv&#xff08;Spatial Attention Convolution&#xff09;是两种用于神经网络中的特殊卷积操作&#xff0c;用于处理图像数据或其他多维数据。以下是它们的简要介绍&#x…...

【万字实操】可视化运维平台openGauss Datakit,带你轻松玩转openGauss 5.0

openGauss Datakit:openGauss社区推出的可视化的运维工具. 特性优势 初级用户学习openGauss门槛高让你望而却步&#xff1f;openGauss Datakit一键化安装企业版集群、监控、日志分析、SQL诊断&#xff0c;让你快速上手&#xff0c;快速部署&#xff0c;从容面对企业环境&#…...

《动手学深度学习 Pytorch版》 10.1 注意力提示

10.1.1 生物学中的注意力提示 “美国心理学之父” 威廉詹姆斯提出的双组件&#xff08;two-component&#xff09;框架&#xff1a; 非自主性提示&#xff1a;基于环境中物体的突出性和易见性 自主性提示&#xff1a;受到了认知和意识的控制 10.1.2 查询、键和值 注意力机制…...

C# 写入文件比较

数据长度&#xff1a;128188个long BinaryWriter每次写一个long 耗时14.7828ms StreamWriter每次写一个long 耗时44.0934 ms FileStream每次写一个long 耗时20.5142 ms FileStream固定chunk写入&#xff0c;循环操作数组&#xff0c;耗时13.4126 ms byte[] chunk new byte[d…...

医院设备利用(Use of Hospital Facilities, ACM/ICPC World Finals 1991, UVa212)rust解法

医院里有n&#xff08;n≤10&#xff09;个手术室和m&#xff08;m≤30&#xff09;个恢复室。每个病人首先会被分配到一个手术室&#xff0c;手术后会被分配到一个恢复室。从任意手术室到任意恢复室的时间均为t1&#xff0c;准备一个手术室和恢复室的时间分别为t2和t3&#xf…...

解决github ping不通的问题(1024程序员节快乐!

1024程序员节快乐&#xff01;&#xff08;随便粘贴一个文档&#xff0c;参加活动 解决github ping不通的问题 域名解析&#xff08;域名->IP&#xff09;&#xff1a;https://www.ipaddress.com/ Ubuntu平台 github经常ping不通或者访问缓慢&#xff0c;方法是更改host…...

QT基础 柱状图

目录 1.QBarSeries 2.QHorizontalBarSeries 3.QPercentBarSeries 4.QHorizontalPercentBarSeries 5.QStackedBarSeries 6.QHorizontalStackedBarSeries 从上图得知柱状的基类是QAbstractBarSeries&#xff0c;派生出来分别是柱状图的水平和垂直类&#xff0c;只是类型…...

微机原理与接口技术-第七章输入输出接口

文章目录 I/O接口概述I/O接口的典型结构基本功能 I/O端口的编址独立编址统一编址 输入输出指令I/O寻址方式I/O数据传输量I/O保护 16位DOS应用程序DOS平台的源程序框架DOS功能调用 无条件传送和查询传送无条件传送三态缓冲器锁存器接口电路 查询传送查询输入端口查询输出端口 中…...

YoloV8改进策略:独家原创,LSKA(大可分离核注意力)改进YoloV8,比Transformer更有效,包括论文翻译和实验结果

文章目录 摘要论文:《LSKA(大可分离核注意力):重新思考CNN大核注意力设计》1、简介2、相关工作3、方法4、实验5、消融研究6、与最先进方法的比较7、ViTs和CNNs的鲁棒性评估基准比较8、结论YoloV8官方结果改进一:测试结果摘要 本文给大家带来一种超大核注意力机制的改进方…...

7天易语言从入门到实战(一)

1.1易语言简介 易语言是一门有着伟大理想的语言。公司用的少&#xff0c;开发者也很少&#xff0c;并不影响国人对他的热情。曾经的多玩LOL&#xff0c;朗读女&#xff0c;都是陪伴再那个国产PC应用匮乏的时代。 2001年1月 吴涛研发了中国自主知识产权的的中文编程语言——易语…...

盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来

一、破局&#xff1a;PCB行业的时代之问 在数字经济蓬勃发展的浪潮中&#xff0c;PCB&#xff08;印制电路板&#xff09;作为 “电子产品之母”&#xff0c;其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透&#xff0c;PCB行业面临着前所未有的挑战与机遇。产品迭代…...

FastAPI 教程:从入门到实践

FastAPI 是一个现代、快速&#xff08;高性能&#xff09;的 Web 框架&#xff0c;用于构建 API&#xff0c;支持 Python 3.6。它基于标准 Python 类型提示&#xff0c;易于学习且功能强大。以下是一个完整的 FastAPI 入门教程&#xff0c;涵盖从环境搭建到创建并运行一个简单的…...

【算法训练营Day07】字符串part1

文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接&#xff1a;344. 反转字符串 双指针法&#xff0c;两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...

Mysql中select查询语句的执行过程

目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析&#xff08;Parser&#xff09; 2.4、执行sql 1. 预处理&#xff08;Preprocessor&#xff09; 2. 查询优化器&#xff08;Optimizer&#xff09; 3. 执行器…...

处理vxe-table 表尾数据是单独一个接口,表格tableData数据更新后,需要点击两下,表尾才是正确的

修改bug思路&#xff1a; 分别把 tabledata 和 表尾相关数据 console.log() 发现 更新数据先后顺序不对 settimeout延迟查询表格接口 ——测试可行 升级↑&#xff1a;async await 等接口返回后再开始下一个接口查询 ________________________________________________________…...

给网站添加live2d看板娘

给网站添加live2d看板娘 参考文献&#xff1a; stevenjoezhang/live2d-widget: 把萌萌哒的看板娘抱回家 (ノ≧∇≦)ノ | Live2D widget for web platformEikanya/Live2d-model: Live2d model collectionzenghongtu/live2d-model-assets 前言 网站环境如下&#xff0c;文章也主…...

安卓基础(Java 和 Gradle 版本)

1. 设置项目的 JDK 版本 方法1&#xff1a;通过 Project Structure File → Project Structure... (或按 CtrlAltShiftS) 左侧选择 SDK Location 在 Gradle Settings 部分&#xff0c;设置 Gradle JDK 方法2&#xff1a;通过 Settings File → Settings... (或 CtrlAltS)…...

前端中slice和splic的区别

1. slice slice 用于从数组中提取一部分元素&#xff0c;返回一个新的数组。 特点&#xff1a; 不修改原数组&#xff1a;slice 不会改变原数组&#xff0c;而是返回一个新的数组。提取数组的部分&#xff1a;slice 会根据指定的开始索引和结束索引提取数组的一部分。不包含…...

【C++】纯虚函数类外可以写实现吗?

1. 答案 先说答案&#xff0c;可以。 2.代码测试 .h头文件 #include <iostream> #include <string>// 抽象基类 class AbstractBase { public:AbstractBase() default;virtual ~AbstractBase() default; // 默认析构函数public:virtual int PureVirtualFunct…...

保姆级【快数学会Android端“动画“】+ 实现补间动画和逐帧动画!!!

目录 补间动画 1.创建资源文件夹 2.设置文件夹类型 3.创建.xml文件 4.样式设计 5.动画设置 6.动画的实现 内容拓展 7.在原基础上继续添加.xml文件 8.xml代码编写 (1)rotate_anim (2)scale_anim (3)translate_anim 9.MainActivity.java代码汇总 10.效果展示 逐帧…...