《Spring实战》(第6版) 保护Spring

第1部分 Spring基础

第4章 使用非关系型数据

关系型数据库一直是首选,近年来"NoSQL"数据库提供了数据存储的不同概念和结构。

SpringData为很多NoSQL数据库提供了支持,包括MongoDB、Cassandra、Couchbase、Neo4j、Redis等,无论选择哪种,编程模型几乎是相同的。

看两个最流行的NoSQL数据库:Cassandra和MongoDB。

4.1 使用Cassandra存储库

Cassandra是一个分布式、高性能、始终可用、最终一致、列分区存储的NoSQL数据库。

Cassandra处理的是要写入表中的数据行,这些数据会被分区到一对多的分布式节点上。

没有任何一个节点会持有所有的数据,任何给定的数据行都会跨多个节点保存副本,从而消除单点故障。

Spring Data Cassandra为Cassandra数据库提供了自动化存储库的支持,与Spring Data JPA对关系型数据库的支持非常类似,还提供了用于将应用的领域模型映射为后端数据库结构的注解。

要完整了解它的特定,建议去阅读Cassandra的官方文档。

4.1.1 启动Spring Data Cassandra

其他略,用到时再说。

4.2 编写MongoDB存储库

自己查吧,用Docker容器来启动。

第5章 保护Spring

5.1 启用Spring Security

自动或手动添加Spring Boot security starter依赖到pom.xml文件中。

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId>
</dependency>

启动,访问主页,http://localhost:8080/login

用户名:user,密码在启动时的控制台:1a6d18d5-a6b9-4aa1-bcbe-08fef7cd5c17

登录进去。

5.2 配置Spring Security

Spring Security有多种配置方式,冗长的基于XML配置,现在都支持基于Java的配置,更加容易编写和阅读。

Spring Security的基础配置类
package tacos.security;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;@Configuration
public class SecurityConfig {@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}}

基础的安全配置主要工作声明 PasswordEncoder bean,创建新用户和登录时对用户认证都会用到它,本例使用BCryptPasswordEncoder。

Spring Security提供的密码转换器:
  • BCryptPasswordEncoder:使用bcrypt强哈希加密。
  • NoOpPasswordEncoder:不使用任何转码,没有任何加密技术,不适合生产环境使用。
  • Pbkdf2PasswordEncoder:使用PBKDF2加密。
  • SCryptPasswordEncoder:使用Scrypt哈希加密。
  • StandardPasswordEncoder:使用SHA-256哈希加密,被认为加密不够安全,已被废弃。

无论哪种密码转换器,数据库中的密码永远不会被解码,用户登录时加密后与数据库对比。

是PasswordEncoder的match()方法中进行的。

Spring Security提供了多个内置的UserDetailsService实现,包括:

  • 内存用户存储
  • JDBC用户存储
  • LDAP用户存储
5.2.1 基于内存的用户详情服务

用户信息可以存在内存之中,假设我们有有限的用户,而且这几个用户几乎不会发生变化,这种情况可以将用户定义成安全配置的一部分是非常简单的。

在内存用户详情服务bean中声明用户
package tacos.security;import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;@Configuration
public class SecurityConfig {@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}@Beanpublic UserDetailsService userDetailsService(PasswordEncoder encoder) {List<UserDetails> usersList = new ArrayList<>();usersList.add(new User("buzz",encoder.encode("buzz"),Arrays.asList(new SimpleGrantedAuthority("ROLE_USER"))));usersList.add(new User("woody",encoder.encode("woody"),Arrays.asList(new SimpleGrantedAuthority("ROLE_USER"))));return new InMemoryUserDetailsManager(usersList);}}

创建用户对象,都包含用户名,密码和权限列表。

用户名/密码:buzz/buzz woody/woody。可以登录。

UserDetails,User都是Spring Security提供的。

5.2.2 自定义用户认证

如需新增、移除或变更用户,我们用关系型数据库进行存储,对用户进行持久化处理。

