Azure AD统一认证及用户数据同步开发指导

news2024/11/16 5:58:10

本文主要目的为:指导开发者进行自有服务与Azure AD统一认证的集成,以及阐述云端用户数据同步的实现方案。本文除了会介绍必要的概念、原理、流程外,还会包含Azure门户设置说明,以及使用Fiddler进行全流程的实操验证,同时还会结合实际的业务需求提出具体的方案建议及关键实现方法的说明,以此达到开发指导的效果。

1. 基础概念

1.1 Azure AD

Azure Active Directory,简称 Azure AD,是微软提供的云身份验证服务,用于管理用户身份和访问权限。它是基于标准的开放式身份协议构建的,可以与多种应用程序和服务集成,包括云应用程序、本地应用程序和移动应用程序。
在这里插入图片描述

1.1.1 Azure AD 主要功能

  • 身份验证和授权管理: Azure AD 提供了多种身份验证方式,包括用户名和密码、多重身份验证、SSO(单一登录)等,以确保用户身份的安全性。它还可以管理用户对资源的访问权限,并控制用户能够执行的操作。
  • 集成式身份管理: Azure AD 可以与其他标识提供者集成,包括本地 Active Directory、LDAP、SAML 和 OAuth,使用户可以使用他们已有的帐户登录到 Azure AD 中的应用程序和服务。
  • 应用程序集成: Azure AD 支持与各种应用程序和服务的集成,包括 Microsoft 365、Azure、SaaS 应用程序、自定义应用程序等。它提供了一种安全的方式来管理和控制用户对这些应用程序的访问权限。
  • 安全和合规性: Azure AD 提供了安全性和合规性功能,包括多重身份验证、条件访问、安全策略、审计日志等,以帮助组织保护其数据和资源。

总之,Azure AD 是一个灵活且功能强大的身份验证和访问管理平台,可以帮助组织实现身份验证、授权和安全管理的统一化。从本质上来说,Azure AD 是基于 OAuth 2.0 和 OpenID Connect 规范的。OAuth 2.0 是一种用于授权的开放标准,用于安全地委托访问令牌,而 OpenID Connect 则是在 OAuth 2.0 的基础上添加了身份验证的协议。Azure AD 结合了这两种标准,以提供身份验证和授权功能,支持多种身份验证方法,并提供与其他服务和应用程序的集成。

需要补充说明的是Microsoft 将 Azure Active Directory (Azure AD) 更名为 Microsoft Entra ID,以介绍产品的多云多平台功能、缓解与 Windows Server Active Directory 的混淆,并统一 Microsoft Entra 产品系列。详见官方文档:https://learn.microsoft.com/zh-cn/entra/

1.1.2 Azure AD 与 ADFS区别

Azure AD 和 Active Directory Federation Services(ADFS)都是由微软提供的身份认证解决方案,但它们在一些方面有所不同:

  • 部署位置
    Azure 统一认证是基于云的身份认证解决方案,完全托管在 Microsoft Azure 云平台上。
    ADFS 是一个本地部署的身份认证解决方案,通常部署在组织的本地网络中。
  • 适用范围
    Azure 统一认证是为云环境和混合云环境设计的,可以为云服务、SaaS 应用程序以及本地应用程序提供身份验证和访问控制。
    ADFS 主要用于提供单点登录 (SSO) 和基于标准的身份验证服务,通常用于本地应用程序和企业资源的身份认证。
  • 标准支持
    Azure 统一认证支持 OAuth 2.0 和 OpenID Connect 等开放标准,使其能够与多种应用程序和服务集成。
    ADFS 支持标准的身份验证协议,如SAML(Security Assertion Markup Language)和 WS-Federation(Web Services Federation)。
  • 管理和维护
    Azure 统一认证是一种完全托管的服务,由 Microsoft 管理和维护,无需组织自行管理基础设施。
    ADFS 需要组织自行部署、配置和维护,需要更多的 IT 管理工作。
  • 灵活性和扩展性
    Azure 统一认证提供了更高的灵活性和扩展性,可以通过添加和配置不同的功能组件来满足不同的身份验证和授权需求。
    ADFS 在本地部署方面更加灵活,可以根据组织的特定需求进行自定义和配置。

