news 2026/10/20 10:21:14

.NET6 WebAPI + SqlServer + JWT:从零搭建带鉴权的增删改查服务

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
.NET6 WebAPI + SqlServer + JWT:从零搭建带鉴权的增删改查服务

简介:本资源是一套基于 .NET6 构建的 Web API 实战示例,面向具备一定 C# 基础、希望掌握 ASP.NET Core 后端开发的开发者,重点演示如何结合 SQL Server 与 JWT 完成增删改查及身份验证。项目涵盖 Web API 接口设计、Swagger 交互式文档、Entity Framework Core 数据库迁移、JWT 无状态鉴权、全局异常处理与错误日志、RESTful 设计规范及 HTTPS 安全传输等关键知识点,并涉及 CI/CD 流程思路,适合作为学习 .NET6 全栈接口开发的参考案例。压缩包共 665 个文件,以 dll 依赖库、cs 源码、pdb 调试符号、json 配置、csproj 项目文件及少量 exe、sln 解决方案为主,整体约 34.81MB,目录按 Model、Service、BLL 等分层组织,便于对照阅读。目前已有 1060 人学习下载,读者可借此理解从数据库交互到权限控制的完整链路,快速上手企业级 Web 服务搭建。

1. 从一张“能跑通”的接口清单说起

很多团队在起步一个后台服务时,最先卡住的不是业务逻辑,而是“怎么让一套 .NET6 WebAPI 用 SqlServer 存数据、用 JWT 管住谁能调”。标题里的三个词——.NET6 WebAPI、SqlServer、JWT——恰好对应了服务端最基础的三件事:宿主框架、持久化、鉴权。把这三件事串成一条增删改查的闭环,是绝大多数管理后台、内部工具、移动端后端的最小可用形态。

我见过不少项目,接口能返回数据,但 Token 一过期就整站 401,或者删改接口谁都能调。问题不在框架,而在没把“认证”和“授权”分开设计。这篇笔记就按我实际搭一套最小服务的顺序走:先定项目骨架和依赖,再落 SqlServer 的实体与迁移,接着把 JWT 的签发与校验写死,最后用一组受保护的增删改查接口验证整条链路。适合刚接触 .NET6 的后端,也适合从 .NET Framework 迁过来、想看清 JWT 落地细节的人。

2. 项目骨架与依赖:先把“能编译”这件事做扎实

2.1 为什么选 .NET6 而不是更早的版本

.NET6 是长期支持版本,WebAPI 模板默认走最小宿主模型,Program.cs里用WebApplication.CreateBuilder就能把配置、日志、依赖注入一次性挂上。相比 .NET Core 3.1,它在System.IdentityModel.Tokens.Jwt和Microsoft.EntityFrameworkCore.SqlServer上的包版本更统一,不会出现运行时找不到程序集的玄学问题。我一般会先确认本机 SDK 版本,再建项目,避免模板生成的 TargetFramework 和实际 SDK 对不上。

# 确认本机 .NET SDK 版本,.NET6 对应 6.x dotnet --list-sdks # 新建 WebAPI 项目,指定框架为 net6.0 dotnet new webapi -n DemoApi -f net6.0 # 进入项目目录 cd DemoApi

dotnet new webapi会生成一个带 WeatherForecast 示例的控制器,这个示例可以直接删掉,它只是模板占位。-f net6.0明确锁定框架,防止本机装了更高版本 SDK 时默认生成 net7 或 net8 的工程。建完先dotnet build跑一次,确认模板本身能编译,再动任何代码。

2.2 三个必须装的 NuGet 包

增删改查加 JWT,最少需要三个包:EF Core 的 SqlServer 提供程序、JWT 的生成与校验库、以及 Swagger 在带鉴权时的 UI 支持。我习惯用命令行装,版本让 NuGet 自己解析到与 net6.0 兼容的最新稳定版。

# EF Core 的 SqlServer 驱动,负责连库和迁移 dotnet add package Microsoft.EntityFrameworkCore.SqlServer # EF Core 设计时工具,用于执行迁移命令 dotnet add package Microsoft.EntityFrameworkCore.Design # JWT 的生成与校验 dotnet add package System.IdentityModel.Tokens.Jwt # Swagger 的 JWT 支持,方便在 UI 里填 Token dotnet add package Swashbuckle.AspNetCore

