构建安全的REST API:OAuth2和JWT实践

引言

大家好,我是小黑,小黑在这里跟咱们聊聊,为什么REST API这么重要,同时,为何OAuth2和JWT在构建安全的REST API中扮演着不可或缺的角色。

想象一下,咱们每天都在使用的社交媒体、在线购物、银行服务等等,它们背后都离不开REST API的支撑。API允许不同的系统和服务之间进行数据交换和通信,正因为有了它,才能让咱们享受到如此便捷的数字生活。

但是,随着技术的发展,安全问题也随之而来。一个没有加密的API就像是一个没有锁的门,任何人都可以随意进入。这时候,OAuth2和JWT就像是一把钥匙和一把锁,确保只有授权的人才能通过这扇门。OAuth2提供了一个全面的授权框架,而JWT(Json Web Token)则用于安全地在各方之间传递信息。

REST API简介

说到REST API,咱们先来搞清楚几个概念。REST(Representational State Transfer)是一种设计风格,它定义了一套规则,用于创建网络服务。通过使用HTTP协议的方法,如GET、POST、PUT、DELETE等,REST API允许应用程序或服务访问网络上的资源。

举个例子,假如小黑现在要开发一个天气预报应用。这个应用需要从一个天气服务提供商那里获取数据。这时候,REST API就是小黑和天气服务提供商之间的桥梁。小黑可以发送一个GET请求到天气服务的API,请求特定城市的天气数据,然后这个服务就会返回一个包含天气信息的JSON响应。

// Java代码示例:使用HttpClient发送GET请求获取天气数据
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class WeatherApiClient {
    public static void main(String[] args) {
        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://api.weather.com/v1/city?name=北京"))
                .build();

        client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
                .thenApply(HttpResponse::body)
                .thenAccept(System.out::println)
                .join();
    }
}

这段代码简单地展示了如何使用Java的HttpClient发送一个GET请求到天气服务的API,并异步地获取响应数据。注意,上面的URL是假设的,实际应用中需要替换成真实的API地址。

通过这个简单的例子,咱们可以看到,REST API使得从不同的服务获取数据变得非常简单和直接。但是,当涉及到敏感信息或者数据需要保护时,单纯的REST API就显得力不从心了。这就是OAuth2和JWT登场的时机,它们可以帮助咱们构建既强大又安全的API服务。

认识OAuth2

在聊OAuth2之前,小黑得先跟咱们解释一下什么是授权。简单来说,授权就是赋予某人或某系统某种权限,比如访问资源的权限。在网络里,授权确保只有被允许的人或系统能访问敏感信息或执行重要操作。这就是OAuth2发光发热的地方。

OAuth2,全名是Open Authorization 2.0,是一个行业标准的授权框架。它允许用户提供一个令牌给第三方应用,而不是直接暴露用户的登录信息,从而安全地授权第三方应用访问用户在某一服务上的信息。想象一下,当小黑想要让一个日历应用访问他的邮箱账户来同步日程时,OAuth2就能派上用场。

小黑偷偷告诉你一个生财信息差网站: 小黑的生财资料站

OAuth2的四种授权模式

OAuth2定义了四种授权模式,每种模式适用于不同的场景:

  1. 授权码模式(Authorization Code):这是最常用的模式,适用于有服务器的Web应用。它通过用户代理重定向来获得授权码,然后交换令牌。

  2. 隐式模式(Implicit):适用于没有后端服务器的纯前端应用,如单页应用(SPA)。它直接在客户端获得令牌,而不是授权码。

  3. 密码模式(Resource Owner Password Credentials):在用户信任客户端的情况下使用,如用户的设备上的应用。用户直接提供用户名和密码给客户端,客户端使用这些信息获得令牌。

  4. 客户端凭证模式(Client Credentials):适用于客户端访问自己保护的资源,不涉及用户,通过客户端的凭证直接获取令牌。

下面,小黑用Java代码示例来说明如何实现授权码模式,因为这是最常见且最安全的一种模式:

// Java代码示例:使用Spring框架实现OAuth2授权码模式
// 注意:这是一个高度简化的示例,实际应用中需要更完整的配置

import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;

@EnableWebSecurity
public class OAuth2SecurityConfig {

