Spring Authorization Server 0.2.3变化

article/2025/10/12 9:00:35

目录

    • 引言
    • 联邦认证示例
    • public client默认设置
    • Introspection端点自定义
    • 访问令牌类型⭐️
    • 令牌生成器优化⭐️
    • 拆分Client认证逻辑OAuth2ClientAuthenticationProvider⭐️
    • 授权端点逻辑⭐️
    • 关于0.3.0版本中JwtEncoder相关变化⭐️

引言

Spring社区在2022-03-24 19:56发布了Spring Authorization Server 0.2.3版本,具体变化如下图:
在这里插入图片描述
接下来结合上图,聊聊新版本的变化。

注:
以下标题中标⭐️的是我这边需要关注的,后续扩展Spring Authorization Server均有涉及。

联邦认证示例

即通过Spring Security OAuth2 Client(Login)模块支持第三方登录,
社区给了一个示例:
https://github.com/spring-projects/spring-authorization-server/tree/main/samples/federated-identity-authorizationserver
示例中集成了Github和Google登录,
在这里插入图片描述
有兴趣的可以查看具体示例代码。

之前在做《Spring Authorization Server(2022-01-27 0.2.2版本)及自定义OIDC扩展实现》时,也实现了类似功能,具体效果如下图:

重点是下面那个 其他方式登录
后续有精力也可以参考社区示例修改成类似Configurer形式:
FederatedIdentityConfigurer extends AbstractHttpConfigurer<FederatedIdentityConfigurer, HttpSecurity>

在这里插入图片描述

public client默认设置

即在注册Client信息时,若对应Public Client(即客户端认证方法仅支持none),
则自定开启PKCE和Consent确认。
具体修改可参见:
https://github.com/spring-projects/spring-authorization-server/commit/586c7daf2a69f72471a98240de1ec044ce256e59

在这里插入图片描述

Introspection端点自定义

新增加OAuth2TokenIntrospectionEndpointConfigurer配置类,可通过如下方式对introspection_endpoint(即OAuth2TokenIntrospectionEndpointFilter)进行自定义:
在这里插入图片描述
如想对令牌验证返回结果进行自定义,可参考OAuth2TokenIntrospectionAuthenticationProvider类进行扩展实现,
返回想要的TokenClaims即可,原相关实现逻辑如下图:
在这里插入图片描述

访问令牌类型⭐️

在这里插入图片描述

可参见OAuth2TokenFormat类,即访问令牌access_token支持如下两种类型(原来不可配置且只支持JWT):

  • SELF_CONTAINED(默认) - 自签JWT类型(包含claim信息如sub、scopes等内容)
  • REFERENCE - 引用类型(Support opaque access tokens),即生成96位随机字符串,具体claim信息存储在DB中

可通过RegisteredClient.TokenSettings.accessTokenFormat方法进行设置。

令牌生成器优化⭐️

原令牌生成逻辑直接耦合在Token端点的AuthenticationProvider中,现将令牌生成逻辑进行拆分,拆分为OAuth2TokenGenerator及其具体实现如下图:
在这里插入图片描述

  • OAuth2TokenGenerator
    • DelegatingOauth2TokenGenerator - 代理类,聚合多个生成器,依次遍历多个生成器,生成结果非空则直接返回结果
    • JwtGenerator - 生成JWT格式的access_token(适用于self_contained类型)和id_token
      • 可通过OAuth2TokenCustomizer<JwtEncodingContext>进行扩展
      • access_token过期时间可通过RegisteredClient.TokenSettings.accessTokenTimeToLive方法进行设置,默认5分钟
      • id_token过期时间30分钟,目前不可配置(写死在代码中)
      • 此类即对应原0.2.2中OAuth2AuthorizationCodeAuthenticationProvider的access_token、id_token生成逻辑
    • OAuth2AccessTokenGenerator - 生成96位随机字符串access_token(适用于reference类型),且相应claims和过期时间等存在在DB中
      • 可通过OAuth2TokenCustomizer<JwtEncodingContext>进行扩展
    • OAuth2RefreshTokenGenerator - 生成96位随机字符串refresh_token,过期时间存放在DB中
      • refresh_token过期时间可通过RegisteredClient.TokenSettings.refreshTokenTimeToLive方法进行设置,默认60分钟
      • 此类即对应原0.2.2中OAuth2AuthorizationCodeAuthenticationProvider的refresh_token生成逻辑
    • OAuth2AuthorizationCodeGenerator - 生成96位随机字符串授权码
      • 过期时间5分钟,目前不可配置(写死在代码中)
      • 此类为private static私有类,即对应原0.2.2中OAuth2AuthorizationCodeRequestAuthenticationProvider的code生成逻辑