Microsoft.EntityFrameworkCore.Design是设计时包,只在执行dotnet ef命令时需要,运行时不会加载。System.IdentityModel.Tokens.Jwt负责把 Claims 编码成 Token,也负责反向解析。Swashbuckle 默认模板里已经带了,但如果你手动建的空项目,需要补上,否则没有接口文档页,调试时只能靠 Postman。

提示:装包时如果提示版本冲突,优先看Microsoft.EntityFrameworkCore.SqlServer的主版本是否和Microsoft.EntityFrameworkCore.Design一致,两者必须同主版本,否则迁移命令会报“找不到设计时服务”。

2.3 目录结构怎么分才不返工

我见过把实体、上下文、控制器全塞在根目录的项目,后期加一个功能要翻半天。最小服务也建议按职责分四个文件夹:Models放实体和 DTO,Data放 DbContext,Services放 JWT 签发逻辑,Controllers放接口。这个结构不重,但能让后面每一步都有明确落点。

DemoApi/ ├── Controllers/ │ └── UsersController.cs ├── Data/ │ └── AppDbContext.cs ├── Models/ │ ├── User.cs │ └── LoginRequest.cs ├── Services/ │ └── TokenService.cs ├── appsettings.json └── Program.cs

Models里实体和 DTO 可以放一起,但建议用不同后缀区分,比如User是数据库实体,LoginRequest是登录入参。Data只放 DbContext 和迁移文件。Services里放不依赖 HTTP 上下文的纯逻辑,TokenService 就是典型。控制器只做参数校验和调用,不写业务细节。

3. SqlServer 落库:实体、上下文与迁移的完整链路

3.1 实体设计:主键、时间戳和密码字段怎么定

增删改查的“增”和“改”最终都落到表结构上。用户表最少要有自增主键、唯一用户名、密码哈希、创建时间。密码绝对不能存明文,我一般用 BCrypt 或 PBKDF2,这里为了聚焦 JWT,先用一个占位哈希字段,实际项目必须换成真正的哈希库。

// Models/User.cs using System.ComponentModel.DataAnnotations; namespace DemoApi.Models; public class User { [Key] public int Id { get; set; } [Required] [MaxLength(50)] public string UserName { get; set; } = string.Empty; // 实际项目存 BCrypt 哈希,这里用字符串占位 [Required] public string PasswordHash { get; set; } = string.Empty; public DateTime CreatedAt { get; set; } = DateTime.UtcNow; }

[Key]标记主键,EF Core 默认会把Id识别为自增主键,显式写出来是为了后面换主键类型时不遗漏。CreatedAt用DateTime.UtcNow而不是Now,避免服务器时区变化导致排序错乱。PasswordHash字段长度不设MaxLength,因为不同哈希算法输出长度不同,设短了会截断。

3.2 DbContext 与连接字符串的写法

DbContext 是 EF Core 和数据库之间的桥。构造函数注入DbContextOptions,OnModelCreating里可以加唯一索引,保证用户名不重复。连接字符串放appsettings.json,不要硬编码在代码里。

// Data/AppDbContext.cs using DemoApi.Models; using Microsoft.EntityFrameworkCore; namespace DemoApi.Data; public class AppDbContext : DbContext { public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { } public DbSet<User> Users => Set<User>(); protected override void OnModelCreating(ModelBuilder modelBuilder) { // 用户名唯一索引,防止重复注册 modelBuilder.Entity<User>() .HasIndex(u => u.UserName) .IsUnique(); } }

DbSet<User> Users用表达式体=> Set<User>()是 .NET6 的推荐写法,比字段声明更简洁。HasIndex加IsUnique会在数据库层生成唯一约束,比在应用层查重更可靠,并发插入时不会出现两个同名用户。

// appsettings.json 片段 { "ConnectionStrings": { "Default": "Server=localhost;Database=DemoDb;Trusted_Connection=True;TrustServerCertificate=True;" }, "Jwt": { "Key": "请替换为至少32位的随机字符串用于签名", "Issuer": "DemoApi", "Audience": "DemoClient", "ExpireMinutes": 60 } }

