API 网关 OpenID Connect 实战:单点登录(SSO)如此简单

作者:戴靖泽,阿里云 API 网关研发,Higress 开源社区 Member

前言

随着企业的发展,所使用的系统数量逐渐增多,用户在使用不同系统时需要频繁登录,导致用户体验较差。单点登录(Single Sign-On,简称 SSO)正是为了解决这一问题。当用户登录一次后,即可获取所有系统的访问权限,不需要对每个单一系统逐一登录。

目前,SSO 的实现方案常见有以下几种:

  1. 基于 JWT: JWT(JSON Web Token)是一种用于在各方之间安全传递信息的开放标准,令牌中包含用户的身份信息和权限。然而,JWT 用于 SSO 时缺乏标准化方案,导致集成复杂,且令牌一旦签发无法撤销,可能影响安全性。
  2. 基于 CAS: CAS(Central Authentication Service)是一种基于中间件的开源单点登录解决方案,通常用于大学和大型企业。用户在一处登录后即可无缝访问所有与 CAS 集成的应用。但其实现较为复杂,对系统集成要求较高。
  3. 基于 SAML: SAML(Security Assertion Markup Language)是一种协议,用于在应用程序与 SSO 服务之间交换身份验证信息。它使用 XML 来交换用户标识数据,提供高安全性和灵活性,但配置和实施较为复杂,增加了开发和维护成本。
  4. 基于 OIDC: OIDC(OpenID Connect)是基于 OAuth 2.0 的身份验证层,允许用户通过多种客户端(如 Web 应用、移动应用等)进行身份验证。OIDC 具有标准化、简单易用、灵活性和安全性等优点,成为许多企业在实现单点登录时的首选。

OIDC 还有广泛第三方服务提供商的支持,如支付宝、钉钉、微信、GitHub 等。例如下图中 Sealos 应用的登录页面,可以跳转 Github,微信和 Google 进行第三方登录,使用的就是 OIDC 身份认证:

Higress 网关作为后端服务所有请求的入口,可以集成 OIDC 实现统一认证服务,所有后端服务不需要各自实现用户认证逻辑,而是统一通过网关进行用户身份的验证。这样简化了系统架构,减少了重复工作,并提高了安全性。

用户在网关配置 OIDC 认证鉴权,可以实现对资源的细粒度访问控制。并且可以方便地对接自建的身份认证服务,或者社交媒体账号等其他第三方账户登录,增强了业务的便利性。

基于此,我们实现了 OIDC 插件让用户在 Higress 网关可以零代码实现 SSO 单点登录。

OIDC 插件使用

后端样例服务部署

参考 Istio Bookinfo [ 1] 样例在集群中部署后端样例服务,用来调试 OIDC 插件功能,部署好之后可以通过下面的命令验证是否部署成功。

kubectl exec "$(kubectl get pod -l app=ratings -o jsonpath='{.items[0].metadata.name}')" -c ratings -- curl -sS productpage:9080/productpage | grep -o "<title>.*</title>"

通过自建身份服务使用 OIDC 插件

配置示例

部署 keycloak 身份认证服务

参考 keycloak-getting-started-docker [ 2] 使用 docker 快速部署 keycloak 身份认证服务,添加用户并创建 client。

🔔 注:需填写 Valid redirect URIs,Valid post logout URIs,Web origins 配置项,否则 OIDC Provider 会认为用户跳转的重定向 URL 或登出 URL 无效。

Higress 服务配置

在 Higress 服务来源中创建 Keycloak 固定地址服务。

Wasm 插件配置

redirect_url: 'http://foo.bar.com/oauth2/callback'
oidc_issuer_url: 'http://127.0.0.1:9090/realms/myrealm'
client_id: 'XXXXXXXXXXXXXXXX'
client_secret: 'XXXXXXXXXXXXXXXX'
scope: 'openid email'
cookie_secret: 'nqavJrGvRmQxWwGNptLdyUVKcBNZ2b18Guc1n_8DCfY='
service_name: 'keycloak.static'
service_port: 80
service_host: '127.0.0.1:9090'

插件效果演示

访问服务页面,未登陆的话进行跳转。

登陆成功跳转到服务页面。