综上所述,Azure 统一认证适用于云环境和混合云环境,提供了更多的托管功能和集成选项,而 ADFS 则更适用于需要本地部署、自定义和控制的场景。关于ADFS及AD的部署配置可以参考:https://blog.csdn.net/camelials/article/details/134857159

1.2 微软Graph

Microsoft Graph 是微软提供的统一 API 平台,用于访问 Microsoft 365 中的各种数据和服务。它提供了一种统一的方式来访问多种 Microsoft 产品和服务的数据,包括 Office 365、Azure Active Directory、Exchange Online、SharePoint 等。
在这里插入图片描述

理解 Microsoft Graph 可以从以下几个方面来看:

  • 统一访问数据和服务:Microsoft Graph 提供了一个统一的终结点,使开发者可以通过一组 API 来访问各种 Microsoft 产品和服务中的数据和功能,而不需要与每个服务单独交互。
  • 多种数据类型支持:Microsoft Graph 支持访问多种类型的数据,包括用户信息、邮件、日历、文件、组织结构等。这些数据可以用于构建各种类型的应用程序和解决方案。
  • RESTful API:Microsoft Graph 的 API 是基于 RESTful 架构的,使用标准的 HTTP 方法和 URL 结构进行访问。这使得它易于使用和集成到现有的应用程序和开发工具中。
  • 权限控制和安全性:Microsoft Graph 提供了严格的权限控制机制,开发者需要通过 OAuth 2.0 认证来获取访问权限,并在访问数据时遵循权限范围的规定,确保数据的安全性和隐私保护。
  • 实现业务逻辑:通过 Microsoft Graph,开发者可以实现各种业务逻辑,例如获取用户信息、发送邮件、管理文件、创建团队等。它可以帮助开发者构建智能化、协作化的应用程序和解决方案。

总的来说,Microsoft Graph 提供了一种统一、灵活的方式来访问 Microsoft 365 中的数据和服务,为开发者提供了丰富的功能和资源,帮助他们构建创新的应用程序和解决方案。Microsoft Graph 中的主要服务和功能可以参考官方文档:https://learn.microsoft.com/zh-cn/graph/overview-major-services

2. 统一认证流程及实操验证

微软Graph分为中国版(由上海世纪互联运营)和国际版,两者大致一样,但是也存在一些差异,例如:Portal门户设置UI不同,终结点不同,一些接口的参数和约定不同等,这里以全球版的v1.0进行介绍。

2.1 前置条件

2.1.1 应用程序注册/设置

1、基本设置
在这里插入图片描述
应用程序主要基本设置如上图,其中租户ID(tenant_id)、应用程序ID(client_id)、客户端凭据(client_secret)、重定向URL(redirect_uri)等在后续的授权及微软Graph API调用的时候需要使用。例如:

### 登录授权终结点
https://login.microsoftonline.com/#{tenant}/oauth2/v2.0/authorize?client_id=#{client_id}&response_type=code&redirect_uri=#{redirect_uri}

### 授权码获取Token
POST https://login.microsoftonline.com/#{tenant}/oauth2/v2.0/token
Content-Type: application/x-www-form-urlencoded

client_id=#{client_id}
&scope=User.Read
&redirect_uri=#{redirect_uri}
&grant_type=authorization_code
&client_secret=#{client_secret}
&code=#{auth_code}

2、API权限设置
在这里插入图片描述
1、可以把Microsoft Graph理解为访问Microsoft 365 和 Azure 云端资源的网关,若要访问这些资源则需要用户或管理员向其授予所需的权限。如果权限设置不当,则在实际的访问中就会遇到各种权限相关错误,例如:Authorization_RequestDenied(Insufficient privileges to complete the operation.),因此权限控制是实操过程中经常被提及和困惑的问题。详细可以参考微软官方文档:https://learn.microsoft.com/zh-cn/graph/permissions-reference

