Oauth2协议

article/2025/9/18 13:45:44

Oauth2协议

  • Oauth2简介
  • 角色
  • 常用术语
  • 令牌类型
    • 特点
  • 授权模式
    • 授权码模式(Authorization Code)
    • 简化授权模式(Implicit)
    • 密码模式(Resource Owner PasswordCredentials)
    • 客户端模式(Client Credentials)
    • 刷新令牌----令牌过期
  • Spring Security Oauth2
    • 授权服务器
    • Spring Security Oauth2架构
    • Spring Security Oauth2授权码模式
      • 创建项目
      • 添加依赖
    • 编写配置类
    • 编写实体类
    • 编写Service
    • 编写Controller
    • 测试
  • Spring Security Oauth2 密码模式
    • 在Redis中存储token
      • 添加依赖及配置
      • 编写Redis配置类
    • 在认证服务器配置中指定令牌的存储策略为Redis


Oauth2简介

第三方认证技术方案最主要是解决认证协议的通用标准问题,因为要实现跨系统认证,各系统之间要遵循一定的接口协议。

OAUTH协议为用户资源的授权提供了一个安全的、开放而又简易的标准。同时,任何第三方都可以使用OAUTH认证服务,任何服务提供商都可以实现自身的OAUTH认证服务,因而OAUTH是开放的。业界提供了OAUTH的多种实现如PHP、JavaScript,Java,Ruby等各种语言开发包,大大节约了程序员的时间,因而OAUTH是简易的。互联网很多服务如Open API,很多大公司如Google,Yahoo,Microsoft等都提供了OAUTH认证服务,这些都足以说明OAUTH标准逐渐成为开放资源授权的标准。

Oauth协议目前发展到2.0版本,1.0版本过于复杂,2.0版本已得到广泛应用。

参考:https://baike.baidu.com/item/oAuth/7153134?fr=aladdin

Oauth 协议:https://tools.ietf.org/html/rfc6749

下边分析一个Oauth2认证的例子,网站使用微信认证的过程:

在这里插入图片描述
1.用户进入网站的登录页面,点击微信的图标以微信账号登录系统,用户是自己在微信里信息的资源拥有者。

在这里插入图片描述
点击“微信”出现一个二维码,此时用户扫描二维码,开始给网站授权。

在这里插入图片描述
2.资源拥有者同意给客户端授权

资源拥有者扫描二维码表示资源拥有者同意给客户端授权,微信会对资源拥有者的身份进行验证,验证通过后,微信会询问用户是否给授权网站访问自己的微信数据,用户点击“确认登录”表示同意授权,微信认证服务器会颁发一个授权码,并重定向到网站。

  1. 客户端获取到授权码,请求认证服务器申请令牌

此过程用户看不到,客户端应用程序请求认证服务器,请求携带授权码。

  1. 认证服务器向客户端响应令牌

认证服务器验证了客户端请求的授权码,如果合法则给客户端颁发令牌,令牌是客户端访问资源的通行证。此交互过程用户看不到,当客户端拿到令牌后,用户在网站看到已经登录成功。

  1. 客户端请求资源服务器的资源

客户端携带令牌访问资源服务器的资源。网站携带令牌请求访问微信服务器获取用户的基本信息。

  1. 资源服务器返回受保护资源

资源服务器校验令牌的合法性,如果合法则向用户响应资源信息内容。

注意:资源服务器和认证服务器可以是一个服务也可以分开的服务,如果是分开的服务资源服务器通常要请求认证服务器来校验令牌的合法性。

Oauth2.0认证流程如下:

引自Oauth2.0协议rfc6749 https://tools.ietf.org/html/rfc6749

在这里插入图片描述


角色

客户端

本身不存储资源,需要通过资源拥有者的授权去请求资源服务器的资源,比如:Android客户端、Web客户端(浏览器端)、微信客户端等。

资源拥有者