关于OAuth2TokenEndpointFilter整体调用逻辑:

AuthenticationConverter -> OAuth2AuthorizationGrantAuthenticationToken -> AuthenticaionProvider -> DelegatingOAuth2TokenGenerator

AuthenticationConverter
根据grant_type解析参数并转换为OAuth2AuthorizationGrantAuthenticationToken
OAuth2AuthorizationGrantAuthenticationTokenAuthenticaionProvider
基本参数验证后使用OAuth2TokenGenerator生成对应的Token
DelegatingOAuth2TokenGenerator
AuthenticationProvider均会聚合对应的DelegatingOAuth2TokenGenerator
OAuth2AuthorizationCodeAuthenticationConverterOAuth2AuthorizationCodeAuthenticationTokenOAuth2AuthorizationCodeAuthenticationProviderDelegatingOAuth2TokenGenerator(JwtGenerator, OAuth2AccessTokenGenerator, OAuth2RefreshTokenGenerator)
OAuth2RefreshTokenAuthenticationConverterOAuth2RefreshTokenAuthenticationTokenOAuth2RefreshTokenAuthenticationProviderDelegatingOAuth2TokenGenerator(JwtGenerator, OAuth2AccessTokenGenerator, OAuth2RefreshTokenGenerator)
OAuth2ClientCredentialsAuthenticationConverterOAuth2ClientCredentialsAuthenticationTokenOAuth2ClientCredentialsAuthenticationProviderDelegatingOAuth2TokenGenerator(JwtGenerator, OAuth2AccessTokenGenerator)

拆分Client认证逻辑OAuth2ClientAuthenticationProvider⭐️

OAuth2ClientAuthenticationProvider及以下拆分后的AuthenticationProver均被OAuth2ClientAuthenticationFilter调用,
即RP向OP发送获取token请求、检查token、吊销token时(POST /oauth2/token|introspect|revoke),OP端提供的认证逻辑。

0.2.2版本中OAuth2ClientAuthenticationProvider耦合了一堆Client认证逻辑,新版本0.2.3中拆分为:

  • ClientSecretAuthenticationProvider - 支持client_secret_basic、client_secret_post认证
    • 比较client_secret是否匹配
    • 支持OAuth2.1中confidential client - pkce验证码code_verifier验证(对应之前授权端点提交的挑战码code_challenge)
  • PublicClientAuthenticationProvider - 支持none认证(PKCE流程)
    • 支持pkce验证码code_verifier验证(对应之前授权端点提交的挑战码code_challenge)
  • JwtClientAssertionAuthenticationProvider - 支持urn:ietf:params:oauth:client-assertion-type:jwt-bearer认证
    • Http Form参数:client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer&client_assertion=jwtXxx
    • authentication_method包含private_key_jwt、client_secret_jwt

原来想要扩展Client认证逻辑,如支持Public client(无法提供client_secret的场景)执行刷新令牌流程,需要覆盖修改整个OAuth2ClientAuthenticationProvider代码,现在0.2.3版本后仅需附加一个新的AuthenticationProver,该AuthenticationProver仅去实现Public client执行刷新令牌流程的认证场景即可,如:

grant_type == "refresh_token" && client_id != null && token_settings.allow_public_client_refresh_token 

关于OAuth2ClientAuthenticationFilter整体调用逻辑:

AuthenticationConverter -> OAuth2ClientAuthenticationToken -> AuthenticaionProvider