定义用户实体
package tacos;import java.util.Arrays;
import java.util.Collection;import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
@Entity
public class User implements UserDetails {private static final long serialVersionUID = 1L;@Id@GeneratedValue(strategy = GenerationType.AUTO)private Long id;private final String username;private final String password;private final String fullname;private final String street;private final String city;private final String state;private final String zip;private final String phoneNumber;@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {return Arrays.asList(new SimpleGrantedAuthority("ROLE_USER"));}public User(String username, String password, String fullname, String street, String city, String state,String zip, String phoneNumber) {super();this.username = username;this.password = password;this.fullname = fullname;this.street = street;this.city = city;this.state = state;this.zip = zip;this.phoneNumber = phoneNumber;}public Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getFullname() {return fullname;}public String getStreet() {return street;}public String getCity() {return city;}public String getState() {return state;}public String getZip() {return zip;}public String getPhoneNumber() {return phoneNumber;}public String getUsername() {return username;}public String getPassword() {return password;}}

getAuthorities()方法应该返回用户被授予权限的一个集合,各种以is开头的方法返回布尔值,表明用户账号的可用、锁定、过期状态。(这些方法在UserDetails接口中,都返回true)

定义用户存储库接口
package tacos.data;import org.springframework.data.repository.CrudRepository;import tacos.User;public interface UserRepository extends CrudRepository<User, Long>{User findByUsername(String username);}

除拓展所有CRUD操作外,还定义findByUsername()方法,在用户详情中会用到,以便根据用户名查找User。

SecurityConfig声明自定义用户详情服务Bean
@Bean
public UserDetailsService userDetailsService(UserRepository userRepo) {return username -> {User user = userRepo.findByUsername(username);if(user != null) { return user; }throw new UsernameNotFoundException("用户名:"+username+"找不到!");};
}

UserDetailsService接口中只有一个方法loadUserByUsername(),则视为函数式接口,则不必实现类,而直接用lambda表达式来简化,需要传入一个username参数。还有就是此方法不能返回null,若返回则抛出异常。

注册用户

用户注册流程需要借助SpringMVC来完成。