Trusted_Connection=True走 Windows 集成认证,本地开发最省事。如果 SqlServer 装在容器里或用 SQL 账号,换成User Id=...;Password=...。TrustServerCertificate=True在本地自签证书时避免握手失败。Jwt.Key必须够长,HMAC-SHA256 要求密钥至少 256 位,也就是 32 个字符以上,短了会在签发时抛异常。

3.3 迁移命令与数据库生成

实体和上下文写完,用 EF Core 迁移把表建出来。迁移命令要在项目根目录执行,且项目里必须有Microsoft.EntityFrameworkCore.Design。

# 生成迁移文件,名称用 AddUsers 描述本次变更 dotnet ef migrations add AddUsers # 把迁移应用到数据库,自动建库建表 dotnet ef database update

migrations add会在项目下生成Migrations文件夹,里面是 C# 代码,记录了本次表结构变更。database update会连到连接字符串指定的 SqlServer,如果数据库不存在会先建库。执行前确认 SqlServer 服务已启动,否则会报“无法连接”。如果报“找不到 dotnet ef”,先执行dotnet tool install --global dotnet-ef安装全局工具。

注意:迁移文件要提交到版本控制,它是数据库结构的唯一真相。不要手动改数据库表结构,否则下次迁移会和实际结构对不上,出现“模型有变更但迁移没生成”的假象。

3.4 在 Program.cs 里注册 DbContext

.NET6 的Program.cs是顶层语句,注册服务直接写在builder.Services上。DbContext 默认注册为 Scoped,每个请求一个实例,适合 WebAPI。

// Program.cs 片段 using DemoApi.Data; using Microsoft.EntityFrameworkCore; var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers(); builder.Services.AddDbContext<AppDbContext>(options => options.UseSqlServer(builder.Configuration.GetConnectionString("Default"))); var app = builder.Build(); app.MapControllers(); app.Run();

AddDbContext的第二个参数是配置委托,UseSqlServer从配置里读连接字符串。GetConnectionString("Default")对应appsettings.json里ConnectionStrings:Default的值。如果读出来是 null,检查 json 层级和键名大小写,配置系统默认不区分大小写,但键名拼错会静默返回 null。

4. JWT 签发与校验:把“谁能调”这件事写死

4.1 JWT 的三段结构和 Claims 放什么

JWT 由 Header、Payload、Signature 三段用点号连接。Header 声明算法,Payload 放 Claims,Signature 用密钥对前两段签名。服务端校验时重新计算签名,对不上就拒绝。Claims 里我一般放用户 Id、用户名和过期时间,不放敏感信息,因为 Payload 只是 Base64 编码,不是加密。

// Services/TokenService.cs using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using System.Text; using DemoApi.Models; using Microsoft.IdentityModel.Tokens; namespace DemoApi.Services; public class TokenService { private readonly IConfiguration _config; public TokenService(IConfiguration config) => _config = config; public string CreateToken(User user) { // 从配置读密钥、签发者、受众 var key = new SymmetricSecurityKey( Encoding.UTF8.GetBytes(_config["Jwt:Key"]!)); var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); // Claims 放用户标识,不放密码 var claims = new[] { new Claim(JwtRegisteredClaimNames.Sub, user.Id.ToString()), new Claim(JwtRegisteredClaimNames.UniqueName, user.UserName), new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()) }; var token = new JwtSecurityToken( issuer: _config["Jwt:Issuer"], audience: _config["Jwt:Audience"], claims: claims, expires: DateTime.UtcNow.AddMinutes( double.Parse(_config["Jwt:ExpireMinutes"]!)), signingCredentials: creds); return new JwtSecurityTokenHandler().WriteToken(token); } }

SymmetricSecurityKey用同一个密钥签名和校验,适合单体服务。Jti是 Token 唯一标识,后面做黑名单或防重放时用得上。expires用 UTC 时间,和CreatedAt保持一致。WriteToken把对象序列化成三段字符串,返回给客户端。

