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

news2024/11/15 20:53:05

作者:戴靖泽,阿里云 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.coloradmin.cn/o/2110882.html

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

相关文章

2024最新!Facebook手机版和网页版改名教程!

Facebook作为全球最大的社交平台之一&#xff0c;允许用户自定义名字和昵称。在Facebook更新姓名可以帮助您更好的展现账号形象。本文将为您提供详细的步骤指导&#xff0c;帮助您在手机APP和网页版上轻松完成Facebook改名操作。 Facebook手机版改名 打开Facebook APP并登录账号…

区块链ARC如何能让节点能够大规模处理交易数据

​​发表时间&#xff1a;2024年8月7日 TAAL技术主管Michael Bckli表示&#xff0c;TAAL公司一直在对ARC进行测试&#xff0c;并准备在今年年底全面发布。因TAAL在区块链交易处理方面具备深厚的专业知识&#xff0c;BSV区块链委托TAAL进行ARC开源参考落地方案的开发。 ARC是一个…

魔珐科技受邀参与外滩大会:以3D数字人AIGC产品赋能大资管行业,重塑金融服务边界

在人工智能浪潮的推动下&#xff0c;金融行业正经历着前所未有的场景革命。2024年Inclusion外滩大会作为行业交流的盛会&#xff0c;汇聚了众多学者、专家及企业领袖&#xff0c;共同探讨AI技术在多领域的深度应用&#xff0c;特别是其在金融行业中的革新潜力。 在外滩大会上&…

在桌面商业分析应用程序中启用高级 Web UI

挑战 Mercur Business Control 应用程序在企业界&#xff0c;尤其是金融领域&#xff0c;拥有悠久的应用历史。它帮助企业处理、可视化和分析海量数据&#xff0c;从而做出明智的商业决策。 随着产品的不断演进和现代化&#xff0c;Mercur Solutions AB 为该应用创建了 Web 客…

使用RestTemplate获取国内大盘股票数据的基本信息并存入数据库中

目录 使用RestTemplate获取国内大盘股票数据的基本信息并存入数据库中 第一步&#xff1a;导入RestTemplate依赖&#xff0c;并配置RestTemplate让其加入到SpringIoC容器中 第二步&#xff1a;在yml文件定义股票的相关参数 第三步&#xff1a;向新浪网发送请求&#xff0c;获…

FP7195:非同步升压恒流LED区动IC

前言&#xff1a;LED驱动芯片是什么&#xff1f; LED驱动芯片是一种能够将电源的电压和电流转换为适合LED&#xff08;发光二极管&#xff09;使用的电压和电流的芯片。这种芯片的主要作用是控制LED的亮度和电流&#xff0c;从而保证LED的正常工作和长寿命。简单来说&#xff…

【C++二分查找】1802. 有界数组中指定下标处的最大值

本文涉及的基础知识点 C二分查找 LeetCode 1802. 有界数组中指定下标处的最大值 给你三个正整数 n、index 和 maxSum 。你需要构造一个同时满足下述所有条件的数组 nums&#xff08;下标 从 0 开始 计数&#xff09;&#xff1a; nums.length n nums[i] 是 正整数 &#xf…

Vue组件:使用$emit()方法监听子组件事件

1、监听自定义事件 父组件通过使用 Prop 为子组件传递数据&#xff0c;但如果子组件要把数据传递回去&#xff0c;就需要使用自定义事件来实现。父组件可以通过 v-on 指令&#xff08;简写形式“”&#xff09;监听子组件实例的自定义事件&#xff0c;而子组件可以通过调用内建…

Ollama Qwen2 支持 Function Calling

默认 Ollama 中的 Qwen2 模型不支持 Function Calling&#xff0c;使用默认 Qwen2&#xff0c;Ollama 会报错。本文将根据官方模板对 ChatTemplate 进行改进&#xff0c;使得Qwen2 支持 Tools&#xff0c;支持函数调用。 Ollama 会检查对话模板中是否存在 Tools&#xff0c;如…

wlanapi.dll丢失怎么办?有没有什么靠谱的修复wlanapi.dll方法

