【工作记录】springsecurity从入门到实战(一)

news2025/1/11 8:49:13

一、介绍

在web应用开发中,安全无疑是十分重要的,目前最流行的安全框架莫过于shiro和springsecurity了。

以下是二者简单的一个对比:

SpringSecurityShiro
基本功能完善完善
文档完善程度强大强大
社区支持度依托于Spring,社区支持强大强大
集成难度、使用方便度与Spring、springboot、springcloud集成方便、简单简单
用户量趋势上升略有下滑
所属组织SpringApache
对oauth2.0的支持支持需要自行实现
社交登录实现支持需要自行实现
功能扩展性

对于项目中的认证授权模块的实现与扩展,二者都是满足要求的,且集成相对都较为容易。如果你只是想实现一个简单的web应用,shiro更加的轻量级,学习成本也更低;如果您正在开发一个分布式的、微服务的、或者与Spring Cloud系列框架深度集成的项目,笔者还是建议您使用Spring Security。具体选择方案看公司和具体项目情况。

当然现在也有一些比较好的开源的认证授权框架,比较好的像sa-token也是值得学习和尝试的。

本文我们重点介绍的是SpringSecurity以及与Springboot项目的集成和扩展。

二、基本使用及异常处理

我们从一个简单的例子入手:

​ 接口分为两类,一类不需要登录可以直接访问,一类需要登录成功后可以访问,

​ 提供一个可以直接访问的登录接口和一个需要登录的验证接口。

项目采用Springboot+Maven+SpringSecurity+ java实现, 目前整体结构如下:

  • auth-parent-new: 顶级父工程

     - auth-common: 公共依赖,放一些工具类、通用实体类等
     - auth-framework: 完成认证授权的核心业务
    

依赖框架及版本:

名称版本号
Springboot2.7.8
Spring-Security5
Maven3
JDK1.8

2.1 新建一个项目auth-parent-new

pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.8</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.zjtx.tech</groupId>
    <artifactId>auth-parent-new</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>pom</packaging>
    <name>auth-parent-new</name>
    <description>parent pom for auth-parent</description>
    <properties>
        <java.version>8</java.version>
        <spring-boot.version>2.7.8</spring-boot.version>
        <lombok.version>1.18.22</lombok.version>
    </properties>
    <modules>
        <module>auth-common</module>
        <module>auth-framework</module>
    </modules>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>${lombok.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

2.2 新建auth-common子模块

命名为auth-common, 对应的pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.zjtx.tech</groupId>
        <artifactId>auth-parent-new</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <artifactId>auth-common</artifactId>
    <description>公共模块代码</description>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.7.10</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
            <version>2.7.10</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>
</project>

auth-common模块中放置一个公共响应类R

package com.zjtx.tech.auth.common.domain;

import lombok.Data;

@Data
public class R<T> {

    private static final int SUCCESS = 200;    //成功
    private static final int ERROR = 1;    //错误
    private static final int FAIL = 2;    //失败
    private static final int INFO = 101;    //信息
    private static final int PROMPT = 102;    //提示
    private static final int WARNING = 103;    //警告

    private int code;

    private String msg;

    private T data;

    public static <T> R<T> ok() {
        return restResult(SUCCESS, "操作成功", null);
    }

    public static <T> R<T> ok(T data) {
        return restResult(SUCCESS, "操作成功", data);
    }

    public static <T> R<T> ok(String msg, T data) {
        return restResult(SUCCESS, msg, data);
    }

    public static <T> R<T> fail() {
        return restResult(FAIL, "操作失败", null);
    }

    public static <T> R<T> fail(String msg) {
        return restResult(FAIL, msg, null);
    }

    private static <T> R<T> restResult(int code, String msg, T data) {
        R<T> apiResult = new R<>();
        apiResult.setCode(code);
        apiResult.setData(data);
        apiResult.setMsg(msg);
        return apiResult;
    }

}

2.3 新建auth-framework子模块

整体结构如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JFmk9p9P-1684286301725)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230410212547701.png)]

目录分为如下几种:

  • exception 全局异常处理
  • service 提供服务的
  • config 配置相关
  • controller 提供给前台访问的controller

具体内容如下:

2.3.1 全局异常处理类GlobalExceptionHandler.java

package com.zjtx.tech.auth.security.exception;

import com.zjtx.tech.auth.common.domain.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.AuthenticationException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(AuthenticationException.class)
    public R<String> authEx(AuthenticationException ex) {
        //这里是用抽象异常类接的,不能使用ex.getCause().getMessage()会报空指针异常
        //ex.getMessage()这个方法返回的就是具体的异常信息
        log.info("捕获到全局异常, {}", ex.getMessage());
        return R.fail(ex.getMessage());
    }

}