4.2 在 Program.cs 里配置认证与授权中间件

认证是“你是谁”,授权是“你能不能调”。JWT 的校验参数必须和签发时完全一致,Issuer、Audience、Key 任何一项不同都会导致 401。

// Program.cs 片段,接在 AddControllers 之后 using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.IdentityModel.Tokens; using System.Text; builder.Services.AddScoped<TokenService>(); builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey = true, ValidIssuer = builder.Configuration["Jwt:Issuer"], ValidAudience = builder.Configuration["Jwt:Audience"], IssuerSigningKey = new SymmetricSecurityKey( Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"]!)) }; }); builder.Services.AddAuthorization(); var app = builder.Build(); app.UseAuthentication(); // 必须在 UseAuthorization 之前 app.UseAuthorization();

ValidateLifetime = true会检查exp字段,过期直接 401。UseAuthentication负责解析 Token 并填充HttpContext.User,UseAuthorization负责检查[Authorize]特性。顺序反了会导致授权时拿不到用户身份,表现为所有带[Authorize]的接口都 401。

4.3 登录接口:签发 Token 的最小闭环

登录接口接收用户名密码,查库比对哈希,成功则返回 Token。这里为了聚焦流程,密码比对先用明文占位,实际必须换成哈希校验。

// Controllers/AuthController.cs using DemoApi.Data; using DemoApi.Models; using DemoApi.Services; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; namespace DemoApi.Controllers; [ApiController] [Route("api/[controller]")] public class AuthController : ControllerBase { private readonly AppDbContext _db; private readonly TokenService _tokenService; public AuthController(AppDbContext db, TokenService tokenService) { _db = db; _tokenService = tokenService; } [HttpPost("login")] public async Task<IActionResult> Login([FromBody] LoginRequest req) { var user = await _db.Users .FirstOrDefaultAsync(u => u.UserName == req.UserName); // 实际项目用 BCrypt.Verify 比对哈希 if (user == null || user.PasswordHash != req.Password) return Unauthorized("用户名或密码错误"); var token = _tokenService.CreateToken(user); return Ok(new { token }); } }

[FromBody]让框架从请求体反序列化 JSON。FirstOrDefaultAsync是异步查询,避免阻塞线程。返回Unauthorized时不要区分“用户不存在”和“密码错误”,统一提示,防止攻击者枚举用户名。Token 放在响应体的token字段,客户端后续请求放在Authorization: Bearer <token>头里。

4.4 受保护的增删改查接口

增删改查四个动作分别对应 POST、GET、PUT、DELETE。给控制器加[Authorize],整个控制器下的接口都需要有效 Token。

// Controllers/UsersController.cs using DemoApi.Data; using DemoApi.Models; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; namespace DemoApi.Controllers; [ApiController] [Route("api/[controller]")] [Authorize] public class UsersController : ControllerBase { private readonly AppDbContext _db; public UsersController(AppDbContext db) => _db = db; // 查:列表 [HttpGet] public async Task<IActionResult> GetAll() => Ok(await _db.Users.AsNoTracking().ToListAsync()); // 查:单个 [HttpGet("{id}")] public async Task<IActionResult> GetById(int id) { var user = await _db.Users.FindAsync(id); return user == null ? NotFound() : Ok(user); } // 增 [HttpPost] public async Task<IActionResult> Create(User user) { _db.Users.Add(user); await _db.SaveChangesAsync(); return CreatedAtAction(nameof(GetById), new { id = user.Id }, user); } // 改 [HttpPut("{id}")] public async Task<IActionResult> Update(int id, User input) { if (id != input.Id) return BadRequest(); _db.Entry(input).State = EntityState.Modified; await _db.SaveChangesAsync(); return NoContent(); } // 删 [HttpDelete("{id}")] public async Task<IActionResult> Delete(int id) { var user = await _db.Users.FindAsync(id); if (user == null) return NotFound(); _db.Users.Remove(user); await _db.SaveChangesAsync(); return NoContent(); } }

AsNoTracking用于只读查询,不跟踪实体变化,减少内存开销。CreatedAtAction返回 201 并在 Location 头里带上新资源地址。Update里先比对路由 id 和实体 id,防止改错对象。EntityState.Modified让 EF Core 生成 UPDATE 语句,但会更新所有字段,如果只想改部分字段,应先查再改。