    protected void configure(HttpSecurity http) throws Exception {
        http
            .oauth2Login()
            .authorizationEndpoint()
                .baseUri("/oauth2/authorize")
                .and()
            .redirectionEndpoint()
                .baseUri("/oauth2/callback/*")
                .and()
            .tokenEndpoint()
                .accessTokenResponseClient(accessTokenResponseClient())
                .and()
            .userInfoEndpoint()
                .userService(customOAuth2UserService());
    }
    
    // 配置访问令牌的响应客户端和用户信息服务...
}

这段代码是在使用Spring Security和Spring Boot时配置OAuth2授权码模式的一个基本示例。它定义了授权端点、重定向端点以及令牌端点。需要注意的是,为了实现OAuth2授权码模式,还需要注册OAuth2客户端详情和配置用户信息服务,这里因篇幅限制,就不展开了。

通过授权码模式,应用程序可以安全地获得用户授权,而不需要用户分享他们的用户名和密码。这种方式不仅提升了安全性,还提升了用户体验,因为用户可以细粒度地控制第三方应用访问自己数据的权限。

深入理解JWT

在OAuth2为咱们提供了一个强大的授权框架后,接下来小黑要跟咱们聊聊JWT,一个在安全传输信息方面非常关键的技术。JWT,全称是JSON Web Token,它是一个开放标准(RFC 7519),定义了一种紧凑且自包含的方式,用于在各方之间安全地传输信息作为JSON对象。因为信息是数字签名的,所以这种方式是安全的。

JWT的结构

JWT通常由三部分组成,用点(.)分隔开:Header(头部)、Payload(负载)和Signature(签名)。

  1. Header:头部通常由两部分组成,令牌的类型(即"JWT")和所使用的签名算法,如HMAC SHA256或RSA。

  2. Payload:负载部分包含了所要传输的信息,这些信息以称为声明(Claim)的键值对形式存在。声明有三种类型:注册的声明、公共的声明和私有的声明。

  3. Signature:为了创建签名部分,你必须取头部的编码、负载的编码,加上一个密钥,然后通过头部中指定的算法进行签名。

使用Java生成和验证JWT

下面,小黑用Java代码示例来演示如何生成和验证一个JWT。咱们将使用java-jwt库来完成这项工作,这是处理JWT的一个流行Java库。

首先,咱们需要添加java-jwt依赖到项目中:

<!-- pom.xml -->
<dependency>
    <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
    <version>3.8.3</version>
</dependency>

然后,咱们来看看如何生成一个简单的JWT:

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import java.util.Date;

public class JwtDemo {

    public static void main(String[] args) {
        // 创建JWT
        String token = JWT.create()
                .withIssuer("小黑")
                .withSubject("JWT示例")
                .withExpiresAt(new Date(System.currentTimeMillis()+3600*1000)) // 设置过期时间
                .withClaim("name", "咱们的用户")
                .sign(Algorithm.HMAC256("secret")); // 使用HMAC256算法,"secret"是密钥

        System.out.println("生成的JWT: " + token);
    }
}

这个示例展示了如何使用java-jwt库来生成一个JWT。咱们在JWT中设置了发布者、主题、过期时间以及一个自定义声明。然后使用HMAC256算法和一个密钥来对其进行签名。

接下来,看看如何验证这个JWT:

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;

public class JwtVerifyDemo {

    public static void main(String[] args) {
        try {
            Algorithm algorithm = Algorithm.HMAC256("secret"); // 使用相同的密钥和算法
            JWTVerifier verifier = JWT.require(algorithm)
                    .withIssuer("小黑")
                    .build(); // 创建JWT验证器

            // 验证JWT
            verifier.verify("这里是之前生成的JWT");
            System.out.println("JWT验证成功!");
        } catch (JWTVerificationException exception){
            // 无效的签名/声明
            System.out.println("JWT验证失败: " + exception.getMessage());
        }
    }
}

这段代码演示了如何验证一个JWT。咱们使用相同的密钥和算法来创建一个JWTVerifier对象,然后调用其verify方法来验证JWT。如果JWT的签名或声明不匹配,这个方法将抛出一个JWTVerificationException异常。

通过这样的方式,JWT提供了一个非常灵活且安全的方法来在不同服务之间传递信息。