AuthenticationException是springsecurity提供的一个认证异常抽象类,其类结构关系为:

异常类结构图

通过名称大致可以理解到基本都是一些认证异常,如用户名密码错误、账户锁定、账户过期之类的。

这里我们的全局异常类捕获的也是这个抽象父类异常,如果抛出的是子类异常就都可以捕获到。

2.3.2 用户服务实现类UserDetailsServiceImpl.java

springsecurity提供了一个获取用户信息的接口类UserDetailsService,在验证用户的时候会调用这个类的实现类的loadUser方法获取实际的用户信息,同时提供了一个接收返回的用户信息的实体类接口UserDetails以及一个默认的实现类User

UserDetailsServiceImpl.java

package com.zjtx.tech.auth.security.service;

import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

@Slf4j
@Service
public class UserDetailServiceImpl implements UserDetailsService {

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //这里返回的是数据库的用户信息转换成的UserDetails的实现类
        //SpringSecurity会自动根据用户名和密码以及加密算法进行匹配
        log.info("根据用户名查询用户:{}", username);
        return 					User.builder().username(username).password("$2a$10$wcPhi2iVfRTL2hEJSTg3S.JiVs3hd4OaMNyiixXePePXbtlYUyiGS")
                .authorities(new SimpleGrantedAuthority("ROLE_ALL_USER"))
                .accountExpired(false)
                .credentialsExpired(false)
                .disabled(false)// disabled为true的话会返回状态码403
                .build();
    }

}

这里的逻辑正常来说的话是根据一个用户标识字段去数据库、内存或者LDAP这样的容器中去查询用户并返回相关信息。上面代码简化了这个逻辑,通过User类的静态方法内置了一个用户。

我们知道用户登录如果是表单登录一般会是用户名+密码这样的验证方式,springsecurity也提供了对应的密码验证接口PasswordEncoder,并提供了一系列的默认实现,如果不配置的话使用的是BCryptPasswordEncoder这个实现类,上面代码中的password参数就是原密码通过BCryptPasswordEncoder加密后的值,springsecurity会将用户输入的密码进行加密后与该值比较,如果不一致则抛出BadCrendicialException。

2.3.3 安全配置类SecurityConfig.java

package com.zjtx.tech.auth.security.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig {

    @Autowired
    private UserDetailsService userDetailsService;

    @Bean
    public SecurityFilterChain filerChain(HttpSecurity http) throws Exception {
        return http
            // 基于 token,不需要 csrf
            .csrf().disable()
            // 基于 token,不需要 session
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
            // 下面开始设置权限
            .authorizeRequests()
            //不校验所有以login开头的接口
            .antMatchers("/login/**").permitAll()
            //其他的接口都需要认证后才能访问
            .anyRequest().authenticated()
            .and()
            // 认证用户时用户信息加载配置,注入springAuthUserService
            .userDetailsService(userDetailsService)
            .build();
    }

    /**
     * 密码明文加密方式配置
     * @return 密码加密器
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /**
     * 获取AuthenticationManager(认证管理器),登录时认证使用
     * @param authenticationConfiguration 认证配置
     * @return 认证管理器
     * @throws Exception 认证异常
     */
    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
        return authenticationConfiguration.getAuthenticationManager();
    }

    /**
     * 配置跨源访问(CORS)
     * @return 跨域配置
     */
    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
        return source;
    }
}

可以看到这个配置类是相当重要的,配置了访问权限、跨域访问、认证管理器、密码加密方式等。通过这个配置springsecurity可以知道哪些接口需要哪些权限或者角色才能访问,哪些接口不需要校验可以直接访问。

2.3.4 controller

提供两个controller类用于验证,一个需要认证的ResourceController和一个不需要认证的LoginController

ResourceController.java

package com.zjtx.tech.auth.security.controller;

import com.zjtx.tech.auth.common.domain.R;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("resource")
public class ResourceController {

    @Autowired
    private AuthenticationManager authenticationManager;

    @GetMapping("doTest")
    public R<Object> doTest(String username) {
        System.out.println("username = " + username);
        return R.ok(username);
    }

}

LoginController.java

package com.zjtx.tech.auth.security.controller;

import com.zjtx.tech.auth.common.domain.R;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("login")
public class LoginController {

    @Autowired
    private AuthenticationManager authenticationManager;