通常为用户,也可以是应用程序,即该资源的拥有者。

授权服务器(也称认证服务器)

用来对资源拥有的身份进行认证、对访问资源进行授权。客户端要想访问资源需要通过认证服务器由资源拥有者授权后方可访问。

资源服务器

存储资源的服务器,比如,网站用户管理服务器存储了网站用户信息,网站相册服务器存储了用户的相册信息,微信的资源服务存储了微信的用户信息等。客户端最终访问资源服务器获取资源信息。


常用术语

  • 客户凭证(client Credentials):客户端的clientId和密码用于认证客户
  • 令牌(tokens):授权服务器在接收到客户请求后,颁发的访问令牌
  • 作用域(scopes):客户请求访问令牌时,由资源拥有者额外指定的细分权限(permission)

令牌类型

  • 授权码:仅用于授权码授权类型,用于交换获取访问令牌和刷新令牌

  • 访问令牌:用于代表一个用户或服务直接去访问受保护的资源

  • 刷新令牌:用于去授权服务器获取一个刷新访问令牌

  • BearerToken:不管谁拿到Token都可以访问资源,类似现金

  • Proof of Possession(PoP) Token:可以校验client是否对Token有明确的拥有权


特点

优点

​ 更安全,客户端不接触用户密码,服务器端更易集中保护

​ 广泛传播并被持续采用

​ 短寿命和封装的token

​ 资源服务器和授权服务器解耦

​ 集中式授权,简化客户端

​ HTTP/JSON友好,易于请求和传递token

​ 考虑多种客户端架构场景

​ 客户可以具有不同的信任级别

缺点

协议框架太宽泛,造成各种实现的兼容性和互操作性差

​ 不是一个认证协议,本身并不能告诉你任何用户信息。


授权模式

授权码模式(Authorization Code)

在这里插入图片描述


简化授权模式(Implicit)

在这里插入图片描述


密码模式(Resource Owner PasswordCredentials)

在这里插入图片描述
同一个大型项目里面获取资源


客户端模式(Client Credentials)

在这里插入图片描述刷新令牌
docker就是客户端模式,去授权服务器进行授权,拿到令牌后,直接下载对应的镜像


刷新令牌----令牌过期

在这里插入图片描述


Spring Security Oauth2

授权服务器

在这里插入图片描述

  • Authorize Endpoint:授权端点,进行授权

  • Token Endpoint:令牌端点,经过授权拿到对应的Token

  • Introspection Endpoint:校验端点,校验Token的合法性

  • Revocation Endpoint:撤销端点,撤销授权


Spring Security Oauth2架构

在这里插入图片描述
流程:

  1. 用户访问,此时没有Token。Oauth2RestTemplate会报错,这个报错信息会被Oauth2ClientContextFilter捕获并重定向到认证服务器

  2. 认证服务器通过Authorization Endpoint进行授权,并通过AuthorizationServerTokenServices生成授权码并返回给客户端

  3. 客户端拿到授权码去认证服务器通过Token Endpoint调用AuthorizationServerTokenServices生成Token并返回给客户端

  4. 客户端拿到Token去资源服务器访问资源,一般会通过Oauth2AuthenticationManager调用ResourceServerTokenServices进行校验。校验通过可以获取资源。


Spring Security Oauth2授权码模式

创建项目

添加依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.2.2.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.yjxxt</groupId><artifactId>springsecurityoauth2demo</artifactId><version>0.0.1-SNAPSHOT</version><name>springsecurityoauth2demo</name><description>Demo project for Spring Boot</description><properties><java.version>1.8</java.version><spring-cloud.version>Greenwich.SR2</spring-cloud.version></properties><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-oauth2</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-security</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>${spring-cloud.version}</version><type>pom</type><!--只有在引入的时候才会生效--><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>

编写配置类