访问登出跳转到登出页面。

http://foo.bar.com/oauth2/sign_out?rd=http%3A%2F%2F127.0.0.1:9090%2Frealms%2Fmyrealm%2Fprotocol%2Fopenid-connect%2Flogout

访问登出跳转到登出页面(携带 post_logout_redirect_uri 参数跳转指定 uri)。

http://foo.bar.com/oauth2/sign_out?rd=http%3A%2F%2F127.0.0.1:9090%2Frealms%2Fmyrealm%2Fprotocol%2Fopenid-connect%2Flogout%3Fpost_logout_redirect_uri%3Dhttp%3A%2F%2Ffoo.bar.com%2Ffoo

通过第三方服务提供商使用 OIDC 插件

配置示例

配置阿里云 OAuth 应用

参考 Web 应用登录阿里云 [ 3] 流程配置 OAuth 应用。

Higress 服务配置

为了让插件能够访问到 OIDC 服务提供商,需要在 Higress 服务来源中创建 Aliyun DNS 服务。

插件参数配置


redirect_url: 'http://foo.bar.com/oauth2/callback'
provider: aliyun
oidc_issuer_url: 'https://oauth.aliyun.com/'
client_id: 'XXXXXXXXXXXXXXXX'
client_secret: 'XXXXXXXXXXXXXXXX'
scope: 'openid'
cookie_secret: 'nqavJrGvRmQxWwGNptLdyUVKcBNZ2b18Guc1n_8DCfY='
service_name: 'aliyun.dns'
service_port: 443

插件效果演示

访问服务页面,未登陆的话进行跳转。

扫码登陆成功跳转到服务页面。

访问登出跳转到登出页面(阿里云登出后会重定向到登录页)。

http://foo.bar.com/oauth2/sign_out?rd=https%3A%2F%2Faccount.aliyun.com%2Flogout%2Flogout.htm

OIDC 插件方案选型

Istio Sidecar 容器方案

Istio 社区提出了使用 Sidecar 容器部署外部授权 [ 4] ,例如 Istio OIDC Authentication with OAuth2-Proxy [ 5] 中提到的部署成熟的 oauth2-proxy 方案,但是这种方案的缺陷首先是在外部授权服务与数据面之间会多一层请求调用,导致性能上会差,其次是外部授权服务会占用一定的 CPU 资源和内存资源,并且如果用户的需要配置多个服务提供商,这个方案也需要部署多个外部授权,因此这个方案灵活性不够强。

Envoy Filter 方案

现有 Envoy 社区开发的 C++ 原生的 OAuth2 Filter [ 6] 也可以实现 OIDC 身份认证的功能,目前社区正在积极开发中,Envoy 社区的 envoy gateway [ 7] 项目使用了该方案,现有的问题是不支持 OIDC 协议标准的 state 参数(Issue 35232 [ 8] )导致受 CSRF 攻击威胁,并且不支持对 cookie 中的令牌进行加密(Issue 23508 [ 9] ),因此这个方案存在安全漏洞导致 OAuth2 Filter 无法在生产环境中使用。

Wasm 插件方案

开源的 Higress 项目插件开发框架 [ 10] 提供了多种编程语言包括 Rust,C++,Golang 和 AssemblyScript(TypeScript 的 Wasm 方言)等编写 Wasm 插件,相比于 C++ 的生态,Rust,Go,TypeScript 等语言的开源库生态更丰富,其中开源的实现了 OIDC 功能的项目如下:

  • Golang:oauth2-proxy [ 11]
  • Rust:oauth2-rs [ 12]
  • TypeScript:angular-oauth2-oidc [1****3]

其中 oauth2-proxy 项目在开源社区中得到了广泛的使用和验证,同时拥有最活跃的社区支持,发布频繁的更新和改进,实现了大部分常见的 OIDC 服务提供商,也是目前 Istio Sidecar 容器方案中推荐的。Wasm 插件方案的优势体现在以下三个方面:

  1. 生产可用性: OIDC 协议涉及身份认证,稳定性和安全性至关重要。基于成熟的开源项目二次开发的插件,通常具有更高的可靠性
  2. 可扩展性: 不同企业实现 OIDC 协议时不一定会完全遵循标准,企业用户可以基于开源的插件代码进行二次开发,实现企业定制化的需求。
  3. 安全性: 插件运行在严格的沙箱虚拟环境中,即使代码出现异常也不会使得 Envoy 崩溃。