    @GetMapping("doLogin")
    public R<Object> doLogin(String username, String password) {
        Authentication token = new UsernamePasswordAuthenticationToken(username, password);
        Authentication authenticate = authenticationManager.authenticate(token);
        return R.ok(authenticate.getPrincipal());
    }

}

2.3.5 Application类和yml配置文件

package com.zjtx.tech.auth.security;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class AuthFrameworkApplication {

    public static void main(String[] args) {
        SpringApplication.run(AuthFrameworkApplication.class, args);
    }

}
server:
  port: 8081

2.3.6 接口测试

通过页面访问链接: http://localhost:8081/login/doLogin?username=1&password=1

用户名密码验证

修改password密码为123456,再次验证。

登录成功验证

访问resource下的doTest接口,可以看到返回的是403无权限,前端可根据该响应做对应页面的展示。

无权限验证

到此一个简单的demo应用就完成了。

三、实现原理

3.1 原理概述

Spring Security 认证原理基于过滤器链,其中核心的过滤器是 UsernamePasswordAuthenticationFilter。该过滤器负责处理来自用户的身份验证请求,并尝试对其进行身份验证。如果身份验证成功,它将生成一个 Authentication 对象并存储在安全上下文中。如果身份验证失败,它将生成一个 AuthenticationException,并向客户端返回错误响应。

除了过滤器链外,Spring Security 还使用了一些其他组件来支持身份验证,例如 AuthenticationManager 和 UserDetailsService。AuthenticationManager 用于管理身份验证过程,并根据需要委托给不同的 AuthenticationProvider 来处理不同类型的身份验证。UserDetailsService 负责从特定来源获取用户信息,例如数据库或 LDAP 目录。

3.2 认证过程描述

具体认证过程如下(以用户名密码登录为例):

  1. 用户登录:用户在登录页面输入用户名和密码并提交表单。
  2. 认证请求:Web容器拦截到表单提交请求后,Spring Security会将其转发至认证处理过滤器链(AuthenticationProcessingFilter)。
  3. 身份验证:认证处理过滤器链根据配置的身份验证方式,在内存、关系型数据库或LDAP等数据源中验证用户的身份。
  4. 认证结果处理:如果身份验证成功,则Spring Security会创建一个经过授权的安全上下文(SecurityContext)并将其绑定到当前线程。如果身份验证失败,则会返回相应的错误信息。
  5. 认证成功处理:如果身份验证成功,Spring Security会根据配置的设置,执行一些额外的操作,例如生成令牌、跳转到指定页面等。
  6. 授权检查:所有后续请求都将通过授权检查过滤器链(FilterSecurityInterceptor)以确保用户被授权访问相应资源。
  7. 认证注销:用户在退出时,Spring Security会清除与该用户相关的所有安全上下文。

以上是Spring Security的基本认证流程,其中具体实现可以根据项目需求进行定制化配置。

3.3 核心概念

  1. Authentication(认证):验证用户身份的过程,通常包含用户名和密码。
  2. Authorization(授权):确定用户是否有权限访问某个资源或执行某个操作。
  3. Principal(主体):代表当前被认证的用户,包含用户的信息和凭证。
  4. Granted Authority(授权信息):用于表示用户拥有哪些操作或资源的访问权限。

3.4 核心组件

  1. SecurityContext(安全上下文):存储当前用户的认证信息和授权信息。
  2. AuthenticationManager(认证管理器):处理Authentication对象的认证过程。
  3. UserDetailsService(用户详情服务):用于加载用户信息,通常从数据库中读取用户信息。
  4. UserDetails(用户详情):包含用户的用户名、密码、授权信息等详细信息。
  5. AccessDecisionManager(访问决策管理器):决定当前用户是否有权限访问某个资源或执行某个操作。
  6. FilterChainProxy(过滤器链代理):在请求到达应用程序之前,对请求进行预处理,并将请求传递给相应的安全过滤器。

3.5 认证流程图

认证流程图,图片来源于网络

图中描述的已经很清晰了,认真看完应该对流程和各个组件的关系就心里有数了。

3.6 扩展点

Spring Security 中的一些扩展点包括:

  1. AuthenticationProvider:用于自定义身份验证逻辑。
  2. AbstractAuthenticationToken: 允许用户实现不同的登录方式,AuthenticationProvider根据具体AbstractAuthenticationToken实现类选择Provider的具体实现类
  3. AccessDecisionVoter:用于根据授权策略来决定是否允许访问特定资源。
  4. FilterInvocationSecurityMetadataSource:用于为每个请求提供相应的安全元数据,这些元数据描述了该请求所需的安全配置。
  5. SecurityContextRepository:用于管理用户的安全上下文信息,例如认证和授权状态。
  6. WebSecurityConfigurerAdapter:用于配置 Spring Security 的安全策略,例如指定哪些 URL 路径需要受保护,如何处理登录和注销等操作。

