前几天实现了在 nginx 中使用 lua 实现远程鉴权,今天想试试在 IIS 中能不能实现相同的功能。查询资料发现需要使用 URL 重写和 HTTP 请求模块,没有深究。干脆使用 ASP.NET 中间件来实现吧。
在 StratUp.cs 的 Configure 方法中,或 Program.cs 文件中添加以下代码:
// 远程鉴权
app.Use(async (context, next) =>
{
var ip = context.Connection.RemoteIpAddress!.ToString();
var ua = context.Request.Headers.UserAgent.ToString();
var host = context.Request.Host.Host;
var uri = new Uri(context.Request.GetDisplayUrl()).PathAndQuery;
var client = new HttpClient();
client.Timeout = TimeSpan.FromSeconds(1); // 设置超时时间
try
{
var requestUrl = "https://鉴权地址/";
var requestMessage = new HttpRequestMessage(HttpMethod.Get, requestUrl);
requestMessage.Headers.Add("X-Real-IP", ip);
requestMessage.Headers.Add("User-Agent", ua);
requestMessage.Headers.Add("X-Forwarded-Host", host);
requestMessage.Headers.Add("X-Forwarded-Uri", uri);
// 发送请求
var response = await client.SendAsync(requestMessage);
// 检查响应状态码
if (response.StatusCode == HttpStatusCode.Forbidden)
{
// 如果返回403,则拒绝访问
context.Response.StatusCode = (int)HttpStatusCode.Forbidden;
await context.Response.WriteAsync("Access Denied");
}
else
{
// 如果返回其他状态码,则继续执行管道中的下一个中间件
await next();
}
}
catch (TaskCanceledException ex) when (ex.CancellationToken.IsCancellationRequested)
{
// 如果请求超时(任务被取消),则继续执行管道中的下一个中间件
await next();
}
catch
{
// 如果遇到错误,则继续执行管道中的下一个中间件
await next();
}
});
代码很简单,使用 HttpClient 发送请求,若返回 403 则拒绝访问,其它情况继续执行业务逻辑,超时或报错的情况按需修改即可。
若鉴权接口在私网中,建议将鉴权接口域名和私网 IP 添加到 hosts 文件中。
安装依赖
sudo yum install -y epel-release sudo yum install -y lua lua-devel gcc make
下载安装 LuaRocks
访问 LuaRocks 的官方网站 获取最新版本的 LuaRocks。你可以使用 wget 命令下载:
wget https://luarocks.org/releases/luarocks-x.x.x.tar.gz tar zxpf luarocks-x.x.x.tar.gz cd luarocks-x.x.x ./configure && make && sudo make install
设置环境变量(可选)
通常,LuaRocks 会自动处理这一步,但如果需要手动设置,可以编辑 ~/.bash_profile 或 ~/.bashrc 文件,添加以下行:
export PATH=$PATH:/usr/local/bin
然后运行以下命令使更改生效:
source ~/.bash_profile
验证安装
luarocks --version
本文记录于 2024 年 11 月。
升级前 | 期望(最新正式版) | 最终选择 | |
操作系统 | Alibaba Cloud Linux 3 | Alibaba Cloud Linux 3 | Alibaba Cloud Linux 3 |
管理面板 | 宝塔面板 Linux 版 9.2.0 | 宝塔面板 Linux 版 9.2.0 | 宝塔面板 Linux 版 9.2.0 |
Web 服务 | nginx 1.24 | nginx 1.24 | nginx 1.24 |
脚本语言 | PHP 7.4 | PHP 8.2 | PHP 8.2 |
数据库 | PolarDB MySQL 5.6 | RDS MySQL 9.1 | PolarDB MySQL 8.0 |
论坛程序 | Discuz! X3.4 GBK | Discuz! X5.0 | Discuz! X3.5 UTF8 |
版本选择原因:
Discuz! X5 刚刚发布,生态尚未成熟,考虑到是老论坛升级,所以选择 X3.5。
Discuz! X3.5 目前最高支持 PHP 8.2、MySQL 8.0。
完整升级步骤:
购买新的 ECS、PolarDB,具体环境配置步骤参此文;
安装宝塔面板并配置;
安装 nginx 及 PHP;
创建网站、配置 SSL、伪静态、防盗链、可写目录禁执行、仅允许部分入口文件执行等(.conf);
配置 hosts;
如果是正式升级阶段,关闭论坛,防止产生新数据。
备份原网站程序、PolarDB 数据库;
PolarDB 创建快照。
测试阶段:从快照还原到新实例(MySQL 5.6 不能直接恢复到 MySQL 8.0),然后从 5.6 迁移到 8.0.x;
正式阶段:全量模式直接从原实例迁移到 8.0.x,若增量模式且存在触发器,建议从快照还原;
上传原网站程序到新的站点目录下;
按 Discuz! X 升级文档升级 X3.4 至 X3.5;详情见下文 ↓;
升级完成后切换到 PHP 8;
配置 OSS、Redis、更新缓存等;
测试论坛基本功能是否正常;检查附件是否能够正常上传;检查附件是否正常显示;全面检查控制台配置;
逐个开启插件并检查兼容性(短信通、马甲引擎等);
按二开备忘录逐个按需进行二开;
逐个修改调用论坛接口的项目及直接调用论坛数据库的项目;
调试 MAGAPP 接口;
尝试强制 https 访问;
将以上所有修改后的程序保留备份;发布升级公告并关闭论坛;重复以上步骤;修改域名解析;开启论坛;
配置 IP 封禁、定时器、日志、自动备份、配置其它 ECS 的 hosts 等;
查看搜索引擎中收录的地址,是否有无法访问的情况;
尝试将历史遗留的本地附件全部转移到 OSS;
建议 在新服上创建 3 个网站:
第 1 个用来尝试迁移、升级、二开,并测试所有功能;
第 2 个用来再次重复这些步骤,最终保留程序代码及 UGC 文件,作为最终的网站程序,以正式域名作为网站根目录路径;
第 3 个用来正式升级,主要功能是升级最新数据库。完成后修改第 2 个网站的数据库连接指向到最新的数据库,差异化同步新增的 UGC 文件到第 2 个网站。
Discuz! X 升级步骤及注意点:
因 PolarDB MySQL 不支持压缩,所以应移除 Discuz! 和 UCenter 代码中所有的 MYSQLI_CLIENT_COMPRESS,将 , MYSQLI_CLIENT_COMPRESS 替换为 /*, MYSQLI_CLIENT_COMPRESS*/。
升级前务必先修改 ./config/ 目录下的数据库/缓存连接信息,以防出现新站连接老库的情况;
按官方文档进行升级,升级前先修改一下:
【UC】先升级 UCenter 1.6 至 1.7。
将 /uc_server/data 权限改为 777 并递归。
打开 update_ucenter_adult.php 修改 $limit 值为 10000 以免执行超时。
因通信失败的“发送通知失败”可以直接改 URL 参数跳过就完成了,原因可能是因数据量大,发送改名通知执行改名时超时。等DZ升级完成后UC会自动重试改名通知,或单独写个 php 文件将 UCenter 的用户名同步到应用的数据库。
【DZ】运行到 /install/update_adult.php?step=innodb&table=pre_common_member_grouppm 时报错:Duplicate key name 'gpmid' ALTER TABLE common_member_grouppm ADD INDEX gpmid(gpmid);
解决方法:先删除索引,因保存时提示失败,应同时取消 gpmid 字段的自增,转换成功后再设置自增。
【DZ】运行到 /install/update_adult.php?step=file 一片空白而停止
正在解决
【问题】common_menber 表用户名字段编码转换失败
原因是部分用户名包含特殊字符(如全角空格),用以下语句查看两个表同一 uid 的不同用户:
SELECT u.uid, u.username AS ucenter_username, c.username AS common_username FROM pre_ucenter_members u JOIN pre_common_member c ON u.uid = c.uid WHERE u.username <> c.username
Discuz! 用户登录都是以 UCenter 中的用户名为主,所以可以写个小程序直接将 pre_ucenter_members 的用户名同步到 pre_common_member 中,另外 pre_ucenter_members 的用户数少于 pre_common_member 是正常的。若 pre_common_member_archive 表遇到错误同理。
如果用户登录慢,或打开 UCenter 慢,是因为 UC 正在通知 DZ 改用户名,每次打开一个页面会更改一个用户名,具体可以查看 pre_ucenter_notelist 中 closed 为 0 的队列,或进入 UC 后台-数据列表-通知列表 查看。
【问题】发布主题遇到错误:(1062) Duplicate entry '*' for key 'pid'
【原因】forum_post 中的 pid 不是自动增长的,而是由表 forum_post_tableid 中自动增长的 pid 生成的。如果生成的 pid 值已在 forum_post 表中存在,则会出现此错误。
【解决】迁移数据库时应关闭论坛,以防止 forum_post 表有新数据插入。
【问题】打开帖子页面 ./thread-***-1-1.html 显示 404 Not Found,而 ./forum.php?mod=viewthread&tid=*** 可以正常打开
【原因】未配置伪静态(可在宝塔面板中选择)
【问题】打开 UCenter 时报错:UCenter info: MySQL Query Error SQL:SELECT value FROM [Table]vars WHERE name='noteexists'
【解决】打开文件 ./uc_server/data/config.inc.php 配置数据库连接
【问题】打开登录 UCenter 后一片空白
【解决】将目录 ./uc_server/data/ 设为可写
需要将原来安装的插件文件移回 ./source/plugin/ 目录,并设置可写;
界面-表情管理,界面-编辑器设置-Discuz!代码
后续 Discuz! X3.5 小版本升级注意事项:
确认插件是否支持新版本(如短信通)
先创建一个新网站测试二开代码
保留 /config/、/data/、/uc_client/data/、/uc_server/data/、/source/plugin/,其它移入 old
上传文件
移回其它需要的文件,如:
-- 勋章/loading/logo/nv 等:/static/image/common/
-- 表情:/static/image/smiley/
-- 水印:/static/image/common/watermark.*
-- 风格:/template/default/style/t2/nv.png 等
-- 默认头像:/uc_server/images/noavatar_***.gif
-- 根目录 favicon.ico 等
-- 及其它非 DZ 文件
再次检查可写目录的写入权限和禁止运行 PHP 效果。
实例化方法一:DbSearcher(String dbFile, QueryType queryType, String key)
实例化方法二:DbSearcher(InputStream is, QueryType queryType, String key)
方法一通过传入文件路径来实例化,方法二通过传入文件流来实例化;
当 queryType 为 MEMORY 时,方法一和方法二只有在实例化时有性能差别,差别在于将指定路径的文件读到内存中保存;在执行 Search 方法时无性能差别,因为都是在内存中执行查找;
queryType 为 MEMORY 和 BTREE 的差别在于前者是在内存中查找,速度快但占内存,后者是在文件中查找,速度慢但省内存。
错误:Padding is invalid and cannot be removed.
原因:可能是数据库文件与密钥不一致。
尝试捕获 InnerException 的 Message:
catch (Exception ex)
{
return BadRequest(ex.InnerException?.Message ?? ex.Message);
}
得到具体的错误信息:
Failed to find library "leptonica-1.82.0.dll" for platform x64.
GitHub 上有人提出了同样的问题,去看看。
解决方法:
安装 VC Redist。
其实 Tesseract 的 GitHub 已经提到需要安装 Visual Studio 2019 运行时。
.NET SDK 的版本 8.0.303 至少需要 MSBuild 的 17.8.3 版本。当前可用的 MSBuild 版本为 16.11.2.50704。请将在 global.json 中指定的 .NET SDK 更改为需要当前可用的 MSBuild 版本的旧版本。
解决方法:
运行 Visual Studio Installer,
选择相应 VS 版本进行修改,
切到“单个组件”,
勾选“.NET SDK (out of support)”,
点击修改并继续。
.NET Framework 项目中使用 MySql.Data.EntityFramework 连接 MySQL 8.0 时遇到以下错误:
NotSupportedException: Character set 'utf8mb3' is not supported by .Net Framework.
解决方法:
Nuget 中将 MySql.Data 和 MySql.Data.EntityFramework 更新到最新版。
未能找到路径“\roslyn\csc.exe”的一部分。
解决方法:
在 nuget 中直接卸载 Microsoft.CodeDom.Providers.DotNetCompilerPlatform
如果 web.config 报错,删除与 Microsoft.CodeDom.Providers.DotNetCompilerPlatform 相关的项,如:
<system.codedom>
<compilers>
<compiler language="c#;cs;csharp" extension=".cs" warningLevel="4" compilerOptions="/langversion:default /nowarn:1659;1699;1701;612;618" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
<compiler language="vb;vbs;visualbasic;vbscript" extension=".vb" warningLevel="4" compilerOptions="/langversion:default /nowarn:41008,40000,40008 /define:_MYTYPE=\"Web\" /optionInfer+" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.VBCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</compilers>
</system.codedom>
然后遇到错误:
功能 空传播运算符 在 C# 5 中不可用。请使用 6 或更高的语言版本
所以还是少不了 Microsoft.CodeDom.Providers.DotNetCompilerPlatform
又把这货装上了,竟然不报错了。
这期间我更改过在 Release 模式下调试,将 .NET Framework 4.8 升级到 .NET Framework 4.8.1 等,然后又退回到原来的状态和版本,竟然都正常了。
就这样吧!
客户端:Failed to connect to host.
服务端:无任何日志
原因:可能是域名、IP 或端口有误,或端口未开放。
客户端/服务端:530 Login incorrect.
原因:用户名或密码错误。
客户端/服务端:503 Use AUTH first.
原因:服务端开启了 FTPS 协议(FTP over TLS),且禁止了 FTP 协议(plain FTP)。
解决方法:不建议服务端恢复不安全的 FTP 协议,客户端应配置 client.Config 的 EncryptionMode、DataConnectionEncryption、SslProtocols、ValidateCertificate 等参数。
客户端/服务端:530 This server does not allow plain FTP. You have to use FTP over TLS.
原因:服务端启用了 FTPS。
解决方法:给 client.Config.EncryptionMode 正确的赋值(FtpEncryptionMode.Explicit 或 FtpEncryptionMode.Auto)。
服务端:[Error] TLS session of data connection not resumed.
原因:证书版本有误。
解决方法:给 client.Config.SslProtocols 赋值正确的 TLS 版本。
服务端:521 PROT P required
原因:服务端开启了“Require TLS session resumption on data connection when using PROT P”
解决方法:client.Config.DataConnectionEncryption = true;
客户端/服务端:450 TLS session of data connection has not resumed or the session does not match the control connection
原因:TLS 与控制连接不匹配,即服务端开启了“Require TLS session resumption on data connection when using PROT P”
解决方法:我暂时还不知道原因,临时关闭了“Require TLS session resumption on data connection when using PROT P”(不建议)。该问题出现在 FileZilla Server 0.x 版本,在 1.x 版本中没有该配置选项。