2、从上图中的权限类型可以看到有2种:委托和应用程序,委托可以理解为用户认证成功之后的委托授权访问,为了好理解,我把这称之为:AppUser权限(需要用户授权);应用程序则不需要用户授权,而是由管理员授权,为了好理解和区分,可以称之为:AppOnly权限。举个例子:

  • AppUser权限:用户登录认证成功之后返回一个授权码,用这个授权码获得的Token就可以访问该登录用户自己的信息和资源,例如他自己的Profile信息,但是无权访问别人的相关资源。这就是AppUser权限的委派授权。
  • AppOnly权限:自有服务(AppServer)直接请求Azure令牌终结点获取Token,然后用该Token请求微软Graph获取该租户下所有的用户数据。

在这里把开通Directory.Read.All和User.Read.All的AppOnly权限的原因是对于用户数据同步的方案,我们将会选择Delta Query方案。对于用户数据同步的方案微软其实提供了2种,后面会详细讲。

2.2 AppUser方式授权

在这里插入图片描述
在了解了AppUser方式授权和AppOnly授权的差异之后,对于上面的流程图就能很容易的理解了,下面对于一些关键点的开发指导做进一步的描述:

1、AppServer需要向客户端提供一个后去登录认证地址的接口。认证终结点地址可以在Azure应用程序中进行查看,如下图:
在这里插入图片描述
同时,认证终结点还需要携带一些参数,示例如下(相关含义,前面的《应用程序注册/设置》章节已经进行过描述):

https://login.microsoftonline.com/#{tenant}/oauth2/v2.0/authorize?client_id=#{client_id}&response_type=code&redirect_uri=#{redirect_uri}

2、客户端拿到登录认证地址即可进行登录,如下图。一般来说,客户端会使用系统浏览器访问Azure授权终结点,那么会遇到一个问题:此时已不在客户端App的进程之内,那么后续该如何重新回到App,或者如何通知App登录认证完成呢?问题先放着,后面会讲。
在这里插入图片描述

3、登录完成之后Azure授权终结点会向事先配置好的回调终结发送一个POST请求,该请求会包含一个授权码,表示认证通过可以授权。下面演示通过使用Fiddler抓包去查看授权码:
在这里插入图片描述
通过上面的方法,我们可以获得授权码。由于这里只是测试,因此我把回调地址配置成了一个不存在的:https://www.baidu.com/login,因此404,但是这并不影响我们通过用Fiddler抓包去查看授权码。

4、拿到授权码后就可以请求Azure令牌终结点去获取Token了,请求示例如下:

### token[authorization_code]
POST https://login.microsoftonline.com/#{tenant}/oauth2/v2.0/token
Content-Type: application/x-www-form-urlencoded

client_id=#{client_id}
&scope=User.Read
&redirect_uri=#{redirect_uri}
&grant_type=authorization_code
&client_secret=#{client_secret}
&code=#{auth_code}

应答示例如下:

HTTP/1.1 200 OK
Cache-Control: no-store, no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Content-Type-Options: nosniff
P3P: CP="DSP CUR OTPi IND OTRi ONL FIN"
x-ms-request-id: 803bf994-b432-4ee8-8380-b1e370535b00
x-ms-ests-server: 2.1.17846.6 - SEASLR1 ProdSlices
x-ms-srs: 1.P
X-XSS-Protection: 0
Set-Cookie: fpc=Al_NmhqaTrVPmpaVIt5Vo10V53uDAQAAAD0mtN0OAAAA; expires=Sun, 19-May-2024 08:45:50 GMT; path=/; secure; HttpOnly; SameSite=None
Set-Cookie: x-ms-gateway-slice=estsfd; path=/; secure; samesite=none; httponly
Date: Fri, 19 Apr 2024 08:45:50 GMT
Content-Length: 2340

{
  "token_type": "Bearer",
  "scope": "User.Read profile openid email",
  "expires_in": 5229,
  "ext_expires_in": 5229,
  "access_token": "eyJ0eXAiOiJKV1QiLCJub25jZSI6Ik..."
}