OAuth2与JWT结合的实践

现在咱们已经分别了解了OAuth2和JWT,接下来小黑要介绍的是,这两个技术如何结合起来,为REST API提供更加强大和安全的认证和授权机制。

结合OAuth2和JWT的好处

OAuth2提供了一个强大的授权框架,而JWT则为信息的安全传输提供了保障。当将它们结合使用时,咱们不仅能实现安全的授权流程,还能确保授权信息的安全传输和验证。这种结合使用的方式,使得系统既能利用OAuth2进行灵活的授权,又能通过JWT确保传输数据的完整性和安全性。

实现流程
  1. 用户认证:用户首先通过OAuth2的授权码模式或其他模式进行认证。
  2. 获取令牌:一旦用户认证成功,授权服务器会发放一个由JWT构成的访问令牌给客户端。
  3. 资源访问:客户端随后可以使用这个JWT令牌来访问受保护的资源。
代码实践:使用Spring Security和JWT

假设小黑正在使用Spring Boot和Spring Security来构建一个REST API,下面是一个简化的示例,展示如何结合OAuth2和JWT来保护这个API。

首先,咱们需要添加Spring Security和JWT的依赖到项目中:

<!-- pom.xml -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
    <version>3.8.3</version>
</dependency>

然后,配置Spring Security来使用JWT:

import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .oauth2Login() // 启用OAuth2登录
            .and()
            .authorizeRequests()
                .anyRequest().authenticated() // 所有请求都需要认证
            .and()
            .oauth2ResourceServer()
                .jwt(); // 使用JWT作为OAuth2资源服务器的令牌
    }
}

这段配置确保了所有请求都必须经过认证,并且指定了使用JWT作为资源服务器的认证令牌。

生成和验证JWT

接下来,小黑要展示如何在授权服务器上生成JWT令牌,并在资源服务器上验证这个令牌。这里简化处理,只展示生成令牌的关键步骤:

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import java.util.Date;

public class TokenProvider {

    public String createToken() {
        return JWT.create()
                .withSubject("用户ID或其他标识")
                .withExpiresAt(new Date(System.currentTimeMillis() + 3600 * 1000)) // 1小时后过期
                .sign(Algorithm.HMAC256("secret")); // 使用密钥签名
    }
}

在资源服务器上,咱们需要验证JWT令牌的有效性。可以使用Spring Security的JWT支持来实现这一点,具体配置和实现方式可能会根据实际情况和框架版本有所不同。

通过这样的实现,小黑和咱们就能构建出一个既安全又灵活的REST API,不仅能有效管理和授权用户访问,还能确保数据在传输过程中的安全性。这种OAuth2结合JWT的做法,在现代应用开发中越来越成为标配。

安全实践与策略

在OAuth2和JWT为咱们构建了一个安全框架的基础上,小黑接下来要和咱们聊聊如何进一步加固REST API的安全性。毕竟,安全是一个永远在路上的话题,需要咱们持续关注和改进。

防范常见的安全威胁
  1. 跨站请求伪造(CSRF):CSRF攻击利用了用户已登录的认证状态,让攻击者能够以用户的名义执行恶意操作。为了防范CSRF,咱们可以利用Spring Security提供的CSRF保护机制,它会要求所有状态改变的请求(例如POST请求)都必须携带一个正确的CSRF令牌。

  2. 跨站脚本攻击(XSS):XSS攻击通过在页面中注入恶意脚本,来窃取用户数据或者伪造用户行为。防范XSS的一个有效方法是确保所有用户输入都经过适当的清理和转义,防止恶意脚本的执行。

  3. 安全通信:使用HTTPS而不是HTTP,可以保护咱们的数据在传输过程中不被窃听或篡改。确保所有的通信都通过SSL/TLS加密,是保护REST API安全的基本要求。

使用OAuth2和JWT的最佳安全实践
  1. 安全存储密钥:在使用JWT时,密钥的安全存储至关重要。不管是对称密钥还是非对称密钥,都应该安全存储,防止被泄露。

  2. 设置合理的令牌过期时间:为了降低令牌被盗用的风险,应该为访问令牌设置一个合理的过期时间。短期的访问令牌加上长期的刷新令牌,是一个比较推荐的做法。

  3. 限制令牌的使用范围:通过限制令牌的使用范围(Scope),可以减少如果令牌被泄露时可能造成的损害。比如,一个仅用于读取信息的令牌,就不应该有修改或删除信息的权限。

  4. 检查和验证所有请求:所有到达服务器的请求都应该经过检查和验证,确保它们都携带了有效的令牌,并且令牌中的权限与请求的操作相匹配。