在遇到各种系统文件错误当中&#xff0c;其中之一就是“wlanapi.dll文件丢失”的问题。这种问题通常发生在Windows操作系统上&#xff0c;特别是当系统试图执行与无线网络相关的任务时。wlanapi.dll是一个重要的系统文件&#xff0c;它负责处理Windows无线网络服务的许多功能。…

一种非接触式智能垃圾桶设计(论文+源码+实物)

1系统方案设计 通过对需求展开分析&#xff0c;本设计非接触式智能垃圾桶采用STM32F103单片机作为控制器&#xff0c;通过红外传感器实现垃圾桶的满溢检测&#xff0c;通过三个SG90舵机分别控制可回收、不可回收、其他垃圾桶盖的开关&#xff0c;并通过WiFi通信模块将数据信息…

Windows编译Hikari-LLVM15[llvm-18.1.8rel]并集成到Android Studio NDK

Windows编译Hikari-LLVM15[llvm-18.1.8rel]并集成到Android Studio NDK 工具1、w64devkit2、ndk3、cmake 编译1、准备工作2、开始编译 集成1、替换文件2、使用 工具 1、w64devkit w64devkit 解压出来给个环境变量 验证一下 2、ndk 通过android studio安装 ndk\27.1.1229…

PaddleOCR基础入门

1、下载paddle源码 https://github.com/PaddlePaddle/PaddleOCR2、新建conda虚拟环境 conda create --name paddleocr_env python3.103、激活conda虚拟环境 conda activate paddleocr_env4、解压paddleOCR并进入ocr目录&#xff0c;运行安装所需库&#xff1a; pip install…

包拯断案 | 数据库从库GTID在变化 为何没有数据写入@还故障一个真相

提问&#xff1a;作为DBA运维的你是否遇到过这些烦恼 1、数据库从库复制链路如何正确配置表过滤信息&#xff1f; 2、数据库从库的GTID在变化&#xff0c;实际却没有数据写入&#xff0c;究竟是什么原因&#xff1f; 心中有章&#xff0c;遇事不慌 作为DBA的你&#xff0c;…

KCP实现原理探析

KCP 是一个轻量级的、高效的、面向 UDP 的传输协议库&#xff0c;专为需要低延迟和高可靠性的实时应用设计。本文针对 KCP 的主要机制和实现与原理进行分析。 1. 术语 术语 全称 说明 TCP Transmission Control Protocol 传输控制协议 RTT Round Trip Time 往返时延 …

SQL Server导入导出

SQL Server导入导出 导出导入 这里已经安装好了SQL Server&#xff0c;也已经创建了数据库和表。现在想导出来给别人使用&#xff0c;所以需要导入导出功能。环境&#xff1a;SQL Server 2012 SP4 如果没有安装&#xff0c;可以查看安装教程&#xff1a; Microsoft SQL Server …

远程控制不止向日葵,这四款工具千万别错过!

不管是什么职业&#xff0c;总有些朋友会需要远程控制电脑&#xff0c;无论是从家里连接到办公室的机器&#xff0c;还是在出差时需要紧急访问我的开发环境。今天&#xff0c;我想和大家分享一下我使用过的几款远程控制软件它们在实际使用中的表现如何。 一、向日葵 网址&…

Arcgis字段计算器:随机生成规定范围内的数字

选择字段计算器在显示的字段计算器对话框内&#xff0c;解析程序选择Python&#xff0c;勾选上显示代码块&#xff0c; 半部分输入&#xff1a; import random; 可修改下半部分输入&#xff1a; random.randrange(3, 28) 表示生成3-28之间的随机数 字段计算器设置点击确定…

【springboot】使用缓存

目录 1. 添加依赖 2. 配置缓存 3. 使用EnableCaching注解开启缓存 4. 使用注解 1. 配置缓存名称 2. 配置缓存的键 3. 移除缓存 5. 运行结果 1. 添加依赖 <!-- springboot缓存--><dependency><groupId>org.springframework.boot</groupId>…

前端发送邮件至指定邮箱的方式方法有哪些?

前端发送邮件的教程指南&#xff1f;前端静态页面怎么发送邮件&#xff1f; 无论是用户反馈、订阅通知还是其他形式的通信&#xff0c;前端发送邮件的功能都显得尤为重要。AokSend将详细介绍几种常见的前端发送邮件的方法&#xff0c;帮助开发者更好地实现这一功能。 前端发送…