SecurityConfig.java----安全配置

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}@Overridepublic void configure(HttpSecurity http) throws Exception {http.csrf().disable().authorizeRequests().antMatchers("/oauth/**", "/login/**", "/logout/**").permitAll().anyRequest().authenticated().and().formLogin().permitAll();}
}

AuthorizationServerConfig.java----认证服务器配置

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {@Autowiredprivate PasswordEncoder passwordEncoder;@Overridepublic void configure(ClientDetailsServiceConfigurer clients) throws Exception {//放在内存中clients.inMemory()//配置client_id--客户端id.withClient("admin")//配置client-secret---秘钥---出于安全考虑,最好加密一下.secret(passwordEncoder.encode("112233"))//配置redirect_uri,用于授权成功后跳转//这里重定向uri是用来获取授权码的.redirectUris("http://www.baidu.com")//配置申请的权限范围---可以细分,这里是全部.scopes("all")//配置grant_type,表示授权类型--这里是授权码模式.authorizedGrantTypes("authorization_code");}
}

ResourceServerConfig.java----资源服务器配置

@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {@Overridepublic void configure(HttpSecurity http) throws Exception {http.authorizeRequests().anyRequest().authenticated().and().requestMatchers().antMatchers("/user/**");//配置需要保护的资源路径}
}

这里把客户端,授权服务器,资源服务器都放在了一起,正式环境下,客户端,授权服务器,资源服务器都属于不同的服务器


编写实体类

User.java

/*** 用户类*/
public class User implements UserDetails {private String username;private String password;private List<GrantedAuthority> authorities;public User(String username, String password, List<GrantedAuthority> authorities) {this.username = username;this.password = password;this.authorities = authorities;}@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {return authorities;}@Overridepublic String getPassword() {return password;}@Overridepublic String getUsername() {return username;}@Overridepublic boolean isAccountNonExpired() {return true;}@Overridepublic boolean isAccountNonLocked() {return true;}@Overridepublic boolean isCredentialsNonExpired() {return true;}@Overridepublic boolean isEnabled() {return true;}
}

编写Service

UserService.java

@Service
public class UserService implements UserDetailsService {@Autowiredprivate PasswordEncoder passwordEncoder;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {String password = passwordEncoder.encode("123456");return new User("admin",password, AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));}
}

编写Controller

UserController.java

//资源
@RestController
@RequestMapping("/user")
public class UserController {@GetMapping("/getCurrentUser")public Object getCurrentUser(Authentication authentication) {return authentication.getPrincipal();}
}

测试

获取授权码

http://localhost:8080/oauth/authorize?response_type=code&client_id=admin&redirect_uri=http://www.baidu.com&scope=all

http://localhost:8080/oauth/authorize?
response_type=code&client_id=admin&redirect_uri=http://www.baidu.com&scope=all 

在这里插入图片描述
注意,如果一直出现用户名和密码错误,请查看自己创建的user类,是否在对应getUname,getUpwd方法中返回了正确的用户名和密码

输入账户密码

在这里插入图片描述
点击授权获取授权码

在这里插入图片描述
根据授权码获取令牌(POST请求)

localhost/oauth/token

在这里插入图片描述
在这里插入图片描述

  • grant_type:授权类型,填写authorization_code,表示授权码模式

  • code:授权码,就是刚刚获取的授权码,注意:授权码只使用一次就无效了,需要重新申请。

  • client_id:客户端标识

  • redirect_uri:申请授权码时的跳转url,一定和申请授权码时用的redirect_uri一致。

  • scope:授权范围。

认证失败服务端返回 401 Unauthorized

注意:此时无法请求到令牌,访问服务器会报错

在这里插入图片描述
出现这个错误,找找是不是body请求体某个参数的key写错了,或者其他地方写错了

在这里插入图片描述

无论本次获取token成功与否,授权码都只能使用一次,使用一次后就无效了,需要重新申请。


通过授权码获取到的token如下:
在这里插入图片描述

根据token去资源服务器拿资源

在这里插入图片描述
拿到返回的资源信息:
在这里插入图片描述
如果修改token就会报错

在这里插入图片描述


Spring Security Oauth2 密码模式

在上面的代码中进行适当的修改即可

SecurityConfig.java

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}//用于密码模式@Bean@Overridepublic AuthenticationManager authenticationManagerBean() throws Exception {return super.authenticationManagerBean();}@Overridepublic void configure(HttpSecurity http) throws Exception {http.csrf().disable().authorizeRequests().antMatchers("/oauth/**", "/login/**", "/logout/**").permitAll().anyRequest().authenticated().and().formLogin().permitAll();}
}