技术示例:防范CSRF和使用HTTPS

为了更具体地展示如何实施这些安全措施,小黑在这里提供一些技术示例。

防范CSRF

在Spring Security中,CSRF保护默认是开启的。但是,如果你的应用是一个REST API,通常会禁用CSRF保护,因为API主要使用令牌认证而非Cookie。如果选择启用,可以这样配置:

import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .csrf().disable() // 对于REST API,通常推荐禁用CSRF保护
            .authorizeRequests()
                .anyRequest().authenticated()
            .and()
            .httpBasic();
    }
}

技术栈和工具

推荐的Java框架和库
  1. Spring Security:这是一个功能强大的安全框架,为基于Spring的应用程序提供声明式的安全访问控制解决方案。它支持OAuth2和JWT,非常适合用来构建安全的REST API。

  2. java-jwt:这个库提供了一种简单的方式来创建和验证JWT令牌。它支持多种算法,易于集成和使用。

  3. JJWT:这是另一个处理JWT的流行Java库,它同样提供了创建和验证JWT的功能,使用简单,灵活性高。

实用工具和资源

在开发和调试安全的REST API时,以下工具和资源非常有帮助:

  1. Postman:这是一个强大的API测试工具,允许咱们发送各种HTTP请求,设置请求头,包括Authorization头,非常适合测试咱们的OAuth2和JWT实现。

  2. OpenSSL:这是一个强大的加密工具,可以用来生成密钥和证书,对于设置HTTPS和生成JWT所需的密钥非常有用。

  3. Let’s Encrypt:这是一个免费的、自动化的、开放的证书颁发机构(CA),提供了一个简单的方式来安装SSL/TLS证书,从而启用HTTPS。

  4. OAuth 2.0 and OpenID Connect:理解OAuth 2.0和OpenID Connect的最佳实践非常重要,这些知识可以帮助咱们更好地理解和实施安全措施。

技术示例:使用Spring Security和java-jwt

为了具体展示如何使用这些技术栈和工具,小黑提供一个简单的示例,展示如何使用Spring Security和java-jwt生成JWT令牌:

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;

import java.util.Collections;
import java.util.Date;

public class JwtUtil {

    private static final String SECRET = "非常秘密的密钥";
    private static final long EXPIRATION_TIME = 864_000_000; // 10天