小结

​ 本文完成了springsecurity基础环境的搭建和简单示例以及原理的简单介绍,后文会继续介绍进一步的应用。
就本文涉及的内容有任何疑问或者建议欢迎留言评论~
创作不易,欢迎一键三连~~~~

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

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

相关文章

Flutter仿写微信导航栏快速实现页面导航

文章目录 前言使用TabBar实现TabBar介绍TabBar的重要属性说明TabBarView介绍TabBarView的重要属性TabBar总结TabBar实现底部导航的例子 BottomNavigationBar实现BottomNavigationBar介绍BottomNavigationBar实现底部导航栏的例子 总结BottomNavigationBarTabBar根据实际情况选择…

代码随想录算法训练营day43 | 1049. 最后一块石头的重量 II ,494. 目标和,474.一和零,01背包问题总结

代码随想录算法训练营day43 | 1049. 最后一块石头的重量 II &#xff0c;494. 目标和&#xff0c;474.一和零 1049. 最后一块石头的重量 II解法一&#xff1a;动态规划 494. 目标和解法一&#xff1a;动态规划 474.一和零解法一&#xff1a;动态规划 01背包问题总结 1049. 最后…

商场导航地图系统,商场导航怎么实现?

商场导航怎么实现&#xff1f;在商场里面&#xff0c;手机上的导航往往接收不了信号或者不支持&#xff0c;由于室内不只是平面的&#xff0c;跟室外导航有很大的区别&#xff0c;因此&#xff0c;室内如何快速导航就成了现代化发展的趋势。电子地图作为大家最喜闻乐见的高效应…

交换机欺骗(Switch Spoofing)简介

交换机欺骗是修改设备的 MAC 地址以伪装成授权交换机端口并获得对目标网络的访问权限的过程。由于 MAC 地址对于特定设备是唯一的&#xff0c;因此大多数网络使用这些 MAC 地址来验证设备并与其通信或建立网络连接。通过欺骗授权设备或更简单地说&#xff0c;网络识别为“受信任…

redis_exporter 部署

目录 - 下载地址- 启动vim ./start.shvim ./stop.sh - 配置prometheus - 下载地址 https://github.com/oliver006/redis_exporter/releases - 启动 为了方便辨认 我更改了它的端口&#xff0c;并编了./start.sh和./stop.sh两个脚本方便以后启动&#xff0c;语句如下&#xf…

机器学习之逻辑回归、一(学习理论)