需要补充说明的是access_token其实就是一个json的jwt序列化字符串,https://jwt.ms/ 可以进行在线解码:
在这里插入图片描述
其实使用com.auth0.jwt.JWT也可以进行解码,但是并不推荐通过这样的方式去获取用户信息,因为目前尚不明确微软对于算法是如何约定的,通过穷尽尝试几种常用的算法成功解码,假如有天微软把算法变了,程序不就出Bug了吗?这里,只是向告诉大家access_token的本质其实就是一个类似ADFS的授权Claims Json信息,常见的 JWT 签名算法有:

  • HMAC256:使用 HMAC(Hash-based Message Authentication Code)和 SHA-256 算法生成签名。
  • RS256:使用 RSA(Rivest-Shamir-Adleman)加密算法和 SHA-256 哈希算法生成签名,需要使用 RSA 公钥/私钥对进行签名和验证。
  • ES256:使用 ECDSA(Elliptic Curve Digital Signature Algorithm)和 SHA-256 哈希算法生成签名,需要使用 ECDSA 公钥/私钥对进行签名和验证。
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;

public class JWTDecoder {
    public static void main(String[] args) {
        String jwtToken = "your_jwt_token_here";
        String secretKey = "your_secret_key_here";

        try {
            Algorithm algorithm = Algorithm.HMAC256(secretKey);
            JWTVerifier verifier = JWT.require(algorithm).build();
            DecodedJWT decodedJWT = verifier.verify(jwtToken);

            // 获取 JWT 中的用户 UPN
            String upn = decodedJWT.getSubject();

            System.out.println("User UPN: " + upn);

        } catch (Exception e) {
            // 处理异常
            e.printStackTrace();
        }
    }
}

5、拿到AccessToken之后就可以请求微软Graph根据业务处理的需要去后去资源了,一般业务场景下都需要首先获得当前登录用户的Profile信息,请求示例如下:

### me
GET https://graph.microsoft.com/v1.0/me
Authorization: Bearer #{access_token}

微软Graph参考资源:

  • https://learn.microsoft.com/zh-cn/graph/api/overview?view=graph-rest-1.0
  • https://developer.microsoft.com/en-us/graph/graph-explorer

6、前面抛出了一个问题:客户端会使用系统浏览器访问Azure授权终结点那么后续该如何重新回到App,或者如何通知App登录认证完成了呢?要解决这个问题其实方案有很多,例如:
1)集成微软SDK;
2)通过服务端输出合适的JS将控制权交给重新交给客户端;
3)重定向到一个中间站点并通过url参数方式传值;
4)将处理结果放在header中;
5)服务端下发通知给客户端(双工App应用,服务端可以向客户端下发通知);
这里我推荐使用方案2,示例JS脚本如下:

<html>
    <header></header>
    <body>
    </body>
    <script language='javascript'>
        if (window.ad) {
            window.ad.end(0, 'ok');
        }
    </script>
</html>

这段 JavaScript 脚本首先检查当前页面是否存在名为 “ad” 的全局对象或变量。如果存在,它调用 “ad” 对象的 “end” 方法,并传入两个参数:0 和 ‘ok’,其中,0 代表状态码,‘ok’ 为描述(code + msg 表达认证回调的服务端处理结果)。

通过服务端输出合适的JS将控制权交给重新交给客户端,这其实是目前的一种经典做法,因为JS是运行在客户端的Local上。上述JS脚本代码通常在网页中嵌入的广告脚本中使用,当广告成功加载并展示后,广告服务商通常会调用类似的方法来通知页面,以便页面做出相应的处理。

2.3 AppOnly授权

在这里插入图片描述
在了解了AppUser授权的相关内容后,AppOnly的授权就会十分简单了:AppServer直接请求Azure令牌终结点获取Token。当然,这里需要事先在Azure门户中对API权限进行应用程序授权(前面已经介绍过),请求示例如下:

### token[client_credentials]
POST https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token
Content-Type: application/x-www-form-urlencoded

client_id=#{client_id}
&redirect_uri=#{redirect_uri}
&grant_type=client_credentials
&client_secret=#{client_secret}
&scope=https://graph.microsoft.com/.default