因此基于以上优势并考虑到前两个方案的灵活性不够强和安全漏洞问题,选择开发 Wasm 插件实现 OIDC 功能。

OIDC 插件原理

OIDC 插件基于 oauth2-proxy 项目的核心流程实现,由于在 Envoy 插件中发起外部请求需要通过异步调用,因此将 oauth2-proxy 项目的主流程中的同步调用改为跟 Envoy 中外部服务的异步调用,在回调函数中对响应进行处理,具体的代码参考 Higress 中的 OIDC 插件 [ 14] ,OIDC 插件的请求响应流程如图所示。

  1. 模拟用户访问对应服务 api。
curl --url "foo.bar.com/headers"
  1. Higress 重定向到 OIDC Provider 登录页同时携带 client_id、response_type、scope 等 OIDC 认证的参数并设置 csrf cookie 防御 CSRF 攻击。
curl --url "https://dev-o43xb1mz7ya7ach4.us.auth0.com/authorize"\--url-query "approval_prompt=force" \--url-query "client_id=YagFqRD9tfNIaac5BamjhsSatjrAnsnZ" \--url-query "redirect_uri=http%3A%2F%2Ffoo.bar.com%2Foauth2%2Fcallback" \--url-query "response_type=code" \--url-query "scope=openid+email+offline_access" \--url-query "state=nT06xdCqn4IqemzBRV5hmO73U_hCjskrH_VupPqdcdw%3A%2Ffoo" \--header "Set-Cookie: _oauth2_proxy_csrf=LPruATEDgcdmelr8zScD_ObhsbP4zSzvcgmPlcNDcJpFJ0OvhxP2hFotsU-kZnYxd5KsIjzeIXGTOjf8TKcbTHbDIt-aQoZORXI_0id3qeY0Jt78223DPeJ1xBqa8VO0UiEOUFOR53FGxirJOdKFxaAvxDFb1Ok=|1718962455|V1QGWyjQ4hMNOQ4Jtf17HeQJdVqHdt5d65uraFduMIU=; Path=/; Expires=Fri, 21 Jun 2024 08:06:20 GMT; HttpOnly"
  1. 用户在登录页进行登录。

  1. 携带授权重定向到 Higress 并携带了 state 参数用于验证 CSRF Cookie,授权 code 用于交换 Token。
curl --url "http://foo.bar.com/oauth2/callback" \--url-query "state=nT06xdCqn4IqemzBRV5hmO73U_hCjskrH_VupPqdcdw%3A%2Ffoo" \--url-query "code=0bdopoS2c2lx95u7iO0OH9kY1TvaEdJHo4lB6CT2_qVFm"
  1. 利用授权交换 id_token 和 access_token。
curl -X POST \--url "https://dev-o43xb1mz7ya7ach4.us.auth0.com/oauth/token" \--data "grant_type=authorization_code" \--data "client_id=YagFqRD9tfNIaac5BamjhsSatjrAnsnZ" \--data "client_secret=ekqv5XoZuMFtYms1NszEqRx03qct6BPvGeJUeptNG4y09PrY16BKT9IWezTrrhJJ" \--data "redirect_uri=http%3A%2F%2Ffoo.bar.com%2Foauth2%2Fcallback" \--data "code=0bdopoS2c2lx95u7iO0OH9kY1TvaEdJHo4lB6CT2_qVFm" \

返回的请求里包含了 id_token,access_token,refresh_token 用于后续刷新 access_token。