AuthenticationConverter
解析参数并转换为OAuth2ClientAuthenticationToken
AuthenticaionProvider
根据认证方法做具体客户端认证
JwtClientAssertionAuthenticationConverterJwtClientAssertionAuthenticationProvider
ClientSecretBasicAuthenticationConverterClientSecretAuthenticationProvider
ClientSecretPostAuthenticationConverterClientSecretAuthenticationProvider
PublicClientAuthenticationConverterPublicClientAuthenticationProvider

授权端点逻辑⭐️

这块不是新扩展的,就是逻辑比较复杂,所以就简单记录下。

考虑个问题,一次授权码流程中总共会经过OAuth2AuthorizationEndpointFilter授权端点/oauth2/authorize几次?
1)客户端首次跳转或重定向到授权端点GET /oauth2/authorize(由于未登录认证,则直接重定向到登录页面)
2)登录成功后通过SaveRequest获取前一个URI,即对应此授权端点,即登录成功后再次重定向到此GET /oauth2/authorize
3.1)若需要consentRequired,则重定向到consentUri确认页后,提交确认时会再请求到此POST /oauth2/authorize(授权范围scope确认无误后会再重定向回客户端redirect_uri)
3.2)若不需要consentRequired,由于用户已认证通过则直接重定向回客户端redirect_uri
4)之后再有Client请求此授权端点GET /oauth2/authorize,由于之前已经登录过,则直接重定向回对应客户端的redirect_uri

  • OAuth2AuthorizationEndpointFilter - 授权端点的具体实现逻辑
    • RequestMatcher
      • GET /oauth2/authorize - 授权端点
      • POST /oauth2/authorize?response_type=xxx&scope=openid… - 授权端点
      • POST/oauth2/authorize且不存在response_type参数 - Consent权限确认表单提交请求
    • OAuth2AuthorizationCodeRequestAuthenticationConverter - 提取认证参数OAuth2AuthorizationCodeRequestAuthenticationToken(通过consent区分类型,区别于consentRequired属性)
      http请求参数授权端点Consent提交请求
      client_idyesyes
      scopeyesyes
      stateyesyes
      response_typeyes
      response_type=code
      no
      redirect_uriyesno
      code_challengeyesno
      code_challenge_methodyes
      s256 | plain
      no
      additional parametersyesyes
    • OAuth2AuthorizationCodeRequestAuthenticationProvider - 具体的认证逻辑实现
      • authenticateAuthorizationConsent
        • 基础验证(state存在、用户认证通过、client_id合法)
        • 授权范围合法…
        • 保存OAuth2AuthorizationConsent
        • 生成授权码code
        • 更新OAuth2Authorization
        • 返回OAuth2AuthorizationCodeRequestAuthenticationToken(clientId, principal, authorization_uri, redirect_uri, authorizedScopes, request.state, authorizationCode)
      • authenticateAuthorizationRequest
        • 基础验证
          • 验证client_id是否合法、redirect_uri是否匹配、是否包含authorization_code授权类型
          • 验证当前请求的scope是否在RegisteredClient中包含(即请求的scope是否在注册Client时指定的范围内)
          • 验证PKCE code_challenge及code_challenge_method是否合法
        • 若之前已认证通过(SecurityContextHolder.getContext().getAuthentication())且非匿名认证AnonymousAuthenticationToken,也即通过Spring Security认证过(如formLogin),则直接返回OAuth2AuthorizationCodeRequestAuthenticationToken
        • 否则记录授权请求
        • 是否需要consent
          • clientSetting.REQUIRE_AUTHORIZATION_CONSENT
          • scope不是仅包含openid
          • 之前DB中OAuth2AuthorizationConsent存储的已确认的scope不完全包含当前请求的scope
        • 若需要consent,则直接返回OAuth2AuthorizationCodeRequestAuthenticationToken(authorizationUri, 新生成的state,scopes, consentRequired=true)
        • 若不需要consent
          • 生成授权码code(96位随机字符串,5分钟有效期,目前不可配置)
          • 生成并保存OAuth2Authorization(authorizationCode, scopes)记录
          • 返回OAuth2AuthorizationCodeRequestAuthenticationToken(authorizationUri, redirectUri, request.state,scopes, authorizationCode, consentRequired=false)
    • 若认证未通过(未颁发授权码 并且 !consentRequired),则继续Filter链触发登录
    • 需要consentRequired,则重定向达授权确认页(默认生成 或者 自定义consentUri)
      • consentUri?client_id=xx&state=xxx&scope=requestedScopes
    • 不需要consentRequired(已登录过、颁发授权码、无需consent或者已经consent),则重定向回客户端redirect_uri?code=xxx&state=request.state
    • 抛异常则重定向回客户端redirect_uri?state=request.state&error=error_code&error_description=xxx&error_uri=xxx