应答示例如下(这里贴个实测的图来证明确实可行)。
在这里插入图片描述
最后,大家可以用这种方式下获得的Token去调用微软Graph(当然,要访问的资源需要事先由Azure管理员授权),后面会涉及获取租户下所有的用户数据,用的token就是这种。大家可以比较下与AppUser授权方式获取Token的差异,那么就会发现grant_type和scope的不同。关于scope=https://graph.microsoft.com/.default的说明,大家可以去查阅微软官网。

3. 用户数据同步方案

Azure提供2种变更数据获取方案:订阅(webhook)方案、Delta Query方案,综合利弊建议大家选择Delta Query方案

方案
订阅方案1、对于Azure第三方应用程序服务端实现简单,只需要接收数据变更通知并予以处理即可;1、webhook方式接收方无法自主控制频度和重试(对于订阅方式,Azure 平台会尽力发送数据通知,但并不保证数据的实时性或完整性,在设计应用程序时应考虑到这一点,并实施适当的容错机制)
2、Azure订阅会有费用成本(计费策略因子为:订阅的数量、通知的频率、数据传输量等),而且可以设置费用告警阈值。这些可能产生解释/沟通成本,同时可能会被客户挑战:为什么不使用无费用的Delta Query方案。
3、webhook订阅数据通知只限于增量变化数据的获取,首次全量数据同步仍然需要从微软Graph接口中获取。
Delta Query方案1、可以自主控制数据获取的频度和失败重试。
2、不涉及成本问题的客户挑战。
3、首次全量数据获取与增量数据获取的方案和处理统一(Delta Query接口有类似版本号的可选参数,不携带该参数则为首次全量获取)
1、Azure第三方应用程序服务端实现相对复杂:需要自行考虑频度,重试等问题。同时还需要自行维护数据版本信息以实现增量数据获取。
2、需要一次性对应用程序API权限进行授权(AppOnly授权方式)。

1、Delta Query方案其实是一个轮询方案,那么就会涉及定时任务,当前可选的框架很多:Spring Framework 的任务执行器(TaskExecutor)、Quartz 、XX-Job等。至于说Delta Query的频度,这个大家根据业务需要自行指定(一天一次也好,多少小时分钟一次也好)。

2、Delta Query方案大家需要理解如何实现数据的增量获取,我给大家演示下首次全量数据获取和非首次增量数据获取大家就明白了。

  • 首次全量数据获取
    在这里插入图片描述
  • 非首次增量数据获取
    在这里插入图片描述
    通过对比上面2个请求和应答就可以很容易的发现:

每次Delta Query请求应答都会返回一个deltatoken,其实可以把这个deltatoken理解为资源的版本。那么就很容易的能够理解:首次全量数据获取就不携带deltatoken,要获取某个版本之后的增量数据就携带deltatoken去请求即可。

最后需要说明的是:对于订阅和Delta Query其实是Azure对于很多资源的通用方案,因此不只是users可以使用,其他的资源也可以使用。前面说了,可以把微软Graph理解为访问云端资源的网关,用户是资源,邮件是资源,outlook等都是资源。
在这里插入图片描述

4. 总结

1、要实现Azure AD统一认证与自己业务的系统的集成,一般来说自身业务系统需要实现2个接口即可:1)获取登录认证Url接口(getAuthUrl);2)认证回调处理接口(authCallback);
2、自身业务系统需要维护自身业务系统UID与Azure AD的用户唯一标识(一般为用户的UPN,这也是AD规范中所推荐使用的),可以把这个过程称之为绑定(大家可以参考下IDasS厂商的一些共同做法),对于已经绑定的用户数据就可以支持定时与云端的数据同步。
3、要实现Azure AD用户数据与自身业务系统用户数据的同步,虽然微软提供了2种方案(订阅方案和Delta Query方案),但是结合一般业务场景下的利弊分析后,建议选择Delta Query方案,但是这也不是绝对的,如何选择还得具体问题具体分析。

