Files
YwxAppThink/app/backend/view/index/index.html
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

170 lines
7.3 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<script>
/^http(s*):\/\//.test(location.href) || alert('请通过 localhost 访问');;
</script>
</head>
<title>YwxApp</title>
<meta charset="UTF-8">
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<link href="/assets/layui/css/layui.css" rel="stylesheet">
<link href="/assets/ywxapp/css/ywxapp.css" rel="stylesheet">
<body class="layui-layout-body" id="LAY_home_iframe">
<div id="LAY_app">
<div class="layui-layout layui-layout-admin">
<div class="layui-header">
<!-- 头部区域 -->
<ul class="layui-nav layui-layout-left">
<li class="layui-nav-item layadmin-flexible" lay-unselect>
<a href="javascript:;" layadmin-event="flexible" title="侧边伸缩">
<i class="layui-icon layui-icon-shrink-right" id="LAY_app_flexible"></i>
</a>
</li>
<li class="layui-nav-item layui-hide-xs" lay-unselect>
<a href="/" target="_blank" title="前台">
<i class="layui-icon layui-icon-website"></i>
</a>
</li>
<li class="layui-nav-item" lay-unselect>
<a href="javascript:;" layadmin-event="refresh" title="刷新">
<i class="layui-icon layui-icon-refresh-3"></i>
</a>
</li>
<li class="layui-nav-item layui-hide-xs" lay-unselect>
<input type="text" placeholder="搜索..." autocomplete="off" class="layui-input layui-input-search" layadmin-event="serach" lay-action="template/search.html?keywords=">
</li>
</ul>
<ul class="layui-nav layui-layout-right" lay-filter="layadmin-layout-right">
<li class="layui-nav-item" lay-unselect>
<a lay-href="app/message/index.html" layadmin-event="message" lay-text="消息中心">
<i class="layui-icon layui-icon-notice"></i>
<!-- 如果有新消息,则显示小圆点 -->
<span class="layui-badge-dot"></span>
</a>
</li>
<li class="layui-nav-item layui-hide-xs" lay-unselect>
<a href="javascript:;" layadmin-event="note">
<i class="layui-icon layui-icon-note"></i>
</a>
</li>
<li class="layui-nav-item layui-hide-xs" lay-unselect>
<a href="javascript:;" layadmin-event="theme">
<i class="layui-icon layui-icon-theme"></i>
</a>
</li>
<li class="layui-nav-item layui-hide-xs" lay-unselect>
<a href="javascript:;" layadmin-event="fullscreen">
<i class="layui-icon layui-icon-screen-full"></i>
</a>
</li>
<li class="layui-nav-item" lay-unselect>
<a href="javascript:;">
<img src="{$user.avatar|default='/static/common/images/avatar.jpg'}" class="layui-nav-img">
<cite>{$user.nickname|default='管理员'}</cite>
</a>
<dl class="layui-nav-child">
<dd><a href="javascript:;" lay-href="{:url('Profile/index')}" lay-text="设置用户信息">设置用户信息</a></dd>
<dd><a href="javascript:;" lay-href="{:url('Profile/avatar')}" lay-text="设置头像">设置头像</a></dd>
<dd><a href="javascript:;" lay-href="{:url('Profile/password')}" lay-text="设置密码">设置密码</a></dd>
<hr>
<dd layadmin-event="logout" style="text-align: center;"><a>退出</a></dd>
</dl>
</li>
<li class="layui-nav-item layui-hide-xs" lay-unselect>
<a href="javascript:;" layadmin-event="about"><i class="layui-icon layui-icon-more-vertical"></i></a>
</li>
<li class="layui-nav-item layui-show-xs-inline-block layui-hide-sm" lay-unselect>
<a href="javascript:;" layadmin-event="more"><i class="layui-icon layui-icon-more-vertical"></i></a>
</li>
</ul>
</div>
<!-- 侧边菜单 -->
<div class="layui-side layui-side-menu">
<div class="layui-side-scroll">
<div class="layui-logo" lay-href="home/console.html">
<span>YwxApp</span>
</div>
<ul class="layui-nav layui-nav-tree" lay-accordion id="LAY-system-side-menu" lay-filter="layadmin-system-side-menu">
<li data-name="home" class="layui-nav-item layui-nav-itemed">
<a href="javascript:;" lay-tips="主页" lay-direction="2">
<i class="layui-icon layui-icon-home"></i>
<cite>主页</cite>
</a>
</li>
<li data-name="get" class="layui-nav-item">
<a href="javascript:;" layadmin-event="about" lay-tips="授权" lay-direction="2">
<i class="layui-icon layui-icon-auz"></i>
<cite>关于</cite>
</a>
</li>
</ul>
</div>
</div>
<!-- 页面标签 -->
<div class="layadmin-pagetabs" id="LAY_app_tabs">
<div class="layui-icon layadmin-tabs-control layui-icon-prev" layadmin-event="leftPage"></div>
<div class="layui-icon layadmin-tabs-control layui-icon-next" layadmin-event="rightPage"></div>
<div class="layui-icon layadmin-tabs-control layui-icon-down">
<ul class="layui-nav layadmin-tabs-select" lay-filter="layadmin-pagetabs-nav">
<li class="layui-nav-item" lay-unselect>
<a href="javascript:;"></a>
<dl class="layui-nav-child layui-anim-fadein">
<dd layadmin-event="closeThisTabs"><a href="javascript:;">关闭当前标签页</a></dd>
<dd layadmin-event="closeOtherTabs"><a href="javascript:;">关闭其它标签页</a></dd>
<dd layadmin-event="closeRightTabs"><a href="javascript:;">关闭右侧标签页</a></dd>
<dd layadmin-event="closeAllTabs"><a href="javascript:;">关闭全部标签页</a></dd>
</dl>
</li>
</ul>
</div>
<div class="layui-tab" lay-unauto lay-allowClose="true" lay-filter="layadmin-layout-tabs">
<ul class="layui-tab-title" id="LAY_app_tabsheader">
<li lay-id="/admin/console/index.html" lay-attr="/admin/console/index.html" class="layui-this"><i class="layui-icon layui-icon-home"></i></li>
</ul>
</div>
</div>
<!-- 主体内容 -->
<div class="layui-body" id="LAY_app_body">
<div class="layadmin-tabsbody-item layui-show">
<iframe src="/admin/console/index.html" frameborder="0" class="layadmin-iframe"></iframe>
</div>
</div>
<!-- 辅助元素,一般用于移动设备下遮罩 -->
<div class="layadmin-body-shade" layadmin-event="shade"></div>
</div>
</div>
<script src="/assets/layui/layui.js"></script>
<script type="text/javascript">
layui.app = {
root: "{$site.root|default=''}",
assetUrl: "/assets",
module: "{$site.module}",
app: "{$site.app}",
routeBase: "{$route_base}",
controller: "{$site.controller}",
action: "{$site.action}"
};
</script>
<script src="/assets/ywxapp/ywxapp.js" module="{$site.app}"></script>
<script type="text/javascript">
layui.use(['index']);
</script>
</body>
</html>