关于redirect_uri的验证可见下图:
在这里插入图片描述

关于0.3.0版本中JwtEncoder相关变化⭐️

在这里插入图片描述
以上截图来自:https://github.com/spring-projects/spring-authorization-server/issues/594

在集成0.2.x版本时,会发现JwtEncodingContext关联的底层实现JwtClaimsSet等均已被@Deprecated标识,
而在扩展Token相关Claims(实现自定义OAuth2TokenCustomizer<JwtEncodingContext>)时会用到相关类,
考虑到后续0.3.0版本JwtEncoding相关实现会有变化,此处扩展最好隔离底层实现,可以参见以下我的实现:

注:集成的工程如需扩展Token Claims,仅需实现AbstractOidcTokenClaimsCustomerExtend即可。

import com.neusoft.oscoe.oauth.authserver.constant.Oauth2Constants;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.core.OAuth2TokenType;
import org.springframework.security.oauth2.core.oidc.endpoint.OidcParameterNames;
import org.springframework.security.oauth2.server.authorization.JwtEncodingContext;
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
import org.springframework.security.oauth2.server.authorization.OAuth2TokenCustomizer;
import org.springframework.util.StringUtils;import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;/*** 默认的OIDC Token定制化实现** @author luohq* @date 2022-04-21 14:59*/
public class DefaultOidcTokenCustomer implements OAuth2TokenCustomizer<JwtEncodingContext> {/*** 自定义Token扩展(默认空实现)*/private AbstractOidcTokenCustomerExtend abstractOidcTokenCustomerExtend = new AbstractOidcTokenCustomerExtend() {};/*** Map(token类型值, 自定义扩展实现)*/private Map<String, Consumer<JwtEncodingContext>> tokenTypeValue2ExtendFuncMap = new HashMap<>(3);/*** 构造函数** @param abstractOidcTokenCustomerExtend 自定义Token扩展*/public DefaultOidcTokenCustomer(AbstractOidcTokenCustomerExtend abstractOidcTokenCustomerExtend) {//设置非空自定义token扩展if (null != abstractOidcTokenCustomerExtend) {this.abstractOidcTokenCustomerExtend = abstractOidcTokenCustomerExtend;}//设置Map(token类型值, 自定义扩展实现)this.tokenTypeValue2ExtendFuncMap.put(OAuth2TokenType.ACCESS_TOKEN.getValue(), this::extendAccessTokenInner);this.tokenTypeValue2ExtendFuncMap.put(OAuth2TokenType.REFRESH_TOKEN.getValue(), this.abstractOidcTokenCustomerExtend::extendRefreshToken);this.tokenTypeValue2ExtendFuncMap.put(OidcParameterNames.ID_TOKEN, this::extendIdTokenInner);}/*** 内部token扩展实现** @param jwtEncodingContext token上下文*/@Overridepublic void customize(JwtEncodingContext jwtEncodingContext) {//token类型OAuth2TokenType tokenType = jwtEncodingContext.getTokenType();//根据token类型扩展对应的token(依次扩展accessToken -> refreshToken -> idToken)//详细扩展逻辑参见 org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationCodeAuthenticationProvider -> authenticate)this.tokenTypeValue2ExtendFuncMap.get(tokenType.getValue()).accept(jwtEncodingContext);}private void extendAccessTokenInner(JwtEncodingContext jwtEncodingContext) {/** 第三方登录,调用第三方用户自动注册逻辑(非OAuth2 Client第三方登录的情况均为UniLoginAuthenticationToken)  */if (jwtEncodingContext.getPrincipal().getClass().getName().equals("org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken")) {String newRegUserId = this.abstractOidcTokenCustomerExtend.registerThirdUser(jwtEncodingContext);//重置newRegUserIdthis.resetNewRegUserIdInJwtContext(newRegUserId, jwtEncodingContext);}//调用自定义扩展this.abstractOidcTokenCustomerExtend.extendAccessToken(jwtEncodingContext);}/*** 重置claims.sub和Auth2Authorization.principalName为newRegUserId** @param newRegUserId 新注册的用户ID* @param jwtEncodingContext jwt编码上下文*/private void resetNewRegUserIdInJwtContext(String newRegUserId, JwtEncodingContext jwtEncodingContext) {try {//覆盖claims.sub为新注册用户IDjwtEncodingContext.getClaims().claim("sub", newRegUserId);//重置OAuth2Authorization.pincipalNameOAuth2Authorization oAuth2Authorization = jwtEncodingContext.getAuthorization();Field principalNameField = OAuth2Authorization.class.getDeclaredField("principalName");principalNameField.setAccessible(true);principalNameField.set(oAuth2Authorization, newRegUserId);} catch (Exception ex) {ex.printStackTrace();throw new AuthenticationServiceException(ex.getMessage());}}/*** 内部idToken扩展(扩展sid)** @param jwtEncodingContext token上下文*/private void extendIdTokenInner(JwtEncodingContext jwtEncodingContext) {//获取登录时的sessionId(避免再次调用RequestContextHolder.getRequestAttributes().getSessionId()获取sessionId而导致额外创建新的session)String loginSessionId = jwtEncodingContext.getAuthorization().getAttribute(Oauth2Constants.AUTHORIZATION_ATTRS.SESSION_ID);//idToken默认添加sidif (StringUtils.hasText(loginSessionId)) {jwtEncodingContext.getClaims().claim(Oauth2Constants.CLAIMS.SID, loginSessionId);}//调用自定义扩展this.abstractOidcTokenCustomerExtend.extendIdToken(jwtEncodingContext);}/*** 自定义扩展适配器<br/>** 注:* 该类实现暂不稳定,后续升级SAS 0.3.0后JwtEncodingContext包名及其底层实现会调整,* 如有扩展需要,目前0.2.x版本可基于AbstractOidcTokenClaimsCustomerExtend进行扩展(兼容后续0.3版本)**/public static abstract class AbstractOidcTokenCustomerExtend {/*** 注册第三方用户为当前系统用户,并返回注册后的当前系统用户ID<br/>* 注:用注册后的用户ID作为token.claim.sub* @param jwtEncodingContext* @return 注册后的用户ID(对应于当前授权服务端的用户)*/public String registerThirdUser(JwtEncodingContext jwtEncodingContext) {return jwtEncodingContext.getPrincipal().getName();}/*** 扩展IdToken** @param jwtEncodingContext token上下文*/public void extendAccessToken(JwtEncodingContext jwtEncodingContext) {}/*** 扩展RefreshToken** @param jwtEncodingContext token上下文*/public void extendRefreshToken(JwtEncodingContext jwtEncodingContext) {}/*** 扩展AccessToken** @param jwtEncodingContext token上下文*/public void extendIdToken(JwtEncodingContext jwtEncodingContext) {}}/*** 自定义Claims扩展适配器<br/>** 注:* 该类屏蔽了SAS 0.2和后续0.3版本会发生变化的部分,较为稳定,* 后续升级SAS为0.3版本后,仅需调整此框架实现,通过此类集成的工程可不受影响*/public static abstract class AbstractOidcTokenClaimsCustomerExtend extends AbstractOidcTokenCustomerExtend {@Deprecated@Overridepublic String registerThirdUser(JwtEncodingContext jwtEncodingContext) {Authentication thirdAuthInfo = jwtEncodingContext.getPrincipal();return this.registerThirdUser(thirdAuthInfo);}@Deprecated@Overridepublic void extendAccessToken(JwtEncodingContext jwtEncodingContext) {Set<String> authorizedScopes = jwtEncodingContext.getAuthorizedScopes();jwtEncodingContext.getClaims().claims(claims -> this.extendAccessTokenClaims(claims, authorizedScopes));}@Deprecated@Overridepublic void extendRefreshToken(JwtEncodingContext jwtEncodingContext) {super.extendRefreshToken(jwtEncodingContext);}@Deprecated@Overridepublic void extendIdToken(JwtEncodingContext jwtEncodingContext) {Set<String> authorizedScopes = jwtEncodingContext.getAuthorizedScopes();jwtEncodingContext.getClaims().claims(claims -> this.extendIdTokenClaims(claims, authorizedScopes));}/*** 注册第三方用户为当前系统用户,并返回注册后的当前系统用户ID<br/>* 注:用注册后的用户ID作为token.claim.sub** @param thirdAuthInfo 第三方用户认证信息(如借助Spring Security OAuth2 Client(集成三方登录oauth2Login)则对应OAuth2AuthenticationToken类型* @return 注册后的用户ID(对应于当前授权服务端的用户)*/public String registerThirdUser(Authentication thirdAuthInfo) {return thirdAuthInfo.getName();}/*** 扩展AccessToken** @param claims           AccessToken属性Map* @param authorizedScopes 当前客户端授权范围*/public void extendAccessTokenClaims(Map<String, Object> claims, Set<String> authorizedScopes) {}/*** 扩展IdToken** @param claims           IdToken属性Map* @param authorizedScopes 当前客户端授权范围*/public void extendIdTokenClaims(Map<String, Object> claims, Set<String> authorizedScopes) {}}}

http://chatgpt.dhexx.cn/article/KoeOt3il.shtml

相关文章

spring authorization server 0.3.1 - 默认示例

spring authorization server 0.3.1 - 默认oidc 开始1、default-authorizationserver项目1.1、AuthorizationServerConfig.java1.2、DefaultSecurityConfig.java1.3、Jwks.java1.4、KeyGeneratorUtils.java1.5、DefaultAuthorizationServer.java1.6、application.yml 2、client…

Authorization Server 认证服务

Hi Auth HiAuth是一个开源的基于Oauth2协议的认证、授权系统&#xff0c;除了标准的Oauth2授权流程功能外&#xff0c;还提供了应用管理、用户管理、权限管理等相关功能。 在这个项目中你能够了解到如何基于spring-security-oauth2-authorization-server实现自己的Authorizat…

java authorization_OkHttp3 之 Authorization处理认证(四)

处理验证 这部分和HTTP AUTH有关. HTTP AUTH 使用HTTP AUTH需要在server端配置http auth信息, 其过程如下:客户端发送http请求 服务器发现配置了http auth, 于是检查request里面有没有”Authorization”的http header 如果有, 则判断Authorization里面的内容是否在用户列表里面…

shiro授权过程

一、授权的核心概念 授权&#xff0c;也就是权限认证或访问控制&#xff0c;即在应用中控制谁能访问哪些资源 授权中的核心要素&#xff1a; 1 用户&#xff0c;在shiro中代表访问系统的任何客户端&#xff0c;即subject 2 角色&#xff0c;是权限的集合&#xff0c;或字符串值…

安全-认证授权、数据脱敏

一、认证授权 JWT &#xff1a;JWT&#xff08;JSON Web Token&#xff09;是一种身份认证的方式&#xff0c;JWT 本质上就一段签名的 JSON 格式的数据。由于它是带有签名的&#xff0c;因此接收者便可以验证它的真实性。 SSO(单点登录) &#xff1a;SSO(Single Sign On) 即单…

认证 (authentication) 和授权 (authorization) 的区别

以前一直傻傻分不清各种网际应用中 authentication 和 authorization, 其实很简单: 这两个术语通常在安全性方面相互结合使用&#xff0c;尤其是在获得对系统的访问权限时。两者都是非常重要的主题&#xff0c;通常与网络相关联&#xff0c;作为其服务基础架构的关键部分。然而…

Authorization—权限控制流程

本篇是对Shiro体系架构的介绍&#xff0c;本栏目大部分内容来自于Shiro官网。翻译过程中已经尽量保证用词的准确性和易懂性&#xff0c;如有不准确或者不确切的地方&#xff0c;请联系作者加以修改。本篇内容翻译自Authorization特征与Authorization官方指南。 Authorization&…

认证 (Authentication) 和授权 (Authorization)的区别是什么?

说简单点就是&#xff1a; 认证 (Authentication)&#xff1a; 你是谁。 授权 (Authorization)&#xff1a; 你有哪些权限 干什么事情。 稍微正式点&#xff08;啰嗦点&#xff09;的说法就是&#xff1a; Authentication&#xff08;认证&#xff09; 是验证您的身份的凭据&a…

变量定义与类型

命名 保留字与关键字 关键字是系统已经用的&#xff0c;保留字是系统自带的的保留 为以后使用做准备 查看关键字方法 import keyword #引入关键字模块 print &#xff08;keyword.kwlist&#xff09; #打印系统全部关键字 变量声明 三种格 #格式1 s1 &#xff02;北京图灵学…

Java变量定义时候的注意事项

常量定义的基本注意事项 在JAVA语言中&#xff0c;主要利用final关键字&#xff0c;&#xff08;在java类中灵活使用Static关键字&#xff09;来定义常量。 当常量被设定后&#xff0c;一般情况下就不允许在进行修改&#xff0c;如可以利用以下形式来定义一个常量:final doubl…

变量的定义和使用

目录 一、变量的定义 二、变量的组成 1.标识 2.类型 3.值 三、变量的多次赋值 一、变量的定义 变量名(name) 赋值运算符() 值(小王) name 小王 二、变量的组成 1.标识 表示对象所存储的物理地址&#xff0c;使用内置函数 id(obj) 来获取。 print(id(name)) 运行…

C语言中变量声明和变量定义的区别

本文转载至CSDN博客JeanCheng 变量声明和变量定义 变量定义&#xff1a;用于为变量分配存储空间&#xff0c;还可为变量指定初始值。程序中&#xff0c;变量有且仅有一个定义。变量声明&#xff1a;用于向程序表明变量的类型和名字。定义也是声明&#xff0c;extern声明不是定义…

C++ 中的变量定义

变量定义就是告诉编译器在何处创建变量的存储&#xff0c;以及如何创建变量的存储。 变量定义指定一个数据类型&#xff0c;并包含了该类型的一个或多个变量的列表&#xff0c;如下所示&#xff1a; type variable_list; 在这里&#xff0c;type 必须是一个有效的 C 数据类型…

十:变量的定义和声明的区别?

1. 变量的声明&#xff1a; 声明是用来告诉编译器变量的名称和类型&#xff0c;而不分配内存。变量的声明有两重含义&#xff1a; 告诉编译器&#xff0c;这个名字已经匹配到一块内存上&#xff0c;下面的代码用到变量或者对象是在别的地方定义的。声明可以出现多次。 告诉编译…

C语言基础教程 之 如何定义变量!

变量定义就是告诉编译器在何处创建变量的存储&#xff0c;以及如何创建变量的存储。变量定义指定一个数据类型&#xff0c;并包含了该类型的一个或多个变量的列表&#xff0c;如下所示&#xff1a; type variable_list; 在这里&#xff0c;type 必须是一个有效的 C 数据类型&…

变量的定义

变量 变量用于存储编程所使用的数据和方法。 声明一般变量的关键字&#xff1a;var,let,const.其中let和const是es6的语法。 声明其他特殊变量的关键字&#xff1a;function,class,improt&#xff08;先了解&#xff09;等 声明变量 变量用于存储数据,因此可以把变量实际上就…

03-变量的定义

一、变量的定义 1.变量是什么&#xff1f; 一句话概括&#xff1a;变量是用来临时保存数据的&#xff0c;该数据是可以变化的数据。 2.什么时候需要定义变量&#xff1f; 如果某个内容需要多次使用&#xff0c;并且在代码中重复出现&#xff0c;那么可以用变量代表该内容。…

【论文阅读】ICRA2021: VDB-EDT An Efficient Euclidean Distance Transform Algorithm Based on VDB Data Struct

参考与前言 Summary: 浩哥推荐的一篇 无人机下的建图 and planning实验 Type: ICRA Year: 2021 论文链接&#xff1a;https://arxiv.org/abs/2105.04419 youtube presentation video&#xff1a;https://youtu.be/Bojh6ylYUOo 代码链接&#xff1a;https://github.com/zhud…