【分布式技术专题】「单点登录技术架构」一文带领你好好对接对应的Okta单点登录实现接口服务的实现落地

news2025/1/19 11:19:02

什么是SAML协议

SAML(Security Assertion Markup Language)是一种基于XML的标准,用于在不同的安全域之间传递身份验证和授权数据。SAML2.0是SAML协议的最新版本,它提供了一种标准的方式来实现单点登录(SSO)和跨域身份验证(Cross-Domain Authentication)。

在这里插入图片描述

SAML2.0协议定义了三种角色:身份提供者(Identity Provider,IdP)服务提供者(Service Provider,SP)用户(User) 。其中,身份提供者 是负责认证用户身份的系统,服务提供者是提供服务的系统,用户是需要访问服务的个体。

SAML 2.0协议的流程

在这里插入图片描述

  1. 用户向服务提供者发起请求,服务提供者检查用户是否已经登录。

  2. 如果用户没有登录,则服务提供者将用户重定向到身份提供者。

  3. 身份提供者验证用户身份,并生成一个SAML响应,其中包含用户的身份信息和授权信息。

  4. 身份提供者将SAML响应发送给服务提供者。

  5. 服务提供者验证SAML响应的签名,并提取用户的身份信息和授权信息。

  6. 服务提供者使用用户的身份信息和授权信息来授权用户访问服务。

SAML2.0协议的优点

SAML 2.0协议的优点在于它提供了一种标准的方式来实现跨域身份验证和单点登录,从而简化了用户的登录流程,提高了用户体验。此外,SAML 2.0协议还提供了强大的安全性和灵活性,可以满足各种不同的安全需求。