{"access_token": "eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIiwiaXNzIjoiaHR0cHM6Ly9kZXYtbzQzeGIxbXo3eWE3YWNoNC51cy5hdXRoMC5jb20vIn0..WP_WRVM-y3fM1sN4.fAQqtKoKZNG9Wj0OhtrMgtsjTJ2J72M2klDRd9SvUKGbiYsZNPmIl_qJUf81D3VIjD59o9xrOOJIzXTgsfFVA2x15g-jBlNh68N7dyhXu9237Tbplweu1jA25IZDSnjitQ3pbf7xJVIfPnWcrzl6uT8G1EP-omFcl6AQprV2FoKFMCGFCgeafuttppKe1a8mpJDj7AFLPs-344tT9mvCWmI4DuoLFh0PiqMMJBByoijRSxcSdXLPxZng84j8JVF7H6mFa-dj-icP-KLy6yvzEaRKz_uwBzQCzgYK434LIpqw_PRuN3ClEsenwRgIsNdVjvKcoAysfoZhmRy9BQaE0I7qTohSBFNX6A.mgGGeeWgugfXcUcsX4T5dQ","refresh_token": "GrZ1f2JvzjAZQzSXmyr1ScWbv8aMFBvzAXHBUSiILcDEG","id_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Imc1Z1ExSF9ZbTY0WUlvVkQwSVpXTCJ9.eyJlbWFpbCI6IjE2MDExNTYyNjhAcXEuY29tIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJpc3MiOiJodHRwczovL2Rldi1vNDN4YjFtejd5YTdhY2g0LnVzLmF1dGgwLmNvbS8iLCJhdWQiOiJZYWdGcVJEOXRmTklhYWM1QmFtamhzU2F0anJBbnNuWiIsImlhdCI6MTcxOTE5ODYzOCwiZXhwIjoxNzE5MjM0NjM4LCJzdWIiOiJhdXRoMHw2NjVkNzFlNzRjMTMxMTc3YmU2NmU2MDciLCJzaWQiOiJjdDJVOF9ZUS16VDdFOGkwRTNNeUstejc5ZGlWUWhhVSJ9.gfzXKJ0FeqzYqOUDLQHWcUG19IOLqkpLN09xTmIat0umrlGV5VNSumgWH3XJmmwnhdb8AThH3Jf-7kbRJzu4rM-BbGbFTRBTzNHeUajFOFrIgld5VENQ_M_sXHkTp0psWKSr9vF24kmilCfSbvC5lBKjt878ljZ7-xteWuaUYOMUdcJb4DSv0-zjX01sonJxYamTlhji3M4TAW7VwhwqyZt8dBhVSNaRw1wUKj-M1JrBDLyx65sroZtSqVA0udIrqMHEbWYb2de7JjzlqG003HRMzwOm7OXgEd5ZVFqgmBLosgixOU5DJ4A26nlqK92Sp6VqDMRvA-3ym8W_m-wJ_A","scope": "openid email offline_access","expires_in": 86400,"token_type": "Bearer"
}
  1. 将获得的 id_token 和 access_token 加密存储在 Cookie _oauth2_proxy 中,用于后续用户登录状态的验证,同时清除 Cookie _oauth2_proxy_csrf。