    public static String generateToken(Authentication auth) {
        User principal = (User) auth.getPrincipal();
        return JWT.create()
                .withSubject(principal.getUsername())
                .withExpiresAt(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
                .sign(Algorithm.HMAC512(SECRET.getBytes()));
    }

    public static Authentication getAuthentication(String token) {
        String user = JWT.require(Algorithm.HMAC512(SECRET.getBytes()))
                .build()
                .verify(token)
                .getSubject();

        return new UsernamePasswordAuthenticationToken(user, null, Collections.singletonList(new SimpleGrantedAuthority("USER")));
    }
}

这段代码展示了如何使用java-jwt库生成和验证JWT令牌。通过简单的配置和代码示例,小黑希望能帮助咱们快速理解和实践如何在Java应用中使用OAuth2和JWT来保护REST API。

通过掌握这些技术栈和工具,加上前面章节介绍的知识和实践,咱们就能构建出既强大又安全的REST API服务。这不仅能保护咱们的数据安全,还能提升用户的信任和满意

总结

经过前面几章的探讨和学习,小黑和咱们一起走过了构建安全REST API的旅程,从基本的概念到实践,再到进阶的安全策略和技术栈的应用。通过这个过程,咱们不仅学会了如何使用OAuth2和JWT保护REST API,还了解了如何防范常见的安全威胁,并掌握了一些实用的工具和资源。

在现代的应用开发中,安全性是一个不能忽视的话题。随着技术的发展和攻击手段的不断进化,保护好咱们的应用和用户数据变得越来越重要。OAuth2和JWT提供了一种有效的方式来保护REST API,但这只是安全领域广阔知识体系中的一部分。安全是一个需要持续学习和实践的过程,随着时间的推移,咱们需要不断更新知识,掌握新的技术和策略。


更多推荐

详解SpringCloud之远程方法调用神器Fegin

掌握Java Future模式及其灵活应用

小黑整的视頻会园优惠站

小黑整的生财资料站

使用Apache Commons Chain实现命令模式

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

大气颗粒物和VOCs PMF源解析实用干货

目前&#xff0c;大气颗粒物和臭氧污染成为我国亟待解决的环境问题。颗粒物和臭氧污染不仅对气候和环境有重要影响&#xff0c;而且对人体健康有严重损害。而臭氧的前体物之一为挥发性有机物&#xff08;VOCs&#xff09;。为了高效、精准地治理区域大气颗粒物和臭氧污染&#…

115.龙芯2k1000-pmon(14)- pmon编程优化

通过上面的分析&#xff0c;发现&#xff0c;其实gzrom-dtb.bin其实有很多空白区域&#xff0c;而且空白区域填充的都是0&#xff0c;这对flash来说并不友好&#xff0c;能否把填充的位置改为ff呢&#xff0c;这样编程的速度也会加快&#xff0c;对flash来说也是一种保护呢。 …

【网站项目】121开放式教学评价管理系统

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

Linux速览(1)——基础指令篇

在上一章对Linux有了一些基础了解之后&#xff0c;本章我们来学习一下Linux系统下一些基本操作的常用的基础指令。 目录 1. ls 指令 2. pwd&&whoami命令 3. cd 指令 4. touch指令 5.mkdir指令&#xff08;重要&#xff09;&#xff1a; 6.rmdir指令 && …

【虚拟机安装centos7后找不到网卡问题】

最近开始学习linux&#xff0c;看着传智播客的教学视频学习&#xff0c;里面老师用的是centos6.5&#xff0c;我这边装的是centos7最新版的 结果到了网络配置的这一节&#xff0c;卡了我好久。 我在centos一直找不到我的网卡eth0&#xff0c;只有一个回环网口&#xff0c;在/…

TikTok外贸系统的核心功能及其源代码分享!

随着全球化的不断推进&#xff0c;外贸业务成为越来越多企业的增长动力&#xff0c;TikTok作为一个全球性的社交媒体平台&#xff0c;其用户基数庞大、活跃度高&#xff0c;为外贸业务提供了无限的商机。 为了帮助企业在TikTok上更好地开展外贸业务&#xff0c;TikTok外贸系统…

Ubuntu环境使用docker构建并运行SpringBoot镜像

今天Ubuntu环境使用docker构建并运行SpringBoot镜像&#xff0c;看文章之前建议先查看安装流程: Linux环境之Ubuntu安装Docker流程 一、镜像打包过程及执行 1、创建一个测试目录 mkdir javaDemo 2、springBoot的包复制到此目录下 cp demo1-0.0.1-SNAPSHOT.jar /data/app/…

Docker快速集成minio

拉取镜像&#xff08;默认最新的&#xff09; docker pull minio/minio创建配制和数据映射文件夹&#xff08;用于将容器内的配置和数据映射到本地&#xff09; 这边的路径可以修改成自己想要的文件夹 mkdir -p /data/minio/{config,data}启动容器 (这边启动容器要保证本地映…

【大厂AI课学习笔记NO.61】环境部署的选择

主要是选择单机和分布式、生产和开发环境的规划等。 开发环境、测试环境、预发布环境和生产环境是软件开发和部署过程中常见的几个环境&#xff0c;它们各自的定义、区别、联系以及实现的关键技术如下&#xff1a; 1. 开发环境&#xff08;Development Environment&#xff09…

骨传导耳机哪个牌子好?六大选购窍门,帮你甩掉坑货!

很多用户对骨传导耳机的理解存在偏差&#xff0c;认为只要选择价格贵的、热度高的产品就能万事大吉&#xff0c;而实际却不是如此&#xff0c;要知道&#xff0c;随着骨传导耳机逐渐成为热门款式&#xff0c;目前的市场上的骨传导耳机品牌也变得五花八门&#xff0c;这其中就包…

Android MediaCodec 简明教程(五):使用 MediaCodec 编码 ByteBuffer 数据,并保存为 MP4 文件

系列文章目录 Android MediaCodec 简明教程&#xff08;一&#xff09;&#xff1a;使用 MediaCodecList 查询 Codec 信息&#xff0c;并创建 MediaCodec 编解码器Android MediaCodec 简明教程&#xff08;二&#xff09;&#xff1a;使用 MediaCodecInfo.CodecCapabilities 查…

刷题日记:面试经典 150 题 DAY3

刷题日记&#xff1a;面试经典 150 题 DAY3 274. H 指数238. 除自身以外数组的乘积380. O(1) 时间插入、删除和获取随机元素134. 加油站135. 分发糖果 274. H 指数 原题链接 274. H 指数 重要的是都明白H指数到底是是个啥。注意到如果将引用数从大到小排序&#xff0c;则对于…

每日一题-移除链表元素

&#x1f308;个人主页: 会编辑的果子君 &#x1f4ab;个人格言:“成为自己未来的主人~” 移除链表元素 以上是题目名称&#xff1a; typedef struct ListNode SListNode; struct ListNode* removeElements(struct ListNode* head, int val) {SListNode*newHead,*newTail;ne…

Matlab 机器人工具箱 例程:运动学+动力学+路径规划+可视化

文章目录 1 创建机器人2 机器人显示3 机器人示教4 机器人路径规划&#xff1a;给定关节角路径5 机器人路径规划&#xff1a;给定末端位姿&#xff0c;求关节角路径6 工作空间可视化参考链接 1 创建机器人 clc;clear;close all; deg pi/180;L1 Revolute(d, 0, a, 0, alpha, 0,…

分账系统哪个好 盘点2024年好用的四款分账系统

分账系统在现代商业活动中扮演着至关重要的角色&#xff0c;为企业提供了高效、准确的分账管理。那么&#xff0c;你知道2024年哪几款分账系统最好用呢&#xff1f;跟着小编的脚步去看看吧&#xff01; 一、商淘云 商淘云是广州商淘信息科技有限公司旗下品牌&#xff0c;它提…

CBA全明星急需改革但先不谈!不如先学学如何尊重球迷

直播吧指定地址&#xff1a;www.bjcenn.com 3月4日讯 昨晚CBA全明星正赛&#xff0c;南区明星队138-122击败北区明星队。 媒体人三土带刺更博长文总结了本次全明星&#xff0c;原文如下&#xff1a; 如何总结这次全明星&#xff1f; 又一届CBA全明星周末结束&#xff0c;关…

OSPF多进程

路由器——>选路——>参考路由表 路由表的生成&#xff1a; 直连路由直接加入 静态路由 动态路由&#xff0c;ospf&#xff1a;选择最优加入 IGP高级特性---OSPF多进程防火墙虚拟系统引流 http://t.csdnimg.cn/mTU3nhttp://t.csdnimg.cn/mTU3n 华为文档地址&#…

骨传导耳机哪个牌子好?简单6招教你选到高品质机型!

作为一名有着十几年工作经验的资深数码产品测评师&#xff0c;多年来见过太多因为选购劣质骨传导耳机而踩雷的情况&#xff0c;对此&#xff0c;我想要提醒大家的是&#xff0c;在选择骨传导耳机时不要一味地追求外观颜值、品牌知名度&#xff0c;而应该更加重视产品的专业技术…

刷题日记:面试经典 150 题 DAY4

刷题日记&#xff1a;面试经典 150 题 DAY4 42.接雨水13.罗马数字转整数12.整数转罗马数字58.最后一个单词长度14.最长公共前缀 42.接雨水 原题链接 42.接雨水 在学校的算法小学期做过&#xff0c;做法是基于一个重要的观察&#xff1a; 一列列的看&#xff0c;当前列雨水的高…

一线大厂软件测试面试题及答案解析,2024最强版...

【软件测试面试突击班】2024吃透软件测试面试最全八股文攻略教程&#xff0c;一周学完让你面试通过率提高90%&#xff01;&#xff08;自动化测试&#xff09; 1、什么是兼容性测试?兼容性测试侧重哪些方面? 参考答案: 兼容测试主要是检查软件在不同的硬件平台、软件平台上…