提示:[Authorize]加在控制器上,所有接口都需要 Token。如果某个接口要匿名访问,单独加[AllowAnonymous],比如登录接口所在的控制器就不加[Authorize]。

5. 避坑与排查:那些让接口 401 和迁移失败的细节

5.1 现象:所有带 [Authorize] 的接口都返回 401,Token 明明没过期

原因通常是UseAuthentication和UseAuthorization顺序反了,或者TokenValidationParameters里的 Issuer、Audience 和签发时不一致。还有一种情况是Jwt:Key在签发和校验时读到了不同的值,比如一个从环境变量读、一个从 json 读。

解决:先确认Program.cs里UseAuthentication在UseAuthorization之前。再打印签发和校验时用的 Issuer、Audience、Key 长度,逐项比对。如果用了环境变量覆盖配置,注意Jwt__Key双下划线是层级分隔符,写成Jwt:Key在环境变量里不生效。

5.2 现象:dotnet ef migrations add 报“无法创建类型为 DbContext 的对象”

原因是Program.cs里注册 DbContext 时用了运行时才有的配置,设计时工具无法构造。比如连接字符串从HttpContext读,或者 DbContext 构造函数有额外参数没在 DI 里注册。

解决:确保AddDbContext的配置只依赖IConfiguration,不依赖请求上下文。如果 DbContext 有额外构造函数参数,在设计时工厂里显式提供,或者把参数改成从配置读。最省事的做法是让 DbContext 只有一个DbContextOptions参数。

5.3 现象:迁移执行成功,但表里没有唯一索引

原因是OnModelCreating里加了索引,但迁移文件是在加索引之前生成的,database update只应用已有迁移,不会重新扫描模型。

解决:加完索引后重新执行dotnet ef migrations add AddUniqueIndex,再database update。不要手动去数据库加索引,否则模型和数据库不一致,下次迁移会生成重复索引或报冲突。

5.4 现象:PUT 接口返回 400,但请求体看起来没问题

原因是路由 id 和请求体里的 Id 不一致,代码里if (id != input.Id) return BadRequest()触发了。客户端可能只传了部分字段,input.Id默认是 0。

解决:要么在请求体里带上 Id,要么改成从路由 id 查实体再更新字段。我一般推荐后者,先FindAsync查出实体,再逐字段赋值,避免客户端传空值覆盖数据库。

5.5 现象:Token 签发成功,但客户端带上后仍然 401,且没有任何错误信息

原因是客户端把 Token 放错了位置,比如放在查询字符串或自定义头里。JWT 默认从Authorization头读,格式必须是Bearer <token>,Bearer 和 token 之间有一个空格。

解决:用浏览器开发者工具或抓包看请求头,确认Authorization: Bearer eyJ...格式正确。如果用了 Swagger,在右上角 Authorize 按钮里填 Token 时不要自己加 Bearer 前缀,Swagger 会自动加。

6. 进阶:让这套骨架扛住真实项目的三个技巧

第一个技巧是给 Token 加刷新机制。访问 Token 设短一点,比如 15 分钟,另发一个刷新 Token 存库,过期后用刷新 Token 换新的访问 Token。这样即使访问 Token 泄露,窗口期也短。刷新 Token 要能撤销,存库时记一个Revoked字段,用户登出时置为 true。

第二个技巧是用策略授权替代角色硬编码。[Authorize(Roles = "Admin")]在角色少时够用,但角色一多就乱。改成[Authorize(Policy = "CanDeleteUser")],在AddAuthorization里注册策略,策略里可以组合角色、Claims 甚至查库判断。这样权限规则集中在一处,改起来不用翻每个控制器。

第三个技巧是给 SqlServer 加连接重试。网络抖动或数据库短暂不可用时,默认会直接抛异常。在UseSqlServer里加EnableRetryOnFailure,EF Core 会自动重试几次。