用户登录表单类
package tacos.security;import org.springframework.security.crypto.password.PasswordEncoder;import tacos.User;public class RegistrationForm {private String username;private String password;private String fullname;private String street;private String city;private String state;private String zip;private String phone;public User toUser(PasswordEncoder passwordEncoder) {return new User(username, passwordEncoder.encode(password), fullname, street, city, state, zip, phone);}public RegistrationForm(String username, String password, String fullname, String street, String city, String state,String zip, String phone) {super();this.username = username;this.password = password;this.fullname = fullname;this.street = street;this.city = city;this.state = state;this.zip = zip;this.phone = phone;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public String getFullname() {return fullname;}public void setFullname(String fullname) {this.fullname = fullname;}public String getStreet() {return street;}public void setStreet(String street) {this.street = street;}public String getCity() {return city;}public void setCity(String city) {this.city = city;}public String getState() {return state;}public void setState(String state) {this.state = state;}public String getZip() {return zip;}public void setZip(String zip) {this.zip = zip;}public String getPhone() {return phone;}public void setPhone(String phone) {this.phone = phone;}}
用户注册的控制器RegistrationController
package tacos.security;import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;import tacos.data.UserRepository;@Controller
@RequestMapping("/register")
public class RegistrationController {private UserRepository userRepo;private PasswordEncoder passwordEncoder;public RegistrationController(UserRepository userRepo, PasswordEncoder passwordEncoder) {super();this.userRepo = userRepo;this.passwordEncoder = passwordEncoder;}@GetMappingpublic String registerForm() {return "registration";}public String processRegistration(RegistrationForm form) {userRepo.save(form.toUser(passwordEncoder));return "redirct:/login";}
}
注册表单视图的Thymeleaf模版registration.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Taco Cloud</title>
</head>
<body><h1>Register</h1><img alt="" th:src="@{images/TacoCloud.png}"><form method="post" th:action="@{/register}" id="registerForm"><label for="username">Username:</label><input type="text" name="username"><br><label for="password">Password:</label><input type="password" name="password"><br><label for="confirm">Confirm password:</label><input type="password" name="confirm"><br><label for="fullname">Full name:</label><input type="text" name="fullname"><br><label for="street">Street:</label><input type="text" name="street"><br><label for="city">City:</label><input type="text" name="city"><br><label for="state">State:</label><input type="text" name="state"><br><label for="zip">Zip:</label><input type="text" name="zip"><br><label for="phone">Phone:</label><input type="text" name="phone"><br><input type="submit" value="Register"></form>
</body>
</html>

应用已经有了完整用户注册和认证功能,启动还是无法进入注册页面,因为所有请求都需要认证。我们看一下Web请求如何被拦截和保护的。

5.3 保护Web请求

应用的安全需求是:用户在设计taco和提交订单之前,必须要经过认证,但主页、登录页和注册页应该对未认证的用户开发。

HttpSecurity可以配置很多功能,其中包括:

  • 要求在某个请求提供服务之前,满足特定的安全条件。
  • 配置自定义的登录页。
  • 使用户能够退出应用。
  • 预防跨站请求伪造。

配置HttpSecurity最常见的需求就是拦截请求以确保用户具备适当的权限。

5.3.1 保护请求

确保只有认证过的用户才能发起对"/design"和"/orders"的请求,而其他请求对所有用户均可用,如下配置就能实现这一点:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {return http.cors(cors -> cors.configure(http)).authorizeHttpRequests(authorize -> authorize.requestMatchers("/design","/orders").hasRole("USER").requestMatchers("/","/**").permitAll()).formLogin(form -> form.loginPage("/login")).logout(logout -> logout.logoutUrl("/logout").permitAll()).build();
}

具备ROLE_USER权限的用户才能访问"/design"和"/orders"。

其他的所有请求允许所有用户访问。

规则顺序很重要,前面的比后面的优先级高。

我用的是spring-security-config-6.4.2,规则和版本5的不同,具体API自己查吧。

可以用SpEL表达式来声明更丰富的安全规则,了解即可。

5.3.2 创建自定义的登录页

formLogin()方法告诉自定义登录页的路径,若没有经过认证并且需要登录,就会将用户重定向到该路径。

登录页很简单,只有一个视图没有其他东西,可以不写Controller,只要在WebConfig中将其声明为一个视图控制器,增加登录页面的视图控制器。

package tacos.web;import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class WebConfig implements WebMvcConfigurer {@Overridepublic void addViewControllers(ViewControllerRegistry registry) {registry.addViewController("/").setViewName("home");registry.addViewController("/login");}}

新建login.html登录页的视图。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Taco Cloud</title>
</head>
<body><h1>Login</h1><img th:src="@{/images/TacoCloud.png}"><div th:if=${error}>无法登录,请检查你的用户名和密码是否正确!</div><p>还未注册,点击 <a th:href="@{/register}">这里</a>去注册!</p><form action="post" th:action="@{/login}" id="loginForm"><label for="username">用户名:</label><input type="text" name="username" id="username"><br><label for="password">密码:</label><input type="password" name="password" id=""password""><br><input type="submit" value="登录"></form>
</body>
</html>

默认情况下,会监听"/login"路径登录请求,用户名密码分别为username和password,这也是可以配置的。

.and()
.formLogin()
.loginPage("/login")
.loginProcessingUrl("/authenticate")
.usernameParameter("user")
.passwordParameter("pwd")

修改完就是,路径为"/authenticate",用户名密码为,user,pwd。

一般登录后导航到正在浏览的页面,如果直接访问登录页,导航至根路径,也就是主页,也可以修改默认的成功页,例如导航到"/design"。强制要求登录到这里的话,后面加true参数。

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {return http.cors(cors -> cors.configure(http)).authorizeHttpRequests(authorize -> authorize.requestMatchers("/design","/orders").hasRole("USER").requestMatchers("/","/**").permitAll()).formLogin(form -> form.loginPage("/login").defaultSuccessUrl("/design",true)).logout(logout -> logout.logoutUrl("/logout").permitAll()).build();
}

上面的代码要和项目中的代码整体整理一下!!!

5.3.3 启用第三方认证

你可能在自己喜欢的Web站点上见过"使用微信登录",“使用QQ登录”,"使用支付宝登录"类似的内容。这种方式能让用户避免在Web站点特定的登录页上自己输入凭证信息。

这种认证基于OAuth2或OpenID Connect(OIDC)。

OAuth2是一个授权规范,用来通过第三方网站实现认证功能,OpenID Connect是另一个基于OAuth2的安全规范,用户规范化第三方认证过程中发生的交互。

自动或手动添加OAuth2客户端的starter依赖。

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>

配置文件中设置通用属性

# 配置 OAuth2 客户端相关信息
spring.security.oauth2.client.registration.wechat.client-id=your_appid
spring.security.oauth2.client.registration.wechat.client-secret=your_appsecret
spring.security.oauth2.client.registration.wechat.client-name=微信登录
spring.security.oauth2.client.registration.wechat.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.wechat.redirect-uri={baseUrl}/login/oauth2/code/{registrationId}
spring.security.oauth2.client.registration.wechat.scope=snsapi_userinfo# 配置 OAuth2 提供者相关信息
spring.security.oauth2.client.provider.wechat.authorization-uri=https://open.weixin.qq.com/connect/qrconnect
spring.security.oauth2.client.provider.wechat.token-uri=https://api.weixin.qq.com/sns/oauth2/access_token
spring.security.oauth2.client.provider.wechat.user-info-uri=https://api.weixin.qq.com/sns/userinfo
spring.security.oauth2.client.provider.wechat.user-name-attribute=unionid

客户端ID和secret是用来标识我们的应用在微信中的凭证。

可以在微信的开发者网站新建应用来获取客户端ID和secret。

scope属性可以用来指定应用的权限范围,案例中获取用户的基本信息。

用户尝试访问需要认证的页面时,他们的浏览器会被重定向到微信,若还没有登录微信,将会看到微信登录页面,他们会被要求根据请求的权限范围对我们的应用程序授权,最后,用户被重定向到我们的应用程序,此时,他们完成了认证。

通过SecurityFilterChain来定义安全配置,还需要启用OAuth2登录。

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {return http.cors(cors -> cors.configure(http)).authorizeHttpRequests(authorize -> authorize.requestMatchers("/design","/orders").hasRole("USER").requestMatchers("/","/**").permitAll()).formLogin(form -> form.loginPage("/login").defaultSuccessUrl("/design",true)).logout(logout -> logout.logoutUrl("/logout"))//.oauth2Login(t -> t.and()).build();
}

也可以配置传统的通过用户名密码登录,可以在配置中指定登录页,或提供一个微信登录页面链接a,退出也同样重要,在HttpSecurity对象上调用logout方法。

整体略。

5.3.4 防止跨站请求伪造

跨站请求伪造(Cross-Site Request Forgery,CSRF)是一种常见的安全攻击。

它会让用户在一个恶意的Web页面上填写信息,然后自动的将表单以攻击受害者的身份提交到另外一个应用上。

为了防止此类攻击,展现表单的时候生成一个CSRF令牌(token),放到隐藏域中临时存储起来,以便后续服务器上使用。

Spring Security提供了内置的CSRF保护,默认启用,唯一要做的就是每个表单有一个名为"_csrf"的字段,它会持有CSRF令牌。

模版中会:

5.4 实现方法级别的安全

比如删除所有订单操作,只有管理员才有权限删除。

可以在配置类中添加对应权限,但是其他控制类也需要这样的操作,为了方便,启用方法上的安全防护。

@PreAuthorize(“hasRole(‘ADMIN’)”)

安全配置类上添加@EnableGlobalMethodSecurity使上面注解生效。

假设根据ID获取订单方法,想限制这个方法,可以用@PostAuthorize注解。

5.5 了解用户是谁

@AuthenticationPrincipal

想详细了解去看下面的书:

  • 入门优先:从《Spring Security实战》或《Spring Boot Up and Running》开始,快速上手。
  • 深入协议:先读《OAuth 2 in Action》,再结合《Pro Spring Security》实践。
  • 全面掌握:《Spring Security in Action》是当前最系统的选择,覆盖现代安全场景(如微服务、响应式)

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

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

相关文章

SQLMesh 系列教程7- 详解 seed 模型

SQLMesh 是一个强大的数据建模和管道管理工具&#xff0c;允许用户通过 SQL 语句定义数据模型并进行版本控制。Seed 模型是 SQLMesh 中的一种特殊模型&#xff0c;主要用于初始化和填充基础数据集。它通常包含静态数据&#xff0c;如参考数据和配置数据&#xff0c;旨在为后续的…

【JavaEE】-- 多线程(初阶)2

文章目录 3.线程的状态3.1观察线程的所有状态3.2线程状态和状态转移的意义 4.多线程带来的的风险-线程安全 (重点)4.1观察线程不安全4.2 线程不安全的原因4.2.1 线程调度是随机的4.2.2 修改共享数据4.2.3 原子性4.2.4 内存可见性4.2.5 指令重排序 4.3解决之前的线程不安全问题 …

安卓系统远程控制电脑方法,手机远控教程,ToDesk工具

不知道大家有没有觉得手机、平板虽然很好用&#xff0c;却也仍存在有很多替代不了电脑的地方。就比如说撰写文档、做数据报表啥的就不如PC端操作般方便&#xff0c;就跟别说PS修图、AE视频剪辑等需高性能设备来带动才易用的了。 好在也是有对策可解决&#xff0c;装个ToDesk远程…

机器学习(李宏毅)——RL(强化学习)

一、前言 本文章作为学习2023年《李宏毅机器学习课程》的笔记&#xff0c;感谢台湾大学李宏毅教授的课程&#xff0c;respect&#xff01;&#xff01;&#xff01; 二、大纲 What is RL&#xff1f;Three steps in MLPolicy GradientActor-CriticReward Shaping 三、What …

【Go】Go wire 依赖注入

1. wire 简介 wire 是一个 Golang 的依赖注入框架&#xff08;类比 Spring 框架提供的依赖注入功能&#xff09; ⭐ 官方文档&#xff1a;https://github.com/google/wire 这里关乎到编程世界当中一条好用的设计原则&#xff1a;A用到了B&#xff0c;那么B一定是通过依赖注入的…

《动手学机器人学》笔记

目录 0.介绍1.概述&#xff5c;空间位置、姿态的描述&#xff08;33&#xff09;&#xff5c;《动手学机器人学》2.&#xff08;2&#xff09;-Robotics Toolbox①&#xff08;V10.4&#xff09;3.齐次坐标与变换矩阵4.一般形式的旋转变换矩阵5.&#xff08;轴角法&#xff09;…

【蓝桥杯单片机】第十三届省赛第二场

一、真题 二、模块构建 1.编写初始化函数(init.c) void Cls_Peripheral(void); 关闭led led对应的锁存器由Y4C控制关闭蜂鸣器和继电器 2.编写LED函数&#xff08;led.c&#xff09; void Led_Disp(unsigned char ucLed); 将ucLed取反的值赋给P0 开启锁存器 关闭锁存…

大语言模型基础

简介 AI大模型是“人工智能预训练大模型”的简称&#xff0c;包含了“预训练”和“大模型”两层含义&#xff0c;二者结合产生了一种新的人工智能模式&#xff0c;即模型在大规模数据集上完成了预训练后无需微调&#xff0c;或仅需要少量数据的微调&#xff0c;就能直接支撑各…

java Web

1.JavaWeb开发 前面的学习javase开发&#xff0c;而javaweb开发需要服务器和网页。 具备: java mysql jdbc htmlcssjs。 web服务器: tomcat服务器. 部署项目。 https://tomcat.apache.org/download-80.cgi 解压软件压缩包即可 不要放在中文目录和特殊符号的目录下 启动tomcat服…

SOME/IP--协议英文原文讲解12(完结)

前言 SOME/IP协议越来越多的用于汽车电子行业中&#xff0c;关于协议详细完全的中文资料却没有&#xff0c;所以我将结合工作经验并对照英文原版协议做一系列的文章。基本分三大块&#xff1a; 1. SOME/IP协议讲解 2. SOME/IP-SD协议讲解 3. python/C举例调试讲解 4.3 Compa…

光明谷推出AT指令版本的蓝牙音箱SOC 开启便捷智能音频开发新体验

前言 在蓝牙音箱市场竞争日益激烈的当下&#xff0c;开发一款性能卓越且易于上手的蓝牙音箱&#xff0c;成为众多厂商追求的目标。而光明谷科技有限公司推出的 AT 指令版本的蓝牙音箱 SOC&#xff0c;无疑为行业带来了全新的解决方案&#xff0c;以其诸多独特卖点&#xff0c;迅…

STM32——HAL库开发笔记22(定时器3—呼吸灯实验)(参考来源:b站铁头山羊)

本文利用前几节所学知识来实现一个呼吸灯实验&#xff1a;两颗led灯交替呼吸。 一、STM32CubeMX配置 step1&#xff1a;配置调试接口 step2&#xff1a;配置定时器 定时器1位于APB2总线上&#xff0c;如上图所示。 step3&#xff1a;配置时基单元 按照下图配置 时钟来源配置…

医疗AI领域中GPU集群训练的关键技术与实践经验探究(下)

五、医疗 AI 中 GPU 集群架构设计 5.1 混合架构设计 5.1.1 参数服务器与 AllReduce 融合 在医疗 AI 的 GPU 集群训练中,混合架构设计将参数服务器(Parameter Server)与 AllReduce 相结合,能够充分发挥两者的优势,提升训练效率和模型性能。这种融合架构的设计核心在于根…

修改Ubuntu系统用户密码(root密码)的方法

本文介绍在Linux系统的Ubuntu电脑中&#xff0c;修改账户用户密码&#xff08;同时也修改了root用户密码&#xff09;的方法。 首先&#xff0c;如果此时处于登录页面&#xff08;也就是意识到自己忘记密码的那个页面&#xff09;&#xff0c;就先点击右上角的关闭按钮&#xf…

【清华大学】DeepSeek从入门到精通系列教程 第五版:DeepSeek与AI幻觉 pdf文档下载

【清华大学】DeepSeek使用教程系列之DeepSeek与AI幻觉 pdf文件完整版下载 https://pan.baidu.com/s/17evZMjiGNR0hun2jVdAkbg?pwd1234 提取码: 1234 或 https://pan.quark.cn/s/160d03fa907f DeepSeek与AI幻觉内容摘要 一、‌定义与类型‌ AI幻觉指模型生成与事实不符…

记录此刻:历时两月,初步实现基于FPGA的NVMe SSD固态硬盘存储控制器设计!

背景 为满足实验室横向项目需求&#xff0c;在2024年12月中下旬导师提出基于FPGA的NVMe SSD控制器研发项目。项目核心目标为&#xff1a;通过PCIe 3.0 x4接口实现单盘3000MB/s的持续读取速率。 实现过程 调研 花了半个月的时间查阅了一些使用FPGA实现NVME SSD控制器的论文、…

【Linux】进程

1. 多任务&#xff08;并发&#xff09; 让系统具备同时处理多个任务的能力。 2. 如何实现多任务 1&#xff09;进程 2&#xff09;线程 3. 进程 正在执行的程序&#xff0c;需要消耗内存和cpu&#xff0c; 一个动态执行的过程。 进程生存周期&#xff1a; …

3D模型在线转换工具:轻松实现3DM转OBJ

3D模型在线转换是一款功能强大的在线工具&#xff0c;支持多种3D模型格式的在线预览和互转。无论是工业设计、建筑设计&#xff0c;还是数字艺术领域&#xff0c;这款工具都能满足您的需求。 3DM与OBJ格式简介 3DM格式&#xff1a;3DM是一种广泛应用于三维建模的文件格式&…

Docker安装Open WebUI教程

Open WebUI 是一个可扩展、功能丰富且用户友好的自托管 AI 平台,旨在完全离线运行。它支持各种LLM运行器,如 Ollama 和 OpenAI 兼容的 API,并内置了 RAG 推理引擎,使其成为强大的 AI 部署解决方案。 官网文档地址:https://docs.openwebui.com/ 一、拉取镜像 下载的镜像包比…

VSCode集成deepseek使用介绍(Visual Studio Code)

VSCode集成deepseek使用介绍&#xff08;Visual Studio Code&#xff09; 1. 简介 随着AI辅助编程工具的快速发展&#xff0c;VSCode作为一款轻量级、高度可扩展的代码编辑器&#xff0c;已成为开发者首选的工具之一。DeepSeek作为AI模型&#xff0c;结合Roo Code插件&#x…