"Set-Cookie": ["_oauth2_proxy_csrf=; Path=/; Expires=Mon, 24 Jun 2024 02:17:39 GMT; HttpOnly","_oauth2_proxy=8zM_Pcfpp_gesKFe4SMg08o5Iv0A8WAOQOmG1-vZBbQ56UggYVC0Cu-gFMEoxJZU5q1O5vqRlVBizlLetgVjRCksGVbttwl8tQ7h5YiyIubbbtvF1T4JzLh3QfzUUrwbB-VznOkh8qLbjAhddocecjBt4rMiDyceKXqMr4eO5TUEMx4vHtJYnTYalMeTYhGXk5MNSyrdZX9NnQnkdrCjiOQM13ggwob2nYwhGWaAlgzFSWkgkdtBy2Cl_YMWZ8_gKk9rDX289-JrJyGpr5k9O9RzRhZoY2iE3Mcr8-Q37RTji1Ga22QO-XkAcSaGqY1Qo7jLdmgZTYKC5JvtdLc4rj3vcbveYxU7R3Pt2vEribQjKTh4Sqb0aA03p4cxXyZN4SUfBW1NAOm4JLPUhKJy8frqC9_E0nVqPvpvnacaoQs8WkX2zp75xHoMa3SD6KZhQ5JUiPEiNkOaUsyafLvht6lLkNDhgzW3BP2czoe0DCDBLnsot0jH-qQpMZYkaGr-ZnRKI1OPl1vHls3mao5juOAW1VB2A9aughgc8SJ55IFZpMfFMdHdTDdMqPODkItX2PK44GX-pHeLxkOqrzp3GHtMInpL5QIQlTuux3erm3CG-ntlUE7JBtN2T9LEb8XfIFu58X9_vzMun4JQlje2Thi9_taI_z1DSaTtvNNb54wJfSPwYCCl4OsH-BacVmPQhH6TTZ6gP2Qsm5TR2o1U2D9fuVkSM-OPCG9l3tILambIQwC3vofMW6X8SIFSmhJUDvN7NbwxowBiZ6Y7GJRZlAk_GKDkpsdrdIvC67QqczZFphRVnm6qi-gPO41APCbcO6fgTwyOhbP3RrZZKWSIqWJYhNE3_Sfkf0565H7sC7Hc8XUUjJvP3WnjKS9x7KwzWa-dsUjV3-Q-VNl-rXTguVNAIirYK-qrMNMZGCRcJqcLnUF0V_J2lVmFyVsSlE3t0sDw2xmbkOwDptXFOjQL5Rb4esUMYdCBWFajBfvUtcZEFtYhD0kb6VcbjXO3NCVW5qKh_l9C9SRCc7TG1vcRAqUQlRXHacTGWfcWsuQkCJ3Mp_oWaDxs1GRDykQYxAn5sTICovThWEU2C6o75grWaNrkj5NU-0eHh3ryvxLmGLBOXZV9OQhtKShWmUgywSWMxOHOuZAqdAPULc8KheuGFjXYp-RnCbFYWePJmwzfQw89kSkj1KUZgMYwKEjSz62z2qc9KLczomv76ortQzvo4Hv9kaW6xVuQj5R5Oq6_WMBOqsmUMzcXpxCIOGjcdcZRBc0Fm09Uy9oV1PRqvAE4PGtfyrCaoqILBix8UIww63B07YGwzQ-hAXDysBK-Vca2x7GmGdXsNXXcTgu00bdsjtHZPDBBWGfL3g_rMAXr2vWyvK4CwNjcaPAmrlF3geHPwbIePT0hskBboX1v1bsuhzsai7rGM4r53pnb1ZEoTQDa1B-HyokFgo14XiwME0zE1ifpNzefjpkz1YY2krJlqfCydNwoKaTit4tD2yHlnxAeFF9iIrxzSKErNUFpmyLa7ge7V33vhEH-6k5oBTLE2Q2BrC6aAkLCcPwU9xv_SzBDQPRY0MEYv3kGF03Swo1crRbGh-aifYX9NiHDsmG6r1vAnx0MAOw2Jzuz2x6SSdfBrzlcoWBlrwiZzd9kAKq75n1Uy9uzZ8SRnkBrEZySHBwEbu196VklkRE0jqwC-e3wWNNuviSOfwkVeX-7QdOoO10yw9VK2sW52lFvIEf4chv_ta7bGfAZOWBjpktG6ZLD81SE6A88zpqG2SysSyNMp9hl-umG-5sFsjCn_c9E8bDvwkUOUVb9bNqhBDsZgR0BNPawiOZjmyfhzmwmWf-zgFzfFSV6BvOwNRi3sCOHTsWcuk9NBQ_YK8CpNkVl3WeIBSDfidimuC_QV9UWKs1GPk35ZRkM4zKtLY2JsBFWKaDy_P80TcOzcMBoP8gIBClXZ-WUqfE8s1yyc4jrq-qL1_wJ24ef1O9FktsbyZiDKXw2vnqsT8-g_hCeG-unrT1ZFscf8oNdqczARHX-K4vKH2k3uIqEx1M=|1719199056|2rsgdUIClHNEpxBLlHOVRYup6e4oKensQfljtmn4B80=; Path=/; Expires=Mon, 01 Jul 2024 03:17:36 GMT; HttpOnly"
]
  1. 携带 Authorization 的标头对应 access_token 访问对应 api。