SAML2.0协议的特点

  • 可用性:从门户或Intranet的一键式访问,深层链接,消除密码和自动续订会话,使用户的生活更轻松。
  • 安全性:SAML基于强大的数字签名进行身份验证和完整性,是世界上最大,最具安全意识的企业所依赖的安全单点登录协议。(网页仿冒防范-如果您没有应用程序密码,就不会被欺骗在虚假的登录页面上输入密码
  • 速度:SAML速度很快。

总之,SAML 2.0协议是一种重要的安全标准,它可以帮助企业实现跨域身份验证和单点登录,提高用户体验和安全性。

SAML开发实战指南

建立SAML协议的SP服务提供者-服务

首先,我们需要先建立出来一个具有支持SAML协议的认证的SP(服务提供者)。使用Java工具包使我们可以将Java应用程序转换为可以连接到IdP(身份提供者)的SP(服务提供者)

SP需要支持功能和特性:

  • SSO(单点登录)和SLO(单点登出)
    • SSO:由SP发起
    • SLO:由IdP发起
  • 解析和分析断言Assert和nameId加密
  • 断言签名:signature
  • 消息签名:AuthNRequest, LogoutRequest, LogoutResponses.
  • 配置断言Assert消费者服务(ACS) 端点.
  • 配置单点登出服务(SLS) 端点.
  • 发布SP metadata(可以签名)

建立SAML协议的IDP服务

我们使用oneLogin提供的IDP服务来进行开发测试SAML协议,该服务需要注册开发者账户后获取。下面将介绍如何搭建。

https://developers.onelogin.com/

在这里插入图片描述

当然你也可以通过其他第三方的IDP进行实现也可,例如Okta或者Azure服务都可以,此处暂时不做过多的赘余豁免。


开始对接实现SP服务提供者

Maven引入方式

<dependency>
    <groupId>com.onelogin</groupId>
    <artifactId>java-saml</artifactId>
    <version>2.5.0</version>
</dependency>

采用OneLogin实现Saml协议认证开发

配置对应的IDP身份的相关参数

默认需要在OneLogin的配置文件onelogin.saml.properties中配置(IDP)身份提供者参数:

SSO的标记属性Settings的配置属性
Issuer URLonelogin.saml2.idp.entityid
SAML 2.0 Endpoint (HTTP)onelogin.saml2.idp.single_sign_on_service.url
SLO Endpoint (HTTP)onelogin.saml2.idp.single_logout_service.url
X.509 Certificate > View Detailsonelogin.saml2.idp.x509cert

主要面向的就是配置onelogin.saml.properties的“ idp”(身份提供者,以onelogin.saml2.idp开头的参数)部分。

配置对应的SP身份的相关参数

在OneLogin中定义(SP)服务提供商的参数

SSO的标记属性Settings的配置属性
Audienceonelogin.saml2.sp.entityid
Single Logout URLonelogin.saml2.sp.single_logout_service.url
Recipientonelogin.saml2.sp.assertion_consumer_service.url
ACS (Consumer) URLonelogin.saml2.sp.assertion_consumer_service.url
RelayState参数可以不用填写 在发起sso代码处可以指定

IDP端的配置可以实时修改保存(在 正式项目环境中我们通常 用metadata文件来进行配置交互)

部署运行SP项目

对于onelogin.saml2.sp.nameid格式,将unspecified更改为emailAddress.在正式项目中根据实际情况来进行配置,这里是目前是OneLogin使用的值。

onelogin.saml2.sp.entityid = http://localhost:8080/metadata.jsp
onelogin.saml2.sp.assertion_consumer_service.url = http://localhost:8080/acs.jsp
onelogin.saml2.sp.single_logout_service.url = http://localhost:8000/sls.jsp

保存配置后进入onelogin连接器的配置选项卡,然后将值从onelogin.saml.properties复制到``配置’’选项卡字段中,如下所示。

onelogin.saml.properties配置文件解读

SP端配置
# 协议配置 基本上默认 没有特殊修改

# SP entityId
#  Identifier of the SP entity  (must be a URI)
onelogin.saml2.sp.entityid = http://localhost:8080/metadata.jsp

# SP 断言解析服务地址
# Specifies info about where and how the <AuthnResponse> message MUST be
#  returned to the requester, in this case our SP.
# URL Location where the <Response> from the IdP will be returned
onelogin.saml2.sp.assertion_consumer_service.url = http://localhost:8080/acs.jsp

# SAML protocol binding to be used when returning the <Response>
# message.  Onelogin Toolkit supports for this endpoint the
# HTTP-POST binding only
onelogin.saml2.sp.assertion_consumer_service.binding = urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST

#单点登出 服务地址 主要是提供给 IDP端用于接收登出响应的
# Specifies info about where and how the <Logout Response> message MUST be
# returned to the requester, in this case our SP.
onelogin.saml2.sp.single_logout_service.url = http://localhost:8080/sls.jsp

# SAML protocol binding to be used when returning the <LogoutResponse> or sending the <LogoutRequest>
# message.  Onelogin Toolkit supports for this endpoint the
# HTTP-Redirect binding only
onelogin.saml2.sp.single_logout_service.binding = urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect

# nameID 格式 一般使用 unspecified 默认参数 
# Specifies constraints on the name identifier to be used to
# represent the requested subject.
# Take a look on lib/Saml2/Constants.php to see the NameIdFormat supported
onelogin.saml2.sp.nameidformat = urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress


# sp端用于报文加密签名使用到的证书
# 这里我们可以自签的x509格式证书 也可以使用pem格式通过 以下方式转换(我使用的是https证书 other下载而来的)
# 公钥转换 openssl x509 -in x509cert.pem -text -out Cert.pem
# 私钥转换 openssl pkcs8 -topk8 -inform pem -nocrypt -in sp.rsa_key -outform pem -out sp.pem
# 证书粘贴注意不要前后注释 并保持在一行上 证书解析对空格换行符敏感

# Usually x509cert and privateKey of the SP are provided by files placed at
# the certs folder. But we can also provide them with the following parameters
onelogin.saml2.sp.x509cert =

# Requires Format PKCS#8   BEGIN PRIVATE KEY	     
# If you have     PKCS#1    convert it by   openssl pkcs8 -topk8 -inform pem -nocrypt -in sp.rsa_key -outform pem -out sp.pem
onelogin.saml2.sp.privatekey =

IDP端配置


# IDP  entityId
# Identifier of the IdP entity  (must be a URI)
onelogin.saml2.idp.entityid = https://app.onelogin.com/saml/metadata/2edb5038-be70-40f5-ad3b-2de9d00ab1a3

# SSO endpoint info of the IdP. (Authentication Request protocol)
# URL Target of the IdP where the SP will send the Authentication Request Message
onelogin.saml2.idp.single_sign_on_service.url = https://westinfosoft-dev.onelogin.com/trust/saml2/http-post/sso/2edb5038-be70-40f5-ad3b-2de9d00ab1a3
# SAML protocol binding to be used when returning the <Response>
# message.  Onelogin Toolkit supports for this endpoint the
# HTTP-Redirect binding only
onelogin.saml2.idp.single_sign_on_service.binding = urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect

# SLO endpoint info of the IdP.
# URL Location of the IdP where the SP will send the SLO Request
onelogin.saml2.idp.single_logout_service.url =https://westinfosoft-dev.onelogin.com/trust/saml2/http-redirect/slo/1095020

# Optional SLO Response endpoint info of the IdP.
# URL Location of the IdP where the SP will send the SLO Response. If left blank, same URL as onelogin.saml2.idp.single_logout_service.url will be used.
# Some IdPs use a separate URL for sending a logout request and response, use this property to set the separate response url
onelogin.saml2.idp.single_logout_service.response.url =

# SAML protocol binding to be used when returning the <Response>
# message.  Onelogin Toolkit supports for this endpoint the
# HTTP-Redirect binding only
onelogin.saml2.idp.single_logout_service.binding = urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect

# 正式项目中 sp端都是从SP_metadata 中获取 的
# Public x509 certificate of the IdP
onelogin.saml2.idp.x509cert =

# 以下是 指纹模式的配置 不过官方不建议使用 应为hash碰撞的问题 
# Instead of use the whole x509cert you can use a fingerprint
# (openssl x509 -noout -fingerprint -in "idp.crt" to generate it,
# or add for example the -sha256 , -sha384 or -sha512 parameter)
#
# If a fingerprint is provided, then the certFingerprintAlgorithm is required in order to
# let the toolkit know which Algorithm was used. Possible values: sha1, sha256, sha384 or sha512
# 'sha1' is the default value.
# onelogin.saml2.idp.certfingerprint = 3E:3B:0D:FA:F2:80:B2:0E:95:46:36:07:9A:78:BD:04:CC:76:CE:A8
# onelogin.saml2.idp.certfingerprint_algorithm = sha1

# Security settings

#安全配置 在演示项目中使用不多 不过在正式环境中 需要注意开启对应的加密项

# Indicates that the nameID of the <samlp:logoutRequest> sent by this SP
# will be encrypted.
onelogin.saml2.security.nameid_encrypted = false

#认证请求的加密
# Indicates whether the <samlp:AuthnRequest> messages sent by this SP
# will be signed.              [The Metadata of the SP will offer this info]
onelogin.saml2.security.authnrequest_signed = false

#登出请求的加密
# Indicates whether the <samlp:logoutRequest> messages sent by this SP
# will be signed.
onelogin.saml2.security.logoutrequest_signed = false

#登出响应的加密
# Indicates whether the <samlp:logoutResponse> messages sent by this SP
# will be signed.
onelogin.saml2.security.logoutresponse_signed = false

# Indicates a requirement for the <samlp:Response>, <samlp:LogoutRequest> and
# <samlp:LogoutResponse> elements received by this SP to be signed.
onelogin.saml2.security.want_messages_signed = false

# Indicates a requirement for the <saml:Assertion> elements received by this SP to be signed.
onelogin.saml2.security.want_assertions_signed = false

# Indicates a requirement for the Metadata of this SP to be signed.
# Right now supported null (in order to not sign) or true (sign using SP private key) 
onelogin.saml2.security.sign_metadata =

# Indicates a requirement for the Assertions received by this SP to be encrypted
onelogin.saml2.security.want_assertions_encrypted = false

# Indicates a requirement for the NameID received by this SP to be encrypted
onelogin.saml2.security.want_nameid_encrypted = false

# Authentication context.
# Set Empty and no AuthContext will be sent in the AuthNRequest
# You can set multiple values (comma separated them)
onelogin.saml2.security.requested_authncontext = urn:oasis:names:tc:SAML:2.0:ac:classes:Password

# Allows the authn comparison parameter to be set, defaults to 'exact'
onelogin.saml2.security.onelogin.saml2.security.requested_authncontextcomparison = exact

SP端代码

keyStores

Auth构造函数支持从KeyStore读取SP公共证书/私钥的功能。必须为KeyStoreSettings对象提供KeyStore,别名和KeyEntry密码。

String keyStoreFile = "oneloginTestKeystore.jks";
String alias = "keywithpassword";
String storePass = "changeit";
String keyPassword = "keypassword";
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(new FileInputStream(keyStoreFile), storePass.toCharArray());
KeyStoreSettings keyStoreSettings =  new keyStoreSettings(ks, alias, keyPassword);
Auth auth = new Auth(KeyStoreSettings keyStoreSetting);
动态配置

您可以从其他来源(例如文件,数据库或生成的值)加载值。SettingsBuilder类公开了fromValues(Map <String,Object> samlData)方法,该方法可让您动态构建设置,密钥字符串与属性文件中的相同。

Map<String, Object> samlData = new HashMap<>();
samlData.put("onelogin.saml2.sp.entityid", "http://localhost:8080/java-saml-tookit-jspsample/metadata.jsp");
samlData.put("onelogin.saml2.sp.assertion_consumer_service.url", new URL("http://localhost:8080/java-saml-tookit-jspsample/acs.jsp"));
samlData.put("onelogin.saml2.security.want_xml_validation",true);
samlData.put("onelogin.saml2.sp.x509cert", myX509CertInstance);
SettingsBuilder builder = new SettingsBuilder();
Saml2Settings settings = builder.fromValues(samlData).build();
//实例化您编写的Auth类
Auth auth = new Auth(settings, request, response);

发起单点登录

用于向IDP发送AuthNRequest

Auth auth = new Auth(request, response);
auth.login();

AuthNRequest将根据安全设置“ onelogin.saml2.security.authnrequest_signed”以签名或未签名的形式发送。然后,IdP将把SAML响应返回给用户的客户端。然后,使用此信息将客户端转发到SP的属性消费者服务。我们可以为登录函数设置一个“ returnTo” URL参数,并将其转换为“ RelayState”参数:

//指定登录成功后跳转的地址
String targetUrl = "https://github.com/onelogin/java-saml";
auth.login(targetUrl);

SP 端点

三个重要的端点,sp元数据(SP_metadata),ACS(断言解析服务),SLS(单点登出响应解析服务)

SP Metadata

这段代码将根据设置文件中提供的信息提供SP的XML元数据文件。

Auth auth = new Auth();
Saml2Settings settings = auth.getSettings();
String metadata = settings.getSPMetadata();
List<String> errors = Saml2Settings.validateMetadata(metadata);
if (errors.isEmpty()) {
   out.println(metadata);
} else {
   response.setContentType("text/html; charset=UTF-8");
   for (String error : errors) {
       out.println("<p>"+error+"</p>");
   }
}

Attribute Consumer Service(ACS)

此代码处理IdP通过用户客户端转发到SP的SAML响应。

Auth auth = new Auth(request, response);
//具体的 响应断言解析
auth.processResponse();
if (!auth.isAuthenticated()) {
   out.println("Not authenticated");
}

List<String> errors = auth.getErrors();
if (!errors.isEmpty()) {
    out.println(StringUtils.join(errors, ", "));
    if (auth.isDebugActive()) {
        String errorReason = auth.getLastErrorReason();
        if (errorReason != null && !errorReason.isEmpty()) {
            out.println(auth.getLastErrorReason());
        }
    }
} else {
    Map<String, List<String>> attributes = auth.getAttributes();
    String nameId = auth.getNameId();
    String nameIdFormat = auth.getNameIdFormat();
    String sessionIndex = auth.getSessionIndex();
    String nameidNameQualifier = auth.getNameIdNameQualifier();
    String nameidSPNameQualifier = auth.getNameIdSPNameQualifier();

    //关键参数
    session.setAttribute("attributes", attributes);
    session.setAttribute("nameId", nameId);
    session.setAttribute("nameIdFormat", nameIdFormat);
    session.setAttribute("sessionIndex", sessionIndex);
    
    session.setAttribute("nameidNameQualifier", nameidNameQualifier);
    session.setAttribute("nameidSPNameQualifier", nameidSPNameQualifier);

    String relayState = request.getParameter("RelayState");

    if (relayState != null && relayState != ServletUtils.getSelfRoutedURLNoQuery(request)) {
        response.sendRedirect(request.getParameter("RelayState"));
    } else {
        if (attributes.isEmpty()) {
            out.println("You don't have any attributes");
        }
       else {
            Collection<String> keys = attributes.keySet();
            for(String name :keys){
                out.println(name);
                List<String> values = attributes.get(name);
                for(String value :values) {
                    out.println(" - " + value);
                }
            }
        }
    }
}

在尝试获取属性之前,请检查用户是否已通过身份验证。如果用户未通过身份验证,则将返回一个空的Map。例如,如果我们在auth.processResponse之前调用getAttributes,则getAttributes()将返回一个空Map。

Single Logout Service (SLS)

以下代码处理注销请求和注销响应。

Auth auth = new Auth(request, response);
auth.processSLO();
List<String> errors = auth.getErrors();
if (errors.isEmpty()) {
   out.println("Sucessfully logged out");
} else {
   for(String error : errors) {
      out.println(error);
   }
}

如果SLS端点收到注销响应,则该响应将得到验证,并且HttpRequest的会话可能会关闭。如果SLS端点接收到注销请求,则该请求将得到验证,会话将关闭,并且注销响应将发送到IdP的SLS端点。如果我们不希望该processSLO破坏会话,则将keepLo​​calSession参数作为true传递给processSLO方法。

2.发起单点登出

用于发送Logout Request到IdP

注意:此方式 是通过SP端发起的单点登出

Auth auth = new Auth(request, response);
String nameId = null;
if (session.getAttribute("nameId") != null) {
    nameId = session.getAttribute("nameId").toString();
}
String nameIdFormat = null;
if (session.getAttribute("nameIdFormat") != null) {
    nameIdFormat = session.getAttribute("nameIdFormat").toString();
}
String nameidNameQualifier = null;
if (session.getAttribute("nameidNameQualifier") != null) {
    nameIdFormat = session.getAttribute("nameidNameQualifier").toString();
}
String nameidSPNameQualifier = null;
if (session.getAttribute("nameidSPNameQualifier") != null) {
    nameidSPNameQualifier = session.getAttribute("nameidSPNameQualifier").toString();
}
String sessionIndex = null;
if (session.getAttribute("sessionIndex") != null) {
    sessionIndex = session.getAttribute("sessionIndex").toString();
}
auth.logout(null, nameId, sessionIndex, nameIdFormat);

将根据安全设置“ onelogin.saml2.security.logoutrequest_signed”以签名或未签名的形式发送注销请求。IdP将通过用户客户端将注销响应返回到SP的单一注销服务。

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

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

相关文章

1.数据结构---时间复杂度+面试题:消失的数字

文章目录前言1.什么是数据结构?2.什么是算法?3.时间复杂度3.1 实例1:请计算一下Func1中count语句总共执行了多少次&#xff1f;大O的渐进表示法实例2:计算Func2的时间复杂度实例3:计算Func3的时间复杂度&#xff1f;实例4:计算Func4的时间复杂度&#xff1f;大O的渐进表示法总…

Activiti7原生整合和工作流相关概念详解

一、概述 Activiti是一个工作流引擎&#xff0c; Activiti可以将业务系统中复杂的业务流程抽取出来&#xff0c;并用专门的建模语言BPMN2.0进行定义&#xff0c;业务流程按照预先定义的流程进行执行&#xff0c;实现了系统的流程由Activiti进行管理&#xff0c;减少业务系统由…

C++ vasprintf

vasprintf 是一个 C 库函数&#xff0c;它可以通过可变参数创建一个格式化的字符串&#xff0c;并将其存储在动态分配的内存中。它的使用方法与 printf 类似&#xff0c;但它不会将结果打印到标准输出流中&#xff0c;而是将其存储在一个指向字符数组的指针中。 以下是 vasprin…

RFID技术在供应链管理中的应用

RFID是无线射频识别技术的简称&#xff0c;广泛应用于物流、制造、供应链等领域。在供应链管理中&#xff0c;RFID技术可以提供更加精确、实时的信息&#xff0c;帮助企业减少损耗和时间成本&#xff0c;提高效率和可靠性。本文将介绍RFID技术在供应链管理中的应用及其优势。 …

6.redis-集群

01-集群cluster 存在的问题 redis提供的服务OPS(operation per second)可以达到10万/秒&#xff0c;当前业务OPS如果超过10万/秒&#xff0c;怎么办&#xff1f; redis集群 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gITgqXr9-1681709270830)(n…

Nginx学习笔记 - 新

跟着 https://www.bilibili.com/video/BV1yS4y1N76R 视频学的 安装教程 nginx环境搭建 通过不同域名相同端口访问不同页面 首先添加hosts&#xff0c;映射下域名到装nginx的主机IP地址&#xff0c;我这里是虚拟机&#xff0c;且没有买域名就自己本地这样玩 进入nginx安装目…

【C语言学习3——基本的C语言语法知识1】

C语言学习3——基本的C语言语法知识主函数什么是主函数&#xff1f;写一个自己的函数主函数是整个C语言程序的入口要调用函数&#xff0c;必须先知道函数什么是变量&#xff1f;#include <stdio.h> int main() { printf("Hello World\n"); return 0; }相信你已…

科研人的R速成利器,读这两本就够了!

R 是数据科学领域的一门大热的编程语言&#xff0c;可以说它是专门为统计分析而生的。 相比起其他语言&#xff0c;R 简单易学&#xff0c;代码可读性强&#xff0c;并且不需要搭建复杂的编程环境&#xff0c;对初学者非常友好。 今天就和大家分享两本学习R的宝藏图书&#x…

【FPGA实验4】举重比赛机制

举重比赛有三名裁判&#xff0c;当运动员将杠铃举起后&#xff0c;须有两名或两名以上裁判认可&#xff0c;方可判定试举成功&#xff0c;若用A、B、C分别代表三名裁判的意见输入&#xff0c;同意为1&#xff0c;否定为0;F为裁判结果输出&#xff0c;试举成功时F1&#xff0c;试…

02-神经网络基础

一、从机器学习到神经网络 1. 两层神经网络 - 多层感知机 2. 浅层神经网络特点 (1)需要数据量小、训练速度快; (2)对复杂函数的表示能力有限,泛化能力受到制约。 Kurt Hornik 证明了理论上两层神经网络足以拟合任意函数,而且过去没有足够的数据和计算能力,因此之前的…

计算机组成原理实验1---运算器 预习报告

本实验为哈尔滨工业大学计算机组成原理实验&#xff0c;实验内容均为个人完成&#xff0c;目的是分享交流&#xff0c;如有抄袭将追究责任&#xff0c;笔者能力有限&#xff0c;若因此影响读者的分数&#xff0c;本人深表抱歉。 一、 实验目的 了解运算器的组成结构基于数据通…

ChatGPT 究竟在做什么?它为何能做到这些?(2)

机器学习和神经网络的训练 到目前为止&#xff0c;我们一直在讨论那些 “已经知道” 如何完成特定任务的神经网络。但是&#xff0c;神经网络之所以如此有用&#xff08;估计也是在大脑中&#xff09;&#xff0c;是因为它们不仅是可以完成各种任务&#xff0c;而且可以逐步 “…

数据 数据元素 数据项 数据对象

文章目录数据、数据元素、数据项和数据对象数据数据元素数据对象数据元素和数据对象数据结构数据结构包括以下三个方面的内容逻辑结构物理结构&#xff08;存储结构&#xff09;逻辑结构与存储结构的关系逻辑结构的种类集合结构线性结构树型结构图状结构或网状结构四种基本的存…

【人工智能】模糊推理

模糊推理:以下内容都是我自学理解的&#xff0c;不保证对引言&#xff1a;“生活中的模糊关系”模糊集合模糊集合的定义模糊集合的表示法模糊集合表示法示例隶属函数模糊规则模糊计算的流程引言&#xff1a;“生活中的模糊关系” 如果说&#xff0c;我们简单的将 温度<10度 …

如何构建敏捷项目管理团队?

敏捷专家认为&#xff1a;团队合作对于交付出色软件来说非常关键&#xff0c;而在优秀的敏捷团队普遍都是站在集体的角度去思考和工作&#xff0c;而不是以个体的形式。对每个成员来说更有价值的是——优秀的成员都会站在团队的角度将自己宝贵的开发经验分享出来&#xff0c;来…

mysql(beetlsql框架)适配人大金仓(KingBase)有感

毁灭吧&#xff0c;前几天加班适配kingbase&#xff0c;发现坑是真滴多&#xff0c;小小总结一波。 tips:kingbase的语法可以直接参照pgsql...他们两个是通用的&#xff08;应该&#xff09; 1. 的坑 在Mysql里面的 (不是单引号&#xff01; 和 还是有点区别的) 这是拿来…

机械臂路径规划path planning

一、路径规划&#xff1a;假设机械臂的终端结构要从一个点运动到另一个点&#xff0c;我们要求所有的关节和终端机构在运动的过程中都不能碰到障碍物&#xff0c;这个称为路径规划。 1、路径规划算法主要可分成两种&#xff1a; &#xff08;1&#xff09;一种是基于搜索结果…

第十三天缓存一致性篇

目录 一、缓存的应用场景 二、缓存数据一致性如何保证&#xff1f; 三、缓存的最终一致性解决方案&#xff1a; 一、缓存的应用场景 1、缓存中的数据不应该是实时性一致性要求超高的&#xff0c; 通过缓存加上过期时间保证每天拿到的数据都是最新的即可。 2、如果实时性要求…

tcp通信,客户端服务端

进行过程 //TCP通信的流程 //服务器端&#xff08;被动接受连接的角色&#xff09; 1.创建一个用于监听的套接字 -监听&#xff1a;监听有客户端的连接 -套接字&#xff1a;这个套接字其实就是一个文件描述符 2.将这个监听文件描述符和本地的IP和端口绑定&#xff08;IP和端口…

飞凌嵌入式AM62x核心板,赋能新一代HMI

HMI&#xff08;人机界面&#xff09;是系统和用户之间进行交互和信息交换的媒介&#xff0c;凡是涉及人机信息交流的领域都离不开人机界面&#xff0c;因此在许多行业内都能见到HMI的身影。随着技术的进步HMI也在持续发展和演进&#xff0c;除了数据收集、控制和显示外&#x…