上述内容调研和折腾了几天的时间,整个过程也都进行了实操验证,而且我也尽量把一些概念、原理也都给予一定的介绍,最后个人认为做调研以下两点非常重要:
1)知其然,知其所以然。
2)一定要上手实操验证。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

.net core webapi 添加日志管理看板LogDashboard

.net core webapi 添加日志管理看板LogDashboard 添加权限管理&#xff1a; 我们用的是Nlog文件来配置 <?xml version"1.0" encoding"utf-8" ?> <nlog xmlns"http://www.nlog-project.org/schemas/NLog.xsd"xmlns:xsi"http:/…

CSS基础:浮动(float)的3种方式,清除浮动3种方式的详解

你好&#xff0c;我是云桃桃。 一个希望帮助更多朋友快速入门 WEB 前端的程序媛。 云桃桃-大专生&#xff0c;一枚程序媛&#xff0c;感谢关注。回复 “前端基础题”&#xff0c;可免费获得前端基础 100 题汇总&#xff0c;回复 “前端工具”&#xff0c;可获取 Web 开发工具合…

iOS - Runloop在实际开发中的应用

文章目录 iOS - Runloop在实际开发中的应用1. 控制线程生命周期&#xff08;线程保活&#xff09;2. 解决NSTimer在滑动时停止工作的问题2.1. 案例2.2 解决 3. 监控应用卡顿4. 性能优化 iOS - Runloop在实际开发中的应用 1. 控制线程生命周期&#xff08;线程保活&#xff09;…

linux系统安全与应用【下】

目录 1.开关机安全控制 1.1GRUB限制 2.终端登录安全控制 2.1 限制root只在安全终端登录 2.2 禁止普通用户登录 3.弱口令检测 3.1 Joth the Ripper&#xff08;JR&#xff09; 4.网络端口扫描 4.1 nmap命令 1.开关机安全控制 1.1GRUB限制 通常情况下在系统开机进入GRU…

Java微服务架构之Spring Boot —上篇

SpringBoot 概述 SpringBoot提供了一种快速使用Spring的方式&#xff0c;基于约定优于配置的思想&#xff0c;可以让开发人员不必在配置与逻辑业务之间进行思维的切换&#xff0c;全身心的投入到逻辑业务的代码编写中&#xff0c;从而大大提高了开发的效率&#xff0c;一定程度…

模板初阶

泛型编程&#xff1a; 泛型编程&#xff1a;编写与类型无关的通用代码&#xff0c;模板是泛型编程的基础 class Test { public:void Swap(int& left, int& right){int tmp left;left right;right tmp;}void Swap(double& left, double& right){double tmp…

orbslam2+kitti数据集序列图像

文章目录 一、下载ORB Slam2依赖二、安装编译ORB_SLAM2三 、运行Kitee数据集3.1 数据集准备3.2 启动&#xff01;&#xff01;&#xff01; 安装ORB Slam2遇到的问题总结参考资料 一、下载ORB Slam2依赖 Orb Slam2 需要下载的依赖项&#xff1a; Pangolin0.5 、Eigen3.1以上、…

【Hadoop3.3.6】数据块副本放置策略及解析EditLog和FsImage

目录 一、摘要二、正文2.1 环境说明2.2 网络拓扑2.3 Hadoop副本放置策略介绍2.4 解析EditLog和Fsimage镜像文件三、小结一、摘要 通过解析存储于NameNode节点上的日志文件EditLog和镜像文件(元数据)Fsimage来反向验证HDFS的数据块副本存放策略,其目的是希望加深对Hadoop的数…

AJAX——同步代码和异步代码

1.同步代码 同步代码&#xff1a;浏览器是按照我们书写代码的顺序一行一行地执行程序的。浏览器会等待代码的解析和工作&#xff0c;在上一行完成后才会执行下一行。这样做是很有必要的&#xff0c;因为每一行新的代码都是建立在前面代码的基础之上的。 这也使得它成为一个同步…

ubuntu快捷更pip源

py安装: apt-get install python3-pip终端输入: pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/

图论基础知识 深度搜索(DFS,Depth First Search),广度搜索(BFS,Breathe First Search)