curl --url "foo.bar.com/headers"--header "Authorization: Bearer eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIiwiaXNzIjoiaHR0cHM6Ly9kZXYtbzQzeGIxbXo3eWE3YWNoNC51cy5hdXRoMC5jb20vIn0..WP_WRVM-y3fM1sN4.fAQqtKoKZNG9Wj0OhtrMgtsjTJ2J72M2klDRd9SvUKGbiYsZNPmIl_qJUf81D3VIjD59o9xrOOJIzXTgsfFVA2x15g-jBlNh68N7dyhXu9237Tbplweu1jA25IZDSnjitQ3pbf7xJVIfPnWcrzl6uT8G1EP-omFcl6AQprV2FoKFMCGFCgeafuttppKe1a8mpJDj7AFLPs-344tT9mvCWmI4DuoLFh0PiqMMJBByoijRSxcSdXLPxZng84j8JVF7H6mFa-dj-icP-KLy6yvzEaRKz_uwBzQCzgYK434LIpqw_PRuN3ClEsenwRgIsNdVjvKcoAysfoZhmRy9BQaE0I7qTohSBFNX6A.mgGGeeWgugfXcUcsX4T5dQ"
  1. 后端服务根据 access_token 获取用户信息并返回对应的 Http 响应。
{"email": "******","email_verified": false,"iss": "https://dev-o43xb1mz7ya7ach4.us.auth0.com/","aud": "YagFqRD9tfNIaac5BamjhsSatjrAnsnZ","iat": 1719198638,"exp": 1719234638,"sub": "auth0|665d71e74c131177be66e607","sid": "ct2U8_YQ-zT7E8i0E3MyK-z79diVQhaU"
}

总结

本文对 Higress 中开源的 OIDC Wasm 插件进行了介绍,现在 Higress 项目中 Wasm 插件支持使用 Go、C++、Rust、AssemblyScript 等语言编写,后续会支持更多的编程语言,有着更低的开发门槛,同时 Wasm 插件运行在隔离的沙箱环境中,具有更高的安全性,而 Wasm 本身作为一种高性能的可移植二进制指令格式不断的有新的进展和技术革新,未来网关场景的更多功能均可以考虑在 Wasm 插件中实现。

本文中的 OIDC Wasm 插件已在 Higress 项目中开源:https://github.com/alibaba/higress/tree/main/plugins/wasm-go/extensions/oidc

欢迎大家在 github 社区提出宝贵的建议,或者在 Higress 社区交流群(钉钉群号:30735012403)里一起沟通。

相关链接:

[1] Istio Bookinfo

https://istio.io/latest/docs/examples/bookinfo/

[2] keycloak-getting-started-docker

https://www.keycloak.org/getting-started/getting-started-docker

[3] Web 应用登录阿里云

https://help.aliyun.com/zh/ram/user-guide/access-alibaba-cloud-apis-from-a-web-application

[4] 外部授权

https://istio.io/latest/zh/docs/tasks/security/authorization/authz-custom/

[5] Istio OIDC Authentication with OAuth2-Proxy

https://medium.com/@lucario/istio-external-oidc-authentication-with-oauth2-proxy-5de7cd00ef04

[6] OAuth2 Filter

https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/oauth2_filter

[7] envoy gateway

https://github.com/envoyproxy/gateway

[8] Issue 35232

https://github.com/envoyproxy/envoy/issues/35232

[9] Issue 23508

https://github.com/envoyproxy/envoy/issues/23508

[10] 开发框架

https://github.com/alibaba/higress/tree/main/plugins

[11] oauth2-proxy

https://github.com/oauth2-proxy/oauth2-proxy

[12] oauth2-rs

https://github.com/ramosbugs/oauth2-rs

[13] angular-oauth2-oidc

https://github.com/manfredsteyer/angular-oauth2-oidc

[14] OIDC 插件

https://github.com/alibaba/higress/tree/main/plugins/wasm-go/extensions/oidc

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在全连接层中进行批量数据并行执行

在全连接层中进行批量数据并行执行 在全连接网络中,为了增加并发性并减少权重的负载,可以同时处理一批图像(来自多个视频通道),如图11-31所示。图11-31 增加并发性并减少权重的负载,可以同时处理一批图像 11.2.6 特征缓存 在流处理中,对输入和结果使用双缓冲区。对于下一…