P(D|θ&#xff09; 文章目录 一、前言二、逻辑回归的由来三、到底什么是逻辑回归&#xff08;1&#xff09;. 先对逻辑回归有个大概感觉&#xff08;2&#xff09;.逻辑回归与线性回归的区别&#xff08;3&#xff09;.sigmoid函数&#xff08;4&#xff09;目标函数&#xf…

有关于ChatGPT你需要了解的内容应该都在这了,看这一篇就够啦

在国内用了很长一段时间的ChatGPT&#xff0c;每次跟小白&#xff0c;哪怕是用ChatGPT的人交流的时候&#xff0c;都感觉解释不清&#xff0c;正好今天周末&#xff0c;给大家整理一篇关于ChatGPT的科普文&#xff0c;想要了解或使用ChatGPT的人&#xff0c;一定要看完~~~ 什么…

内网渗透(CS与MSF联动) ATTCK实战系列一红队实战(一)

靶场下载地址: http://vulnstack.qiyuanxuetang.net/vuln/detail/2/ 拓扑图 环境配置 win7网络配置情况: 外网 内网域网络 Win2K3网络配置情况: 内网域网络 win2008(域控)网络配置情况: 内网域网络 渗透过程 开始之前&#xff0c;先到win7上开启phpstudy 打开网页&#…

安装 kubeadm

安装 kubeadm、kubelet 和 kubectl 基于Red Hat的发行版本 1、写入软件源 cat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo [kubernetes] nameKubernetes baseurlhttps://packages.cloud.google.com/yum/repos/kubernetes-el7-\$basearch enabled1 gpgcheck1 …

盘点谷歌26个插件生态;WPS AI上新与测评;Prompt中文指南;ChatGPT最新联网插件评测 | ShowMeAI日报

&#x1f440;日报&周刊合集 | &#x1f3a1;生产力工具与行业应用大全 | &#x1f9e1; 点赞关注评论拜托啦&#xff01; &#x1f916; 『Google 最新发布的26个插件&#xff0c;哪些ChatGPT也有&#xff1f;』插件生态初见端倪 ▢ Google自家生态 (9个)&#xff1a;办公…

CATIA操作经典技巧问答

如何快速知道当前的CATIA作图区上的零件的放大比例? 答:选中TOOLS----->OPTIONS----->VISUALIZATION----> DISPLAY CURRENT SCALE IN PARALLEL, MODE 的选项. 在屏幕的右下方的数值表示当前作图区内的几何体的显示比例。 如何快速定义草图方向? 答:按CTRL键点选在…

Crypto VC 们最近有何动向?7 个工具助你轻松追踪

http://www.btcwbo.com/7289.html 加密 VC 和基金对初创项目的投资收益超过百万美元。它们为具有增长潜力的早期创业公司提供资金、技术支持和专业知识&#xff0c;作为交换&#xff0c;它们将获得这些公司的股份&#xff08;代币&#xff09;。 你可能经常会听到“VC 投了”之…

nacos注册中心源码分析二之服务发现

nacos服务发现 服务发现是客户端发起负载均衡(feign)调用接口的时候内部第一次调用nacos服务端接口的时候去调用的 后续调用基本上都是从客户端的缓存列表里边去取&#xff0c;拿不到才会向服务端发起调用 如果想看这一块代码可以看下ribbion源码分析ribbon源码分析 上一篇&am…

什么是互联网交换中心?为什么它很重要?

互联网交换中心&#xff08;Internet Exchange Point, IXP&#xff09;是为促进互联网骨干网的网间互联和公平竞争而设置的运营商间进行数据网际交换的机构&#xff0c;是为互联网业者提供空间进行网络互连、交换流量和资源的服务场所&#xff0c;互联网业者可以在这里利用机架…

基于自定义知识库回答问题的ChatGPT-

前言 ChatGPT是一个强大的语言模型&#xff0c;利用大规模的自然语言处理和机器学习算法&#xff0c;可以进行自然而流畅的对话&#xff0c;理解自然语言问题和回答&#xff0c;相信在座各位&#xff0c;尤其是程序员的你&#xff0c;肯定不可能还没使用过ChatGPT。 ChatGPT能…

属于开发者的交流,openGauss SIG版本规划工作会议来啦!

想参与SIG组未来半年的规划与工作&#xff1f; 想与开发者们近距离探讨需求与解决方案&#xff1f; 想将您的需求合入到openGauss的下个版本&#xff1f; 想在社区年度Summit上展现成果&#xff1f; 那就不能错过这个属于开发者的交流盛会&#xff01; 社区年度开发者大会…

取用水监测计量标准化建设,加强流量在线监测

方案背景 根据《关于强化取水口取水监测计量的意见》、《十四五”节水型社会建设规划》以及《2022年水资源管理工作要点》等政策要求&#xff0c;为强化水资源管理&#xff0c;做好水资源税改革&#xff0c;构建节水型社会&#xff0c;要全面加强取水计量监测设施建设&#xff…

计算机网络实验(ensp)-​实验2:PP协议及PAP认证

目录 实验报告&#xff1a; 实验操作 1.建立网络拓扑图并开启设备 2.修改路由器名字 1.输入命名&#xff1a;sys 从用户视图切换到系统视图 2.输入命名&#xff1a;sysname 姓名 修改路由器名字 3.重复步骤1和2配置每台路由器 3.抓包 1.点击菜单栏的“数…

计算机图形学-GAMES101-6

一、前情提要 在观察和投影变换的基础上提出了视口变换&#xff0c;最终我们会将【-1,1】^ 3 立方体转换到屏幕空间中去。 当所有图像都在屏幕空间中时&#xff0c;我们就要将所有的图像画在屏幕上&#xff0c;这个过程就是光栅化&#xff0c;光栅化就是简单的在屏幕空间的采样…

独家公布!985/211高校毕业生源数量统计Top10揭晓……

2023&#xff0c;985/211高校硕博毕业生总数约达49W。 这是在各大高校官网、官方公众号统计/整理后得到的数据。可能不完全&#xff0c;但数量已经足够庞大&#xff0c;就业竞争也更为激烈。 为了帮助大家更好地了解这些大学的毕业生源情况&#xff0c;本文将为大家揭晓&#x…