builder.Services.AddDbContext<AppDbContext>(options => options.UseSqlServer( builder.Configuration.GetConnectionString("Default"), sql => sql.EnableRetryOnFailure( maxRetryCount: 3, maxRetryDelay: TimeSpan.FromSeconds(5), errorNumbersToAdd: null)));

maxRetryCount是重试次数,maxRetryDelay是每次重试最大等待。这个配置对瞬时故障有效,但对连接字符串写错这种持续性错误没用,重试完还是会抛。我一般只在生产环境开,本地开发关掉,否则调试时看不到真实错误。

验证这套骨架是否真的可用,我习惯用两个动作:先用 Swagger 走一遍登录拿 Token,再带着 Token 调一遍增删改查,确认 401 和 200 的边界都对。然后把 Token 的过期时间改成 1 分钟,等它过期再调一次,确认返回 401 而不是 500。这两个动作能覆盖大部分配置错误。

我自己踩过最深的坑,是早期把Jwt:Key写在代码里,换环境时忘了改,结果测试环境的 Token 拿到生产环境校验不过,排查了半天才发现是密钥不一致。从那以后,所有和签名、连接相关的配置一律走配置文件或环境变量,代码里只留读取逻辑。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/20 10:20:43

微信小程序聊天页面接入大模型:流式输出与LLM对接实战

简介&#xff1a;这份资源是一套微信小程序AI聊天页面的完整前端源码&#xff0c;面向希望快速上手小程序对接大语言模型的开发者与学习者&#xff0c;尤其适合想体验AI对话能力、又不想从零搭建界面的初中级前端人员。压缩包共6个文件&#xff0c;约386KB&#xff0c;包含wxml…

作者头像 李华
网站建设 2026/10/16 14:43:58

containerd 2.x 对接 Harbor 私有仓库配置与排错指南

上个月接到一个“看起来很简单的”任务&#xff1a;一台 Ubuntu 24.04 上新装的 containerd 2.x&#xff0c;怎么把镜像推到内网的 Harbor 仓库里去。本以为是三分钟的事&#xff0c;结果一执行就报了一个非常经典的错误——harbor 推送失败&#xff0c;get "https://192.…

作者头像 李华
网站建设 2026/10/16 6:16:53

CORBA Explorer 实战:连接命名服务、调用接口与排障指南

简介&#xff1a;CORBA Explorer 是一款面向分布式中间件开发与测试人员的实用工具&#xff0c;主要用于辅助服务端接口调试、对象引用解析与通信信息验证&#xff0c;适合具备一定 CORBA 基础、需要排查 ORB 交互问题的工程师使用。压缩包共收录 538 个文件&#xff0c;整体约…

作者头像 李华
网站建设 2026/10/15 10:58:21

亚马逊退货率吃掉多少利润?4个关键指标+3类工具帮你算明白2026年亚马逊退货成本测算的测评维度与工具选型

一、先破三个误区&#xff1a;算不清退货账&#xff0c;往往卡在认知上 谈工具之前&#xff0c;先破除三个容易让卖家算不清退货账的认知误区。 误区一&#xff1a;退货成本等于退款金额。实际上&#xff0c;一笔FBA退货的真实成本远不止退回的那笔货款。退货处理费、往返运费…

作者头像 李华
网站建设 2026/10/14 16:14:23

单链表与双链表全解析:从指针原理到工程选型与代码实现

“单链表和双链表”这个题目&#xff0c;几乎是每个学编程的人都会遇到的第二个数据结构&#xff08;第一个当然是数组&#xff09;。很多人在这一步开始吃力&#xff1a;不是看不懂定义&#xff0c;而是边界条件一多就崩&#xff0c;指针指来指去把自己绕晕。其实链表并没有那…

作者头像 李华
网站建设 2026/10/20 3:31:45

用Rust构建MCP Server:让AI安全操作本地文件的实践指南

最近好几个朋友都在问我同一件事&#xff1a;怎么让AI助手安全地操作本地文件。有人图省事&#xff0c;直接把终端权限交给了Claude&#xff0c;结果AI不到十分钟就把环境变量改乱了。我的做法不一样&#xff0c;我把文件操作封装成了一个MCP server&#xff0c;让AI只能调用我…

作者头像 李华