【整理】【Jinja2 模板】基础

Jinja2是基于python书写的模板引擎。 jinja2 必知必会 1、jinja2文件以.j2为后缀,也可以不写后缀。 2、jinja2中存在 三种定界符 注释:{{# #}}变量引用:{{ var }}逻辑表达:{% %}3、jinja2 逻辑控制 条件表达: {% if %}......{% endif %}案例:循环控制:案例:注意:

CatiaV6 3DE软件许可优化解决方案

CatiaV6 3DE软件介绍 3DEXPERIENCE 是一个业务和创新平台可助力组织机构实时、全面地了解其业务活动和生态系统。它在统一的协同环境中将人员、构思、数据和解决方案连接在一起,从初创企业到大型企业,使各类企业都能够以全新的方式进行创新、生产和贸易。您可以将该平台用作真…

CSDN免登录复制

一、 1.打开开发人员工具 2.找到对应元素 二、 1.打开开发人员工具,进入控制台2.输入doucument.designMode=on结果图:3.选中,打印输出PDF效果图:ps: 效果图:

如何快速求一个序列的gcd和lcm

背景: 教授在打某道关于序列gcd与lcm的题,但是看不懂题解,于是决定打表找规律;然而自己又懒得算数,于是写了个程序。 使用说明: 输入格式:n str a1 a2 ... an,\(n\) 为序列长度;str为操作种类,只有GCD和LCM;\(a\) 为序列,其中所有元素都必须是自然数。 如果输入不合…

WPF check key and modified key

private void Window_KeyDown(object sender, KeyEventArgs e) {if (e.Key == Key.A && e.KeyboardDevice.Modifiers == ModifierKeys.Control){MessageBox.Show($"You entered Key:{Key.A} and modifier:{ModifierKeys.Control}");} }

数业智能心大陆告诉你如何培养孩子的批判性思维?

现今的教育体系自小学起便强调培养孩子的批判性思维,这种能力被视为在复杂世界中生存和发展的关键。在当今信息爆炸的时代,它能让我们在海量信息中辨别真伪、深入思考并做出明智决策。如今,如数业智能心大陆产出的AI 心理咨询平台的出现为培养孩子批判性思维提供了新可能,其…

maven导入本地jar

引入lib下加载(加载过后打包,以后再次使用不用再次导入) 1、首先创建一个用于创建jar包的项目,并测试能否成功运行 2、将项目打包 3、在需要引入的项目中创建lib目录 并把刚才打包的jar复制进去 4、通过dependency引入jar包groupId、artifactId、version要与jar包保持一致…

基准测试

一:基准测试1: 单线程tps能达到300/s,预估50000/s需要多少线程=50000/3002:2000个线程并发或负载持续一段时间,系统没有任何问题3;可以确定200个并发不超过1s4:可以为后续作为性能指标。 基准点 1:基准负载:线程数+Ramp+永远,用监听器tps查看拐点(第一次上升,下划点),…

查看文件(或文件夹)被哪个进程使用【文件已在另一程序中打开】

原文链接:https://www.cnblogs.com/liushui-sky/p/8135292.html windows系统中当我们在删除某个文件或文件夹时有时会提示该文件有程序在使用不能被删除,这时相当惆怅。那么可以用这个方法来找到是哪个进程在占用该文件: 1:打开任务管理器选择“性能” 2:单击下部的“资…

windows环境下使用clion编译fortran

环境配置 1.安装minGW安装之后bin目录下存在gfortran.exe配置clion环境使用安装的minGW路径工具链使用配置的minGW其他不变cmake文件编写配置完毕可能问题 没有安装minGW使用的VSstudiode

MongoDB 3种高可用架构全面剖析

大纲MongoDB 背景 高可用架构Master-Slave 模式 Replica Set 副本集模式 Sharding 模式推荐使用姿势使用姿势一:怎么保证高可用? 使用姿势二:怎么保证数据的高可靠? 使用姿势三:怎么保证数据的强一致性?总结 后记MongoDB 背景MongoDB 是一款功能完善的分布式文档数据库,…