AuthorizationServerConfig.java

/*** 授权服务器配置*/
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {@Autowiredprivate PasswordEncoder passwordEncoder;@Autowiredprivate AuthenticationManager authenticationManager;@Autowiredprivate UserService userService;/*** 使用密码模式需要配置*/@Overridepublic void configure(AuthorizationServerEndpointsConfigurer endpoints) {endpoints.authenticationManager(authenticationManager).userDetailsService(userService);}@Overridepublic void configure(ClientDetailsServiceConfigurer clients) throws Exception {clients.inMemory()//配置client_id.withClient("admin")//配置client-secret.secret(passwordEncoder.encode("112233"))//配置访问token的有效期.accessTokenValiditySeconds(3600)//配置刷新token的有效期.refreshTokenValiditySeconds(864000)//配置redirect_uri,用于授权成功后跳转.redirectUris("http://www.baidu.com")//配置申请的权限范围.scopes("all")//配置grant_type,表示授权类型//可以同时指定多个.authorizedGrantTypes("authorization_code","password");}
}

测试:

下面的认证输入的是用户id和秘钥

在这里插入图片描述

密码登录输入的就是我们自定义用户时,设置的用户名和密码

访问请求获取令牌

http://localhost:8080/oauth/token

在这里插入图片描述

获取到令牌
在这里插入图片描述
拿着令牌请求资源

在这里插入图片描述


在Redis中存储token

之前的代码我们将token直接存在内存中,这在生产环境中是不合理的,下面我们将其改造成存储在Redis中

添加依赖及配置

pom.xml

<!--redis 依赖-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- commons-pool2 对象池依赖 -->
<dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId>
</dependency>

application.properties

# Redis配置
spring.redis.host=192.168.10.100
#如果redis设置了密码登录,不要忘记配置

编写Redis配置类

RedisConfig.java

/*** 使用redis存储token的配置* @author zhoubin* @since 1.0.0*/
@Configuration
public class RedisConfig {@Autowiredprivate RedisConnectionFactory redisConnectionFactory;@Beanpublic TokenStore redisTokenStore(){return new RedisTokenStore(redisConnectionFactory);}}

在认证服务器配置中指定令牌的存储策略为Redis

/*** 授权服务器配置* @author zhoubin* @since 1.0.0*/
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {@Autowiredprivate PasswordEncoder passwordEncoder;@Autowiredprivate AuthenticationManager authenticationManager;@Autowiredprivate UserService userService;@Autowired@Qualifier("redisTokenStore")private TokenStore tokenStore;/*** 使用密码模式需要配置*/@Overridepublic void configure(AuthorizationServerEndpointsConfigurer endpoints) {endpoints.authenticationManager(authenticationManager).userDetailsService(userService).tokenStore(tokenStore);}@Overridepublic void configure(ClientDetailsServiceConfigurer clients) throws Exception {clients.inMemory()//配置client_id.withClient("admin")//配置client-secret.secret(passwordEncoder.encode("112233"))//配置访问token的有效期.accessTokenValiditySeconds(3600)//配置刷新token的有效期.refreshTokenValiditySeconds(864000)//配置redirect_uri,用于授权成功后跳转.redirectUris("http://www.baidu.com")//配置申请的权限范围.scopes("all")//配置grant_type,表示授权类型.authorizedGrantTypes("password");}
}

测试:

使用密码模式请求token

在这里插入图片描述
在这里插入图片描述



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

相关文章

2021年中国医药O2O行业发展现状、发展问题及发展建议分析[图]

医药O2O模式指的是基于线下药店&#xff0c;利用现存资源&#xff0c;将门店的功能从售药转变为体验、提货和配送&#xff0c;贴合当地需求&#xff0c;完成和用户的最终接轨。 随着疫情防控成为常态化&#xff0c;医药电商与数字医疗也迎来了新的发展。医药的网上销售呈现出逐…

中国IT运维O2O市场发展研究及十四五前景规划分析报告2022-2027年

中国IT运维O2O市场发展研究及十四五前景规划分析报告2022-2027年 第1章:IT运维O2O的概念界定与内涵1.1 IT运维的概念界定与内涵 1.1.1 IT运维的概念 1.1.2 IT运维的演化历程 1.1.3 IT运维的内容 1.1.4 IT运维的流程 1.1.5 IT运维的价值 1.2 IT运维O2O的概念界定与内涵…

案例直播 | Pulsar Summit Asia 2022:Day 1 - 分论坛 1:腾讯、华为、有道、vivo、科大讯飞...

关于 Pulsar Summit Pulsar Summit 是 Apache Pulsar 社区年度盛会&#xff0c;它将分布在世界各地的 Apache Pulsar 项目 Contributor、Committer 和各企业 CTO/CIO、开发者、架构师、数据科学家&#xff0c;以及消息和流计算社区的精英召集在一起。于此盛会&#xff0c;大家分…

高德导航免费,那他靠什么收入?

来源 &#xff5c;一口Linux 一位工作了12年的软件工程师说&#xff1a;当你打开导航时&#xff0c;不需要任何费用&#xff0c;还会给高德公司带来丰厚的收入。当时我不信&#xff0c;去查了相关资料后&#xff0c;才知道这个行业不简单。 出门外出&#xff0c;对路线不熟时&a…

全球及中国前置汽车中冷器行业需求趋势分析及发展规划研究报告2021-2027年版

全球及中国前置汽车中冷器行业需求趋势分析及发展规划研究报告2021-2027年版 2020年,全球前置汽车中冷器市场规模达到了XX百万美元,预计2027年可以达到XX百万美元,年复合增长率(CAGR)为XX% (2021-2027)。中国市场规模增长快速,预计将由2020年的XX百万美元增长到2027年的X…

智能家居市场应采用精准营销策划模式

智能家居在全世界的发展都属于新鲜事物&#xff0c;在中国市场&#xff0c;智能家居行业参与进来的企业众多&#xff0c;包括跨国企业也包括本土的强势品牌都参与其中&#xff0c;唐太子、霍尼韦尔、莫顿、新加坡NICO、上海索博、广东安居宝、波创科技、海尔集团、天津瑞朗、联…

O2O营销结构思维导图模板分享

O2O营销是线上线下营销&#xff0c;随这互联网科技的发展&#xff0c;很多公司的业务从线下扩展到线上。但是在如此多行业的竞争下&#xff0c;怎样做好线上业务就成为最大的麻烦&#xff0c;下面是分享的O2O营销结构思维导图模板以及利用在线工具编辑思维导图的操作方法&#…

新项目从零到一DDD实战思考与总结

抱歉了&#xff0c;前面几篇DDD的文章我删除了&#xff0c;本篇是前面发表的几篇DDD的汇总&#xff0c;内容有修改。 领域驱动设计&#xff08;DDD&#xff09;是一种业务领域建模方法论、业务架构设计方法论&#xff0c;战略设计阶段从业务领域视角划分领域边界&#xff0c;抽…

设计模式 | 四、代理模式(静态代理、JDK动态代理、Cglib动态代理、手写动态代理核心部分)[ProxyPattern]

代理模式 源码&#xff1a;https://github.com/GiraffePeng/design-patterns 1、应用场景 在生活中&#xff0c;我们经常见到这样的场景&#xff0c;如&#xff1a;租房中介、售票黄牛、婚介、经纪人、快递、事务代理、非侵入式日志监听等&#xff0c;这些都是代理模式的实际…

23种设计模式 原型设计模式

原型模式的定义&#xff1a; 原型模式&#xff1a;使用原型实例指定待创建对象的类型&#xff0c;并且通过复制这个原型来创建新的对象。 原型模式的结构&#xff1a; 原型模式主要包含3个角色&#xff1a; &#xff08;1&#xff09;Prototype(抽象原型类)&#xff1a;声明克…

OTO模式 传统产业掘金互联网时代的利器

OTO模式 传统产业掘金互联网时代的利器 2013年10月16日 07:11 来源&#xff1a;中国经济网—《证券日报》 编者按&#xff1a;今年以来&#xff0c;一种新型的商业模式OTO模式迅速被国内众多传统企业所熟悉&#xff0c;很多传统企业借助OTO模式实现了从传统产业向互联网时…

OTO电子商务商业模式探析

一、前言 OTO&#xff08;O2O&#xff09;&#xff0c;即Online to Offline&#xff0c;是将线下商务机会与线上互联网结合在一起&#xff0c;让互联网成为线下交易前台的一种电子商务商业模式&#xff0c;简单来说就是“线上拉客&#xff0c;线下消费”。其核心理念是通过电子…

2020-1024

2020 - 1024 996

1024程序员节

1024是一种逐渐流行的回帖方式&#xff0c;常见于BBS、网络社区和论坛的网友交流中。其常见形式为"1024"、"1024顶"两种形式。 1024所表达的含义&#xff0c;类似于"顶"、"非常棒&#xff0c;一级棒" &#xff0c;还有表达回帖者的身…

1024,干程序才懂得节日!

1024程序员节 1024程序员节是广大程序员的共同节日。1024是2的十次方&#xff0c;二进制计数的基本计量单位之一。针对程序员经常周末加班与工作日熬夜的情况&#xff0c;部分互联网机构倡议每年的10月24日为1024程序员节&#xff0c;在这一天建议程序员拒绝加班。 程序员就像是…

2022年的1024

一年一度的1024来啦&#xff01; 今年是我的第6个1024. 在这个专属节日里&#xff0c;我想随性记录一下当下的心境吧&#xff1a; 从2016年接触编程以来&#xff0c;自己各方面都有成长&#xff0c;可是不变的是从最初知道自己是小白到现在知道自己还是小白&#xff0c;笑死…

1024,鸽了1024篇博文的我。。。

1024&#xff0c;鸽了1024篇博文的我。。。 最近&#xff0c;硕士研究生刚开学&#xff0c;鉴于小菜鸡的我刚开始我的“填坑”之路&#xff0c;很忙&#xff0c;对&#xff0c;真的&#xff01;&#xff01;&#xff01; 我在忙什么&#xff1f; 忙于脑网络的学习&#xff0c…

「1024」福利

重点突出 这不是一篇纯技术文&#xff0c;也不是一篇广告文&#xff0c;而是我和明哥等几个 Android 开发者共同在做的一件事&#xff1a;「Android答疑解惑」。 我们在做一个付费的 Android 圈子&#xff0c;这里可以提供 Android系统层和 Android应用层方面的技术&#xff0c…

浅谈1024

说起1024&#xff0c;大家都知道在数学计算中1GB1024MB&#xff0c;1MB1024KB&#xff0c;1KB1024Byte。 对于程序员来说&#xff0c;接触1024的机会非常多&#xff0c;所以被广大程序员称为&#xff1a;程序员节 浅谈自己的1024 我的第1024行代码 if (devicesBean.getMetadat…