SpringCloud Gateway OAuth2 统一认证:微服务网关层 JWT 校验与权限控制实战
简介这份资源是面向 Java 后端与微服务开发者的 SpringCloud Gateway OAuth2.0 JWT 认证授权实战源码适合正在搭建统一鉴权体系、需要打通网关层与资源服务权限校验的中高级开发者参考。项目以网关作为统一入口结合 OAuth2 授权服务器与 JWT 令牌完成用户身份认证、令牌签发与资源访问控制并借助 Redis 存储令牌、JDBC 持久化客户端与用户信息同时依赖 Nacos 做服务注册与配置管理覆盖认证服务、资源服务与用户信息查询等典型调用链路。压缩包共 270 个文件以 204 个 xml 配置、56 个 java 源码为主另含 yml、sql 脚本与少量图片整体约 340KB结构紧凑便于快速导入 IDE 阅读。目前已有 7162 人学习下载读者可据此理解过滤器、令牌服务、授权服务器配置与安全配置等核心模块的协作方式并在此基础上改造出符合自身业务的安全方案。1. 网关做认证这件事为什么我劝你别再每个服务写一遍去年帮一个团队排查线上问题六个微服务里五个都在自己的application.yml里配了同一套 JWT 校验逻辑结果其中一个服务因为依赖版本差了一个小版本解析 token 时对exp字段的处理不一致导致用户在 A 服务能正常访问、跳到 B 服务就被踢回登录页。这种每个服务各写一遍认证的架构在微服务数量超过三个之后基本就是灾难——密钥散落、逻辑漂移、改一处要发六个包。springcloud-gateway-oauth2这份源码包解决的正是这个痛点把 OAuth2.0 的令牌签发、JWT 的解析校验、以及基于角色的权限判断全部收敛到 SpringCloud Gateway 这一层。网关作为所有流量的唯一入口在请求转发到下游微服务之前就完成身份认证和授权决策下游服务只需要信任网关透传的用户信息不再关心 token 怎么来的、怎么验的。这套方案适合三类人正在做微服务拆分、被认证逻辑重复困扰的后端需要给现有系统加统一登录入口的架构同学以及想搞明白 OAuth2 密码模式、授权码模式在网关层到底怎么落地的一线开发。源码包里包含完整的网关配置、资源服务器配置、JWT 工具类和几个模拟业务服务拿来就能跑通登录拿 token → 带 token 访问 → 网关校验放行这条链路。下面我按实际拆包的顺序把关键配置和几个容易翻车的地方讲清楚。2. 拆开源码包网关、认证中心、资源服务到底怎么分工2.1 三个角色的职责边界这份源码的结构是典型的三角色模型理解它们各自管什么后面配参数才不会乱。网关gateway是唯一对外暴露的入口端口通常是 8080 或 9000。它承担两件事一是路由转发把/api/user/**转到用户服务、/api/order/**转到订单服务二是全局过滤器里的 token 校验请求进来先过GlobalFiltertoken 不合法直接返回 401根本不会打到下游。认证中心auth-server负责签发 token。用户拿用户名密码来换它验证通过后用 JWT 格式生成 access_token 返回。这个模块依赖 Spring Security OAuth2 的授权服务器能力密码模式下核心是TokenEndpoint那套流程。资源服务resource-server是真正干活的业务微服务。它们不直接面向公网只接受网关转发过来的请求。关键点是资源服务不再自己解析 token而是从请求头里读网关塞进去的用户信息比如X-User-Id、X-User-Roles。提示如果你的资源服务还能被外网直接访问那网关的认证就是纸糊的。生产环境务必让资源服务只监听内网地址或者用安全组限制来源。2.2 认证中心的核心配置先看认证中心怎么签发 JWT。源码里AuthorizationServerConfig这个类是整个签发流程的入口我把它精简成能直接抄的版本Configuration EnableAuthorizationServer public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { Autowired private AuthenticationManager authenticationManager; Autowired private JwtAccessTokenConverter jwtAccessTokenConverter; // 配置 token 的存储方式和签名 Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) { endpoints .authenticationManager(authenticationManager) // 密码模式必须显式注入 .accessTokenConverter(jwtAccessTokenConverter) // 用 JWT 而非默认的 UUID token .allowedTokenEndpointRequestMethods(HttpMethod.POST); } // 配置客户端信息谁有资格来申请 token Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory() .withClient(gateway-client) // 客户端 id .secret(passwordEncoder().encode(secret-123)) // 客户端密钥必须加密存储 .authorizedGrantTypes(password, refresh_token) .scopes(all) .accessTokenValiditySeconds(7200) // access_token 有效期 2 小时 .refreshTokenValiditySeconds(604800); // refresh_token 有效期 7 天 } }逻辑说明configure(AuthorizationServerEndpointsConfigurer)决定 token 怎么生成这里注入authenticationManager是因为密码模式需要它去校验用户名密码注入jwtAccessTokenConverter是把默认的随机字符串 token 换成自包含的 JWT。configure(ClientDetailsServiceConfigurer)决定谁能来申请 tokenwithClient和secret是客户端凭证authorizedGrantTypes里password支持用户名密码直接换 tokenrefresh_token支持过期后用刷新令牌续期。参数怎么改accessTokenValiditySeconds设太短用户频繁掉线设太长泄露风险大一般业务系统 2 小时是平衡点refreshTokenValiditySeconds可以给到 7 天甚至 30 天因为它只在换 token 时用一次。secret千万别用明文源码里用了passwordEncoder().encode()你换成自己的 BCrypt 加密串。2.3 JWT 签名密钥的配置JWT 的安全性全压在签名密钥上。源码里用对称加密HMAC做签名配置在JwtAccessTokenConverter的 bean 里Bean public JwtAccessTokenConverter jwtAccessTokenConverter() { JwtAccessTokenConverter converter new JwtAccessTokenConverter(); converter.setSigningKey(your-256-bit-secret-key-here-must-be-long); // 签名密钥 // 如果要在 token 里塞自定义信息比如用户 id converter.setAccessTokenConverter(new CustomAccessTokenConverter()); return converter; }逻辑说明setSigningKey设置的是 HMAC 的密钥认证中心用它签名网关用它验签两边必须完全一致。CustomAccessTokenConverter是自定义转换器用来往 JWT 的 payload 里加额外字段比如用户 id、角色列表。参数说明密钥长度建议 256 位以上32 个字符以上太短容易被暴力破解。对称加密的优点是配置简单、验签快缺点是认证中心和网关都得持有同一个密钥一旦泄露全线沦陷。如果对安全要求更高可以换成非对称加密RS256认证中心持私钥签名、网关持公钥验签这样网关即使被攻破也拿不到签名能力。源码默认给的是对称方案够用但不是最安全的。3. 网关层的 token 校验过滤器怎么写才不漏3.1 全局过滤器的执行时机网关校验 token 靠的是GlobalFilter。这里有个新手最容易踩的点过滤器有order值值越小越先执行。认证过滤器必须排在路由转发之前否则请求已经打到下游了才校验等于没校验。Component public class AuthGlobalFilter implements GlobalFilter, Ordered { Autowired private JwtUtil jwtUtil; // 白名单登录接口、健康检查等不需要 token private static final ListString WHITE_LIST Arrays.asList( /auth/login, /auth/refresh, /actuator/health ); Override public MonoVoid filter(ServerWebExchange exchange, GatewayFilterChain chain) { String path exchange.getRequest().getURI().getPath(); // 白名单直接放行 if (WHITE_LIST.stream().anyMatch(path::startsWith)) { return chain.filter(exchange); } // 从 Authorization 头里取 token String authHeader exchange.getRequest().getHeaders().getFirst(Authorization); if (authHeader null || !authHeader.startsWith(Bearer )) { return unauthorized(exchange, 缺少 token); } String token authHeader.substring(7); // 去掉 Bearer 前缀 try { Claims claims jwtUtil.parseToken(token); // 解析并验签 // 把用户信息塞进请求头透传给下游 ServerHttpRequest mutated exchange.getRequest().mutate() .header(X-User-Id, claims.getSubject()) .header(X-User-Roles, String.valueOf(claims.get(roles))) .build(); return chain.filter(exchange.mutate().request(mutated).build()); } catch (Exception e) { return unauthorized(exchange, token 无效或已过期); } } Override public int getOrder() { return -100; // 负数确保在路由转发过滤器之前执行 } private MonoVoid unauthorized(ServerWebExchange exchange, String msg) { exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED); exchange.getResponse().getHeaders().add(Content-Type, application/json;charsetUTF-8); byte[] bytes ({\code\:401,\msg\:\ msg \}).getBytes(StandardCharsets.UTF_8); return exchange.getResponse().writeWith(Mono.just(exchange.getResponse().bufferFactory().wrap(bytes))); } }逻辑说明filter方法先判断路径是否在白名单是就直接放行否则从Authorization头取 token格式必须是Bearer xxx解析成功后把用户 id 和角色写进新的请求头用mutate()构造新请求再转发这样下游服务就能直接读X-User-Id。getOrder返回 -100保证认证在路由之前。参数说明WHITE_LIST里放不需要认证的路径登录、刷新 token、健康检查是标配。X-User-Id和X-User-Roles这两个头名要和下游服务约定好别一边叫X-User-Id一边叫userId。unauthorized方法返回的是 JSON 而不是默认的 HTML 错误页前端处理起来更省事。3.2 路由配置与下游透传网关的路由配置决定了请求往哪转。源码里用的是 YAML 配置我把它整理成表格方便对照配置项作用示例值id路由唯一标识user-serviceuri下游服务地址lb://user-servicepredicates匹配条件Path/api/user/**filters路由级过滤器StripPrefix1lb://前缀表示走服务发现负载均衡需要配合注册中心使用。StripPrefix1表示转发时去掉路径的第一段比如/api/user/info转发到下游变成/user/info这个参数配错了会导致下游 404是高频翻车点。注意网关透传的X-User-Id这类头如果外部请求里也带了同名头会被恶意伪造。正确做法是在网关入口处先剥离所有X-开头的头再重新写入。源码里如果没做这一步记得自己补上。3.3 下游资源服务怎么读用户信息下游服务不再解析 token而是从请求头读。一个典型的 Controller 长这样RestController RequestMapping(/user) public class UserController { GetMapping(/info) public ResultUserVO info(RequestHeader(X-User-Id) String userId, RequestHeader(value X-User-Roles, required false) String roles) { // 直接用网关透传的用户 id 查数据不再碰 token UserVO vo userService.getById(userId); return Result.success(vo); } }逻辑说明RequestHeader直接读网关塞进来的头required false是因为有些接口可能允许匿名访问角色头可能为空。这样下游服务完全解耦了认证逻辑换认证方案时只改网关下游一行不动。参数说明如果下游服务也想做细粒度权限控制比如只有管理员能调某个接口可以在方法上加自定义注解配合拦截器读X-User-Roles判断。但记住核心的你是谁由网关保证你能不能干这个可以在下游做也可以统一在网关做看团队习惯。4. 避坑排查这五个地方我踩过你别再踩4.1 现象网关放行了但下游一直 401原因下游服务自己也引了 Spring Security 依赖默认开启了认证网关虽然透传了用户信息但下游的 Security 过滤器链不认识直接拦截。解决下游服务的SecurityConfig里要放行所有请求或者干脆不引 Security 依赖。配置成http.authorizeRequests().anyRequest().permitAll()把认证职责完全交给网关。这个坑我见过至少三个团队踩排查半天以为是 token 问题其实是下游自己又拦了一道。4.2 现象token 明明没过期网关却报验签失败原因认证中心和网关的签名密钥不一致。常见于配置从 YAML 挪到配置中心后一边读到了新值一边还是旧值或者密钥里有特殊字符YAML 解析时被转义了。解决把密钥抽成环境变量或配置中心统一管理两边引用同一个 key。排查时可以在网关打印一下实际用的密钥长度和认证中心对比。密钥里尽量只用字母数字避免$、#这类在 YAML 里有特殊含义的字符。4.3 现象跨域请求预检OPTIONS被网关拦截返回 401原因浏览器的 CORS 预检请求不带Authorization头网关的认证过滤器把它当未认证请求拦了。解决在WHITE_LIST里放行OPTIONS方法或者在过滤器里判断exchange.getRequest().getMethod() HttpMethod.OPTIONS时直接放行。同时网关要配好 CORS 相关响应头否则预检过了正式请求还是会被浏览器拦。4.4 现象刷新 token 后旧 token 还能用原因JWT 是无状态的签发后服务端不保存所以没法主动作废。用户刷新拿到新 token旧 token 在过期前依然有效。解决这是 JWT 的固有特性不是 bug。如果业务要求旧 token 立即失效得引入 Redis 黑名单签发时把 token 的 jti 存进 Redis 并设过期时间网关校验时查一下黑名单。代价是每次请求多一次 Redis 查询牺牲了 JWT 无状态的优势。源码默认没做黑名单按需自己加。4.5 现象网关转发后下游拿到的用户 id 是乱码原因请求头里塞了中文或特殊字符HTTP 头默认用 ISO-8859-1 编码中文会乱。解决用户 id 用数字或 UUID别用中文。角色信息如果非要用中文先 URL 编码再塞进头里下游解码。更稳妥的做法是头里只传 id角色信息让下游拿 id 去缓存或数据库查。5. 进阶把权限判断也搬到网关以及怎么验证整套链路5.1 网关层做基于角色的路由级鉴权基础版只校验 token 有效性进阶版可以在网关直接判断角色。比如订单管理接口只允许ROLE_ADMIN访问在过滤器里加一段// 在 token 解析成功后根据路径和角色做判断 String roles String.valueOf(claims.get(roles)); if (path.startsWith(/api/order/admin) !roles.contains(ROLE_ADMIN)) { return forbidden(exchange, 权限不足); }逻辑说明claims.get(roles)拿到的是签发时塞进 JWT 的角色列表contains判断是否包含所需角色。forbidden方法返回 403。这样权限规则集中在网关一处改规则不用动下游。参数说明角色字符串的格式要和签发端约定好是逗号分隔的ROLE_ADMIN,ROLE_USER还是 JSON 数组解析方式不同。规则多了之后建议抽成配置表别硬编码在过滤器里否则改一条规则要重新发网关包。5.2 用 curl 验证整条链路配置完别急着上前端先用命令行把链路走通。三步验证# 第一步用密码模式换 token curl -X POST http://localhost:9000/auth/oauth/token \ -d grant_typepasswordusernameadminpassword123456 \ -d client_idgateway-clientclient_secretsecret-123 # 返回里拿到 access_token # 第二步不带 token 访问应该返回 401 curl -i http://localhost:8080/api/user/info # 第三步带 token 访问应该返回 200 和用户数据 curl -i http://localhost:8080/api/user/info \ -H Authorization: Bearer 上一步拿到的access_token逻辑说明第一步验证认证中心能正常签发第二步验证网关的拦截生效第三步验证网关验签、透传、下游读取整条链路通畅。三步都过说明核心功能没问题。参数说明grant_typepassword对应密码模式client_id和client_secret要和认证中心配置的一致。如果第一步就失败先查认证中心的日志多半是客户端凭证或用户密码不对如果第二步返回 200说明白名单配错了把不该放行的路径放行了。5.3 一个我坚持了很多年的习惯每次改完网关的过滤器或密钥配置我一定先跑一遍上面这三条 curl再打开浏览器测。因为浏览器有缓存、有跨域、有各种预检出问题时你分不清是网关的锅还是浏览器的锅。命令行干净能快速定位问题出在哪一层。从那以后我每次动认证相关配置都强制走一遍换 token → 裸访问 → 带 token 访问这三步省下的排查时间比写这三行命令多得多。这套源码包的价值不在于代码多复杂而在于它把网关认证这条链路里该有的角色、该配的参数、该避的坑都摆出来了。你拿到后先按第 2 章把认证中心跑起来再用第 3 章的过滤器接上网关最后用第 5 章的 curl 验证基本一个下午能跑通。跑通之后再按自己的业务改白名单、加角色规则、决定要不要上 Redis 黑名单。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

Android四大组件:生命周期、启动模式与Binder调度全解析

Android四大组件:生命周期、启动模式与Binder调度全解析

1. 面试前先想清楚:Android为什么要设计四大组件前两天帮一个刚准备跳槽的朋友做了次模拟面试,聊到安卓四大组件,他背得滚瓜烂熟:Activity是界面、Service是后台、BroadcastReceiver是广播、ContentProvider是数据共享。但当我追了…

2026/10/12 16:46:40 阅读更多 →
南航编译原理课程设计:从词法分析到目标代码生成的完整实现指南

南航编译原理课程设计:从词法分析到目标代码生成的完整实现指南

简介:这份南京航空航天大学编译原理课程设计资源,面向计算机专业学生及需要完成编译原理课设的学习者,提供一套经检验无BUG的完整实现方案。压缩包共32个文件,约961KB,包含词法分析与语法分析两大模块:源码…

2026/10/12 16:46:40 阅读更多 →
计算机系统基础备考:进制转换与冯·诺依曼原理精讲

计算机系统基础备考:进制转换与冯·诺依曼原理精讲

简介:《第一章 计算机系统基础知识》演示文稿是软考初级程序员备考的核心资料,围绕考试大纲拆解计算机硬件与软件、数据表示及运算、冯诺依曼工作原理、指令系统、多媒体系统五大知识模块,重点突出,总结到位,既适合零基…

2026/10/12 16:46:40 阅读更多 →

最新新闻

卡尔曼滤波器从一维到EKF:机器人状态估计实战笔记

卡尔曼滤波器从一维到EKF:机器人状态估计实战笔记

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 18:56:01 阅读更多 →
POD-LSTM高维时间序列预测实战:降维+建模+可视化一站式指南

POD-LSTM高维时间序列预测实战:降维+建模+可视化一站式指南

简介:本资源是一份面向数据科学与工业智能领域工程师的POD-LSTM时间序列预测实战指南,聚焦高维多变量场景下的降维建模与可解释预测难题,适用于风电功率、设备状态监测、环境治理等实际业务场景。资源以1个146KB的docx文档形式交付&#xff0…

2026/10/13 18:56:01 阅读更多 →
LiteLLM:大模型多平台协议桥接与标准化调用实战指南

LiteLLM:大模型多平台协议桥接与标准化调用实战指南

1. 一个被严重低估的“协议翻译官”:LiteLLM到底在解决什么真问题?很多人第一次看到LiteLLM这个名字,下意识会以为它是又一个大模型训练框架、推理加速库,或者某种新型开源大模型。我最初也这么想——直到在某次跨平台AI服务集成中…

2026/10/13 18:56:01 阅读更多 →
华为AI DevSpace编译星闪WS63 SDK全攻略

华为AI DevSpace编译星闪WS63 SDK全攻略

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 18:56:01 阅读更多 →
Django+Vue小说推荐系统:从爬虫到可视化完整实现

Django+Vue小说推荐系统:从爬虫到可视化完整实现

看到标题里同时出现了“DjangoVue.js”“小说推荐系统”“小说可视化”“小说爬虫”“大数据毕业设计”这一串关键词,我基本能猜到你在选毕设题目时经历了什么——翻了一下午题目清单,要么是太简单拿不出手,要么是纯理论写到头秃,…

2026/10/13 18:56:01 阅读更多 →
静态时序分析实战:从时序弧到时钟约束的完整解读

静态时序分析实战:从时序弧到时钟约束的完整解读

说实话,静态时序分析这个系列写到第二篇,我想换个切入点。上一篇我们把STA是什么、为什么需要它、建立时间和保持时间的基本定义聊了一遍。但很多刚接触时序分析的同学,看完概念之后对着工具报出来的一屏时序报告,还是会有一种&qu…

2026/10/13 18:54:57 阅读更多 →

日新闻

物联网系统集成避坑指南:从选型到验收的关键要点

物联网系统集成避坑指南:从选型到验收的关键要点

做了这么多年物联网系统集成的项目,我最大的感受是,大部分坑不是出在技术前沿,而是出在一些看起来很平常的地方。设备选了便宜的、协议没问清楚、现场没摸透、验收标准写得含糊——这些细枝末节,最后都会变成延期、超支和扯皮的大…

2026/10/13 0:00:57 阅读更多 →
ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

如果你玩ESP32有一阵子了,很难不碰到舵机控制这道坎。做智能小车要转方向,做机械臂要抬关节,做云台要偏航俯仰,背后都是同一个东西在干活:舵机。而我见过太多人卡在“代码能编译、舵机就是不听话”这个阶段&#xff0c…

2026/10/13 0:00:57 阅读更多 →
CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

1. 为什么CAN总线至今仍是工业现场的“硬通货”?——从汽车底盘到智能温室的真实需求你有没有拆过一辆老款燃油车的中控台?或者调试过某高校实验室里那台跑着Modbus协议却频频丢帧的PLC控制柜?又或者,在某个农业物联网项目里&…

2026/10/13 0:00:57 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/13 2:54:56 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/13 16:22:04 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 21:05:09 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →