Files
YwxAppThink/addon/haonav/route/app.php
T
yangwx 18101cf11a feat: 上线前安全加固与发布工程化;appmall 由插件迁移为独立应用
安全(P0)
- 发布包签名:新增 scripts/package_keygen.php、scripts/package_verify.php、
  ywxapp\service\PackageVerifier;FrameworkService::apply() 解压前强制验签
  (ywxapp.framework_package_verify,默认开启)
- JWT 收紧:config/jwt.php 移除公开默认密钥,JwtService::assertStrongSecret()
  校验非空 / 长度≥32 / 已知弱值;.env.production.example 键名由 JWT_SECRET_KEY 修正为 JWT_SECRET
- /api/v1/Article:免登录白名单收窄为只读接口,写操作字段白名单 + assertOwner() 越权校验
- 开发者令牌:查找接口不再回显明文、统一失败文案 + 限流
- TemplateInstaller:文件名白名单 + realpath 归一化 + 目录内断言,修复 Zip Slip;补 use ZipArchive
- 后台登录:接入验证码、失败锁定与登录限流(config/ratelimit.php)
- 缓存 / Session 驱动可由 .env 覆盖(CACHE_DRIVER / SESSION_TYPE),集群部署改 redis
- paycenter 支付日志开关改为 PAY_LOG,不再跟随 APP_DEBUG

工程化 / 交付
- 新增 CHANGELOG.md 与 .env.production.example;composer.lock 入库锁定依赖版本
- 插件离线安装 CLI 增加 --uid,后台上传安装透传 uid,付费插件授权校验可通过
- 授权拒绝文案区分「未携带 uid」与「未找到有效授权」,便于排障
- .gitignore 放行 .env.production.example / .env.addon.example / .gitattributes / public/.htaccess

结构
- appmall 由 addon/appmall 迁移为独立应用 app/appmall(市场 / 开发者中心 / 审核 / 分润)
2026-10-22 00:53:39 +08:00

99 lines
4.8 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/*
* @Author: YwxApp <ywx@ywxapp.cn>
* @Date: 2026-07-31 13:28:15
* @LastEditors: YwxApp <ywx@ywxapp.cn>
* @LastEditTime: 2026-08-10 23:40:51
* @Description:
* @FilePath: \ywxapp_dev\addon\haonav\route\app.php
* @CustomString: Copyright (c) 2026 YwxApp
*/
// +----------------------------------------------------------------------
// | YwxApp [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2026-2036 http://ywxapp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: ywxapp<admin@ywxapp.cn>
// +----------------------------------------------------------------------
use think\facade\Route;
// 说明:本文件由 ywxapp/service/AppService::loadAddonRoutes() 在 boot 阶段
// include,并统一被外层 Route::group('haonav', ...) 包住,因此下面写的都是
// 【相对规则】,最终自动加 /haonav 前缀:
// 顶层规则 -> /haonav/*
// backend 组 -> /haonav/*
// 对外 REST API 才需要带前导 / 写绝对规则(本项目 haonav 暂无对外 API)。
// 前台页面 / 接口
// URL 写法规范:【插件名 + 规则路径】,如 url('haonav/rank')、url('[haonav_site]', ['id'=>x])。
// 不要写「插件名/控制器/方法」(如 haonav/index/rank):插件是独立应用,请求进来时
// MultiApp 会把 URL 首段插件名剥掉,路由表里生效的是下面这些扁平规则,对不上;
// 原 index/:id 还把所有 index/xxx 吞给首页(Index::index),故改为精确的 index。
// 带参数规则统一 ->name(),参数才会被填进路径段(否则会退化成 ?query)
Route::rule('index', 'Index/index')->name('haonav_index');
Route::rule('index/test', 'Index/test');
Route::rule('category/:id', 'Index/category')->name('haonav_category');
Route::rule('site/:id', 'Index/site')->name('haonav_site');
Route::rule('search', 'Index/search');
Route::rule('suggest', 'Index/suggest');
Route::rule('rate', 'Index/rate');
Route::rule('rank', 'Index/rank');
Route::rule('submit', 'Index/submit');
Route::rule('apply', 'Index/apply');
Route::rule('favicon', 'Index/favicon')->name('favicons');;
Route::rule('snapshot', 'Index/snapshot');
Route::rule('sw', 'Index/sw');
Route::rule('ad/click', 'Index/adClick');
// 前台会员:登录 / 注册 / 退出 / 资料(复用框架前台 Auth,token 经 Cookie 落地)
Route::rule('account/login', 'Account/login');
Route::rule('account/register', 'Account/register');
Route::rule('account/logout', 'Account/logout');
Route::rule('account/profile', 'Account/profile');
// 首页小组件:实时热搜 / 天气(服务端代理 + 缓存)
Route::rule('widget/hot', 'Widget/hot');
Route::rule('widget/weather', 'Widget/weather');
// 用户云端收藏(登录后「我的导航」跨端同步;未登录返回 401,前端回退本地)
Route::rule('favorite/list', 'Favorite/list');
Route::rule('favorite/add', 'Favorite/add');
Route::rule('favorite/remove', 'Favorite/remove');
Route::rule('favorite/sort', 'Favorite/sort');
Route::rule('favorite/merge', 'Favorite/merge');
// 收藏夹分享:配置接口(登录) + 公开分享页(凭 token 只读浏览)
Route::rule('favorite/share', 'Favorite/share');
Route::rule('favorite/sharesave', 'Favorite/shareSave');
Route::rule('favorite/shared/:token', 'Favorite/shared');
// SEO:站点地图(/haonav/sitemap.xml 与 /haonav/sitemap.html 均可访问)
Route::rule('sitemap', 'Index/sitemap');
Route::rule('sitemap.xml', 'Index/sitemap');
// 计划任务入口(cron 调用,需携带 token;最终地址 /haonav/task/checklinks)
Route::rule('task/checklinks', 'Task/checkLinks');
// 惰性自动巡检(前台页面异步 ping,缓存锁限频,无 cron 环境兜底)
Route::rule('task/autocheck', 'Task/autoCheck');
// 后台管理路由(对应 controller/ 下的控制器;最终地址 /haonav/*)
// 注意:全局 route_complete_match=false 时,裸规则(如 'links')会前缀匹配
// 'links/create' 等子路径并把多余段当参数吞掉(先注册先匹配),导致
// /links/create 被派发到 Links::index 而非 create。
// 因此裸规则必须 强制完整匹配。
Route::group('backend', function () {
Route::rule('index', 'Dashboard/index');
Route::rule('dashboard', 'Dashboard/index');
Route::rule('dashboard/:action', 'Dashboard/:action');
Route::rule('links', 'Links/index');
Route::rule('links/:action', 'Links/:action');
Route::rule('category', 'Category/index') ;
Route::rule('category/index', 'Category/index') ;
Route::rule('configs', 'Configs/index');
Route::rule('configs/:action', 'Configs/:action');
Route::rule('ad', 'Ad/index');
Route::rule('ad/:action', 'Ad/:action');
Route::rule('apply', 'Apply/index');
Route::rule('apply/:action', 'Apply/:action');
})->prefix('backend/');;