图论基础知识 学习记录自代码随想录 dfs 与 bfs 区别 dfs是沿着一个方向去搜&#xff0c;不到黄河不回头&#xff0c;直到搜不下去了&#xff0c;再换方向&#xff08;换方向的过程就涉及到了回溯&#xff09;。 bfs是先把本节点所连接的所有节点遍历一遍&#xff0c;走到下…

【React】Day6

项目搭建 基于CRA创建项目 CRA是一个底层基于webpack快速创建React项目的脚手架工具 # 使用npx创建项目 npx create-react-app react-jike# 进入到项 cd react-jike# 启动项目 npm start调整项目目录结构 -src-apis 项目接口函数-assets 项目资源文件&…

JavaEE初阶——多线程(六)——线程池

T04BF &#x1f44b;专栏: 算法|JAVA|MySQL|C语言 &#x1faf5; 小比特 大梦想 此篇文章与大家分享多线程的第六篇文章,关于线程池 如果有不足的或者错误的请您指出! 目录 3.线程池3.1标准库的线程池3.2 标准库自己提供的几个工厂类3.3自己实现一个线程池完成大体框架接下来完…

Hive架构原理

Hive Hive 的架构是设计用于在大数据环境下进行数据仓库操作和分析的系统。它建立在 Hadoop 生态系统之上&#xff0c;利用 Hadoop 的存储&#xff08;HDFS&#xff09;和计算&#xff08;MapReduce、Tez、Spark 等&#xff09;能力。 1. 元数据存储&#xff08;Metastore&am…

go语言并发实战——日志收集系统(六) 编写日志收集系统客户端

上节回顾 在上一篇文章中我们介绍了编写客户端的四个步骤&#xff0c;分别是&#xff1a; 读取配置文件&#xff0c;寻找日志路径初始化服务根据日志路径l来收集日志将收集到的日志发送Kafka中 关于上述的内容博主画了一个思维导图(有点丑&#xff0c;大家勉强看看&#xff0…

iOS - 多线程-GCD

文章目录 iOS - 多线程-GCD1. 常见多线程方案2. GCD2.1 GCD的常见函数GCD中有2个用来执行任务的函数 2.2 GCD的队列2.2.1 GCD的队列可以分为2大类型 2.3 容易混淆的术语2.4.1 有4个术语比较容易混淆&#xff1a;同步、异步、并发、串行 2.4 各种队列的执行效果 3. 死锁3.1 死锁…

鸿蒙开发模拟器的坑, No Devices

问题 我已经安装了模拟器&#xff0c;并且模拟器已经运行了 在Device Manager页面开启模拟器 No Devices 但是这里没有模拟器的选项 解决 添加环境变量 下面步骤 1、清除用户数据 2、 关闭Device Manager 3、 关闭ide 重启ide、开启模拟器 看到有模拟器的选项了

【数据结构|C语言版】算法效率和复杂度分析

前言1. 算法效率2. 大O的渐进表示法3. 时间复杂度3.1 时间复杂度概念3.2 时间复杂度计算举例 4. 空间复杂度4.1 空间复杂度的概念4.2 空间复杂度计算举例 5. 常见复杂度对比结语 ↓ 个人主页&#xff1a;C_GUIQU 个人专栏&#xff1a;【数据结构&#xff08;C语言版&#xff09…

光伏仿真设计需要用到的工具有哪些?

随着全球能源结构的转型和可持续发展战略的深入实施&#xff0c;光伏发电作为一种清洁、可再生的能源形式&#xff0c;正日益受到广泛关注和应用。在光伏系统的设计和优化过程中&#xff0c;光伏仿真设计工具发挥着至关重要的作用。那么&#xff0c;光伏仿真设计需要用到的工具…

Opencv_3_图像对象的创建与赋值

ColorInvert.h 如下&#xff1a; #include <opencv.hpp> using namespace std; #include <opencv.hpp> using namespace cv; using namespace std; class ColorInvert{ public : void mat_creation(); }; ColorInvert.cpp 文件如下&#xff1a; #include &q…