ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Apache+SVN用户自助修改密码的CGI实现方案

Apache+SVN用户自助修改密码的CGI实现方案 1. 需求拆解为什么“改密码”会变成SVN管理员的日常灾难先说个我自己的真实经历。早几年在一家软件公司做研发基础架构公司代码仓库用的是 Apache SVN 这套组合账号密码文件用 htpasswd 维护。最开始几十号人偶尔有人说“密码忘了”我跑一趟服务器执行一下 htpasswd 也就完事了。等团队涨到一两百人尤其是外包、实习生、离职人员交替变动的阶段改密码这件事几乎每天都能消耗我半小时。更尴尬的是好多人不是忘了密码而是觉得自己密码可能泄露了或者公司安全制度要求三个月换一次密码结果所有人都来找管理员。这就是 Apache SVN 这套方案的经典痛点它天生只负责“验证密码是否正确”压根没打算给你做一个“用户自助修改密码”的管理界面。htpasswd 是一个静态密码文件Apache 的 mod_authn_file 在认证时读取它仅此而已。用户要改密码只能由管理员登录服务器执行命令或者在运维平台上定制一套额外的工具。如果你正在管理一套 Apache SVN 服务或者你被团队里一波又一波的“帮我改下密码”弄得不厌其烦这篇文章就是给你写的。我会从方案选型、脚本设计、Apache 配置、常见坑位几个角度把“让 SVN 用户自己改密码”这件事从头到尾讲干净。文章默认你已经有了一套能跑的 Apache SVN 环境客户端可能是 TortoiseSVN小乌龟、命令行 svn、IDEA 内置 SVN 插件这些都不影响服务端改密码的实现方式。动手之前先彻底搞明白你手上的 SVN 到底是什么认证结构。这一步很多人会跳过结果后面脚本写好了却发现根本跑不通。SVN 服务端有两种主流形态一种是自己搭的 svnserve 进程走 svn:// 协议账号密码在 conf/passwd 文件里另一种是 Apache mod_dav_svn走 http:// 或 https:// 协议账号密码由 Apache 的认证模块负责最常见的配置是 mod_authn_file 配合 htpasswd 生成的密码文件。本文讲的是第二种因为标题里的 Apache 已经限定了场景。如果你的环境是 svnserve改密码的逻辑完全不同那是直接编辑 passwd 文件不涉及 Apache 这一层别搞混了。确认环境的方法很简单看仓库 URL。如果 URL 是 http://192.168.1.10/svn/repo 或 https://svn.company.com/svn/repo那就是 Apache 模式。再看 Apache 配置里认证部分用的是 AuthUserFile 还是 AuthDBMUserFile。AuthUserFile 对应 htpasswd 维护的文本文件这是我们最常见的场景也是下面所有方案的基础。2. 方案对比htpasswd 改密码的五种思路哪种适合你2.1 最原始的做法找管理员改这个不用多解释就是每次有人提出需求管理员 ssh 到服务器执行htpasswd -bm /data/svn/passwd 用户名 新密码然后告诉对方改好了。这种做法在小团队里完全没问题但如果团队上了规模管理员的时间被大量占用不说还有个隐形问题密码是管理员经手的用户心里会犯嘀咕安全审计上也不好看。所以一旦人数超过二十人或者公司有密码定期更换的合规要求这个方法就该淘汰了。2.2 给 htpasswd 开放写权限看起来很省事实际上很危险有人会想既然 htpasswd 就是个文件那我给 Apache 用户可写权限再写个简单的网页或者接口让用户填一下新旧密码脚本直接改文件不就完了思路方向是对的但直接照着做容易翻车。htpasswd 文件通常权限很敏感里面是所有 SVN 账号的密码散列值一旦被非法读取攻击者就能拿字典跑离线破解。如果你为了改密码把整个文件开放给 Apache 进程可读可写等于扩大了被攻击面而且如果脚本写得不够严谨任意用户都可能把别人的密码改掉那就是安全事故了。所以这个方案不是不能用而是必须配合严格的身份验证逻辑——也就是下面要讲的 CGI 脚本方案只是需要做对几个关键点。2.3 用 CGI 脚本做自助修改我推荐的主力方案这是性价比最高的路线。思路是用一个网页表单让用户输入用户名、旧密码、新密码提交给服务器上一个 CGI 脚本。脚本先调用 htpasswd 验证旧密码是否正确验证通过后再调用 htpasswd 更新新密码最后把结果返回给用户。整个过程不暴露 htpasswd 文件本身Apache 进程只需要在脚本执行期间有权限执行 htpasswd 命令并写入密码文件即可。脚本本身做严格的身份校验只有用户自己知道旧密码才能改新密码其他人无法越权。这个方案不需要安装额外的重型工具不依赖数据库一套 Perl 脚本加上 Apache 的 CGI 支持就能跑起来特别适合几十到几百人的团队。2.4 DBM 认证模式另一种可选结构如果你的 Apache 配置里用的是 AuthDBMUserFile而不是 htpasswd 文件那情况略有不同。DBM 模式适合账号数量非常大的场景认证性能更好但修改密码不能直接用 htpasswd 命令得用专门的工具或者写脚本操作 DBM 文件。从维护成本来看中小团队没必要上 DBMhtpasswd 文本文件在几千个用户以内完全撑得住。如果你已经是 DBM 环境可以参照本文的脚本思路底层命令换成相应 DBM 管理工具但要注意 DBM 文件格式和锁机制别让写入把文件搞坏了。2.5 企业级工具什么时候才需要上重武器市场上也有一些现成的 SVN 管理平台比如 VisualSVN ServerWindows 环境、SVNManager、Sventon、ViewVC 配合用户管理插件等它们自带 Web 界面支持用户自助改密码。如果你刚好是全新搭建预算也允许直接上这类工具确实省心。但问题是很多存量环境已经运行了好几年Apache 配置、authz 权限文件、钩子脚本、和内部账号体系的对接都稳定运行了这时候为了一个改密码功能去迁移整个服务端架构成本高、风险大不划算。我见过好几个团队评估过迁移最后都放弃了因为 SVN 本身已经处于维护模式大家的心思都在往 Git 迁没必要在这个节骨眼搞大动作。所以我的观点是除非你正在从零搭建否则用 CGI 脚本补一个改密码入口是最务实的过渡方案。2.6 方案选型小结方案成本安全风险用户体验适用场景管理员代改低低但管理员负荷高差要等20人以下临时场景直接开放文件写权限低高容易被越权改密中不推荐单独使用CGI 自助改密脚本中中低做好校验即可好随时可改中小团队存量环境首选DBM 架构定制工具中高中好大用户量场景有现成基础企业级管理平台高低最好新搭建或预算充足3. 实操用 Perl CGI 给 Apache SVN 加一个改密码页面3.1 环境准备Apache CGI 模块与目录权限动手写脚本之前先确认几件事。第一Apache 要支持 CGI。检查方法是在 httpd.conf 或 conf.d 下的配置里搜索 mod_cgi 或 mod_cgid如果没启用Ubuntu/Debian 下执行sudo a2enmod cgi sudo systemctl restart apache2CentOS/RHEL 下一般是编译进去的确认一下有没有 LoadModule cgi_module modules/mod_cgi.so。第二确认 htpasswd 命令的绝对路径。多数系统在 /usr/bin/htpasswd如果是源码编译的 Apache可能在 /usr/local/apache2/bin/htpasswd。执行which htpasswd看一下。第三确定密码文件的绝对路径和属主。假设密码文件在 /data/svn/passwd那么 Apache 进程用户通常是 www-data、apache 或 daemon必须对该文件有读权限脚本执行时才读得动要能写入新密码还需要写权限。如果你的密码文件一直归 root 所有接下来必须调整。我个人建议的目录布局是密码文件单独放在 /data/svn/conf/ 下目录属主设为 Apache 用户权限 750密码文件权限 640。这样脚本执行用户能读写普通用户通过任何路径都无法直接访问。如果你不想动现有密码文件的位置也可以把新密码文件复制一份到新目录在 Apache 配置里把 AuthUserFile 路径改过去效果一样还能顺便把历史遗留的弱权限问题解决掉。3.2 改密码脚本的核心逻辑写脚本之前先把逻辑拆成四步每一环都不能漏校验入参用户名不能为空旧密码不能为空新密码长度和复杂度要达标两次输入的新密码必须一致。验证旧密码调用 htpasswd -vb 校验旧密码是否正确。这一步的返回值至关重要不对就直接拒绝不给任何写入机会。写入新密码调用 htpasswd -bm 更新密码文件。这里要注意并发问题两个用户同时改密码时不能让他们同时写同一个文件否则可能把文件写坏下面会专门讲。返回结果给用户一个清晰的页面提示成功或失败原因。下面是一份我实际在用的 Perl CGI 脚本精简过注释但保留了核心逻辑。Perl 在绝大多数 Linux 服务器上都是预装的写这种短脚本不需要额外装模块CGI.pm 在系统 Perl 里默认就有。#!/usr/bin/perl use strict; use warnings; use CGI qw(:standard); use IPC::System::Simple qw(system); # 配置区 my $htpasswd_bin /usr/bin/htpasswd; my $passwd_file /data/svn/conf/passwd; my $lock_file /data/svn/conf/passwd.lock; my $q CGI-new; print $q-header(text/html; charsetutf-8); my $username $q-param(username) || ; my $old_password $q-param(old_password) || ; my $new_password1 $q-param(new_password1) || ; my $new_password2 $q-param(new_password2) || ; # 检查提交方式拒绝 GET只允许 POST if ($q-request_method ne POST) { print_error(请通过表单提交。); exit 0; } # 入参校验 if ($username eq || $old_password eq || $new_password1 eq ) { print_error(用户名、旧密码、新密码都不能为空。); exit 0; } if ($new_password1 ne $new_password2) { print_error(两次输入的新密码不一致。); exit 0; } if (length($new_password1) 8) { print_error(新密码长度至少 8 位。); exit 0; } if ($new_password1 !~ /[A-Za-z]/ || $new_password1 !~ /[0-9]/) { print_error(新密码必须同时包含字母和数字。); exit 0; } # 用 flock 对锁文件加锁防止并发写坏密码文件 open(my $lock_fh, , $lock_file) or die cannot open lock file: $!; flock($lock_fh, 2); # LOCK_EX # 验证旧密码htpasswd -vb 返回 0 表示验证通过 system($htpasswd_bin, -vb, $passwd_file, $username, $old_password); my $verify_rc $? 8; if ($verify_rc ! 0) { print_error(旧密码验证失败请检查用户名或旧密码是否正确。); exit 0; } # 更新密码 system($htpasswd_bin, -bm, $passwd_file, $username, $new_password1); my $update_rc $? 8; if ($update_rc ! 0) { print_error(密码更新失败请稍后重试或联系管理员。); exit 0; } print HTML; htmlbody p stylecolor:green; font-size:18px;密码修改成功下次提交 SVN 时请使用新密码。/p pa href/svn/返回 SVN 首页/a/p /body/html HTML sub print_error { my ($msg) _; print htmlbodyp style\color:red; font-size:18px;\$msg/p; print pa href\javascript:history.back()\返回重试/a/p/body/html; }这里有几个细节值得展开说。第一个是IPC::System::Simple这个模块我在脚本里引用了它但系统自带的 Perl 不一定装了。更稳妥的做法是不引入这个模块直接用反引号或者 system $? 判断返回值。考虑到不是所有人都有权限装 CPAN 模块下面的代码改用纯 system 方式判断避免依赖问题。上面这段代码是我简化过的实际部署时你应该用下面的版本my $verify_cmd $htpasswd_bin -vb $passwd_file $username $old_password; system($verify_cmd); my $verify_rc $? 8;注意这里用 system 传一个字符串会经过 shell 解析如果用户名或密码里有空格、特殊字符会有注入风险。更严谨的做法是用 system 的列表形式system($htpasswd_bin, -vb, $passwd_file, $username, $old_password); my $verify_rc $? 8;这样参数不会经过 shell安全性好很多。htpasswd 的 -v 是校验模式-b 表示密码通过命令行参数传入而不是交互式输入。如果你的 htpasswd 版本比较老可能不支持 -v至少 Apache 2.2 之后的版本都是支持的实际部署前先手动跑一次验证一下命令格式。第二个是并发写保护。flock($lock_fh, 2)是对锁文件加独占锁。为什么要加锁htpasswd 更新文件的时候并不是原子操作两个同时发起的改密请求如果同时写文件轻则其中一个请求失败重则整个密码文件被截断或混入脏数据那就是全组人都登不上的事故。加锁之后第二个请求会等第一个请求执行完再进入写入逻辑代价是极端情况下用户会多等一两秒完全值得。第三个是密码强度校验。很多管理员觉得 SVN 密码无所谓随便设一下就行。但 SVN 仓库里放的是公司核心代码资产密码太弱等于门户大开。我在脚本里做了两个硬性检查长度至少 8 位必须包含字母和数字。如果你有更高的合规要求可以再加正则比如必须包含特殊字符、不能和用户名相同等。注意正则里的转义Perl 里特殊字符要小心处理。3.3 前端页面的设计与处理脚本输出的是一个简单的 HTML 表单但实际部署时你可能会想让页面好看一点和公司内部 IT 系统的风格统一。做法有两种一种是直接把 HTML 嵌在脚本里像我上面那样优点是部署简单一个文件搞定另一种是单独写一个 HTML 页面表单 action 指向 CGI 脚本脚本负责处理完成后返回结果页面。我个人推荐第二种HTML 和逻辑分离后续改样式不必动 Perl 代码更利于维护。一个可用的表单页面大概是这样的!DOCTYPE html html langzh-CN head meta charsetutf-8 titleSVN 密码自助修改/title /head body h2SVN 密码修改/h2 form methodpost action/cgi-bin/change_svn_password.cgi p用户名input typetext nameusername required/p p旧密码input typepassword nameold_password required/p p新密码input typepassword namenew_password1 required/p p确认新密码input typepassword namenew_password2 required/p pbutton typesubmit修改密码/button/p /form /body /html这里有个小细节action 路径必须和实际部署的 CGI 路径一致下面会讲 Apache 配置。另外表单必须是 POST 提交脚本里已经做了 request_method 检查防止有人扒着 URL 直接带参数访问。3.4 Apache 配置把脚本挂到 HTTPS 服务下脚本写好了接下来要让它能从外部访问。在 Apache 配置里加一个 ScriptAlias。假设你的 SVN 配置在 /etc/httpd/conf.d/svn.confCentOS或 /etc/apache2/conf-available/svn.confDebian/Ubuntu加上ScriptAlias /cgi-bin/change_svn_password.cgi /data/svn/cgi-bin/change_svn_password.cgi Directory /data/svn/cgi-bin Require all granted Options ExecCGI SetHandler cgi-script /Directory注意/data/svn/cgi-bin这个目录在文件系统上的权限。脚本要能被执行目录本身不能让 Apache 用户写否则别人上传个恶意脚本进去就麻烦了。建议目录属主 root权限 755脚本属主 root权限 755。但如果脚本要写密码文件执行脚本的进程用户Apache 用户需要能访问密码文件所在目录和文件本身。所以密码文件不能放在 root-only 的目录下而是放在 Apache 用户能读写的目录里。除此之外还有一层需要提醒的这个改密页面本身是全公司可访问的如果你不打算让所有人都能打开改密页面可以在 Directory 里加上内网 IP 段限制比如Directory /data/svn/cgi-bin Require ip 10.0.0.0/8 192.168.0.0/16 /Directory这个选择取决于你们的使用场景大多数公司 SVN 本身就在内网不加反而省事。配置改完记得执行apachectl -t或者httpd -t检查语法然后 reload 或 restart Apache。如果你改的是 conf-available 下的文件Debian/Ubuntu 上还得执行 a2enconf 把配置启用这里不展开了。3.5 客户端侧改完密码后如何使用服务端改完密码之后客户端那边通常会碰到一个很隐蔽的问题密码缓存。TortoiseSVN小乌龟默认会保存认证凭据用户在网页上改了密码再去 SVN 操作时小乌龟仍然用旧密码去认证结果一直报授权失败用户还以为服务端没改成功。解决办法是在 TortoiseSVN 里清除保存的凭据。菜单路径在 TortoiseSVN - Settings - Saved Data点一下 Authentication data 一栏的 Clear 按钮把缓存的凭据清掉。之后再做任意 SVN 操作它就会重新弹出输入密码的对话框这时输入新密码就行。如果是命令行 svn 客户端Windows 上的凭据默认也是缓存的位置在 %APPDATA%\Subversion\auth\svn.simple 下最粗暴的方法是把这个目录下的文件删掉或者更省事的方式是执行svn auth命令查看然后用svn auth --remove移除对应条目。Linux 下的凭据在 ~/.subversion/auth/svn.simple 下同理删除即可。还有一个经常被忽略的场景如果用户正在用 IDE 的 SVN 插件比如 IDEA凭据一般由 IDE 自身或操作系统的凭据管理器统一缓存。用户改了密码后IDE 可能不会马上弹窗而是持续报认证失败。遇到这种情况先到 IDEA 的 Settings - Appearance Behavior - System Settings - Passwords 里查看保存的密码删掉对应条目或者把 Passwords 的存储策略改成不保存以后每次操作都要求输入密码。这些客户端侧的细节看起来和“Apache SVN 修改密码”的主题有点距离但实际运维中大量问题是发生在这一环的。我本人就曾经被同一个问题折腾过服务端脚本写得没问题用户也改成功了结果小乌龟一直报认证失败排查半天才发现是缓存的老密码在捣乱。所以你在写文档或者发公告的时候一定记得把“如何清理客户端缓存凭据”这个步骤写进去能省掉一大半的答疑时间。4. 常见问题与排查实录4.1 问题速查表现象可能原因排查与解决办法访问改密页面报 403 ForbiddenScriptAlias 与 Directory 配置不匹配或者没有 ExecCGI 权限检查 httpd -t 语法确认 ScriptAlias 目标文件存在且可执行查看 Apache 错误日志脚本执行报 500 Internal Server ErrorCGI 脚本没有可执行权限或者 perl 解释器路径不对chmod x 脚本检查脚本第一行 shebang#!/usr/bin/perl改密成功但 SVN 客户端仍报认证失败客户端缓存了旧密码凭据清理 TortoiseSVN/SVN 命令行/IDE 中缓存的认证数据旧密码验证一直失败htpasswd 版本不支持 -v或者密码算法不匹配手动执行 htpasswd -vb 测试确认密码文件里该用户确实存在两个用户同时改密码一个失败并发写入冲突启用 flock 锁文件机制检查锁文件路径可写脚本说密码更新成功但登录还是旧密码htpasswd 更新了另一个文件Apache AuthUserFile 指向不同路径核对 Apache 配置里的 AuthUserFile 与脚本里的 $passwd_file 是否一致页面内容显示乱码编码不一致确保脚本输出 header 里 charsetutf-8HTML 文件也保存为 UTF-84.2 容易被忽略的文件权限细节我见过很多次脚本本身写得完美但用户一提交就报“无法写入密码文件”原因几乎都是文件权限没配好。Apache 进程用户跑着脚本脚本要写密码文件这个文件如果属于 root 且权限是 600Apache 用户自然写不进去。解决办法有两种思路。第一种是把密码文件和锁文件的属主直接改成 Apache 用户chown www-data:www-data /data/svn/conf/passwd /data/svn/conf/passwd.lock chmod 640 /data/svn/conf/passwd第二种是保持文件属主不变把 Apache 用户加入文件属组然后设置组写权限。哪种好从最小权限原则看第二种更好一些因为 Apache 进程不需要对文件所在目录有写权限只需要对文件本身有写权限就行。但如果密码文件所在目录将来还要给其他脚本写入第二种反而容易引出一堆权限纠缠不如直接用第一种省心。还有一点很多系统上 Apache 用户是 nologin 的直接用 root 执行 htpasswd 和用 Apache 用户执行 htpasswd对密码文件的影响是一样的都是追加或覆盖条目不会改变文件里其他用户。所以不用担心用 Apache 用户写入会破坏别的数据。4.3 脚本日志与错误定位CGI 脚本出问题时第一件事是看 Apache 错误日志。Debian/Ubuntu 默认在 /var/log/apache2/error.logCentOS/RHEL 默认在 /var/log/httpd/error_log。日志里会明确告诉你脚本执行时的完整报错比如 “Permission denied”、“Cant locate IPC/System/Simple.pm”、“syntax error at ...” 这类信息。调试期还有一个非常实用的技巧直接在命令行用 CGI 环境变量方式执行脚本模拟 HTTP 请求。比如REQUEST_METHODPOST \ CONTENT_TYPEapplication/x-www-form-urlencoded \ CONTENT_LENGTH80 \ echo -n usernametestold_passwordoldnew_password1newpass123new_password2newpass123 | perl /data/svn/cgi-bin/change_svn_password.cgi这样可以跳过 Apache 直接看脚本输出能快速定位是脚本逻辑问题还是 Apache 配置问题。这个技巧是命令行时代传下来的老办法但真的非常好用比一遍遍刷新浏览器高效得多。注意 CONTENT_LENGTH 必须和输入字符数匹配不然后端可能读不全参数。嫌麻烦可以直接用curl -X POST -d username...访问线上地址来调试但内网地址要先确认防火墙放行。5. 补强安全性的几个顺手操作5.1 强制 HTTPS 和 Basic 认证的隐患SVN 走 HTTP 认证时最常见的方案是 Basic Auth也就是用户名密码以 Base64 编码放在 HTTP 头里。Base64 不是加密是编码中间人截获后可以直接解码拿到明文密码。所以如果你现在还是纯 http:// 提供 SVN 服务必须尽快切到 https://。这个道理大家都懂但很多内部系统一跑就是好多年一直没切。在 Apache 配置里加个跳转把所有 HTTP 请求强制转到 HTTPSVirtualHost *:80 ServerName svn.company.com Redirect permanent / https://svn.company.com/ /VirtualHost改密页面同样必须走 HTTPS否则用户在这个页面上输入新旧密码密码直接裸奔在网络上。我的建议是SVN 服务和改密页面统一绑到同一个 HTTPS 虚拟主机里不给明文 HTTP 留任何入口。5.2 htpasswd 文件与脚本权限的加固建议一个高度安全的部署至少要做到以下几点htpasswd 文件属主为 Apache 用户权限 640其他用户没有任何权限。htpasswd 所在目录属主为 Apache 用户权限 750不要让普通用户能 ls 目录。CGI 脚本属主为 root目录属主为 root脚本权限 755确保目录和脚本不被 Apache 用户篡改。密码文件定期备份尤其是在批量导入用户或大量改密前后。改密脚本执行的命令不要使用 shell 拼接字符串务必用 system 的列表传参方式避免注入。这些看起来是琐碎的基础工作但对内部系统来说往往就是这些琐碎的地方决定了安全性高低。真的被攻击时攻击者往往不是靠什么高深的漏洞而是靠运维配置上露出来的“窗户纸”。5.3 密码策略与审计日志改密脚本里已经做了密码强度校验但如果你要应付安全审计可能还需要更多比如密码有效期提醒、密码历史不能重复、连续错误锁定账号等。这些在纯 Apache htpasswd 的环境下做起来比较费劲因为 htpasswd 文件本身没有这些元数据。我的处理方式是写一个定时扫描脚本解析 Apache 访问日志里认证失败次数配合脚本的日志输出对短时间内连续失败的账号做告警密码有效期则用一个简单的时间戳文件记录每个用户上次改密时间。如果你不想自己造轮子也可以把认证后端换成 LDAP然后把密码策略交给 LDAP 目录服务统一管理。不过这是比较大的架构调整而且 LDAP 本身的维护成本不低小团队谨慎考虑。5.4 备份与恢复的兜底方案再稳的脚本也存在意外比如误操作导致密码文件被清空。我习惯在改密脚本每次执行成功后自动把旧密码文件备份一份按日期保留最近七天的版本。实现方式很简单在脚本写入新密码前复制一份旧文件cp -p $PASSWD_FILE $BACKUP_DIR/passwd.$(date %Y%m%d%H%M%S)然后写个 cron 任务定期清理超过七天的备份文件。这么做的好处是万一某次脚本有 bug 把密码文件写乱了管理员可以马上从最近一次的备份里恢复影响面能控制在几分钟以内。我实际遇到过一次脚本并发问题导致密码文件出现脏数据幸好有备份十分钟内恢复了服务。从那以后我把这个备份逻辑写进了所有同类脚本里。说实话Apache SVN 这套技术栈现在已经不算新潮了很多团队都在往 Git 迁移。但存量系统的维护短则一两年长则三五年只要 SVN 还在跑改密码就是躲不开的需求。用一个小脚本补上这个功能让用户自助完成既省了管理员的时间也少了来回沟通的成本。根据我个人的维护经验CGI 脚本方案投入产出比是最高的。如果你对 Perl 不熟改成 Python 的 CGI 脚本也可以核心逻辑完全一样验证旧密码、校验新密码、加锁更新文件。关键是先把方案想清楚再去纠结具体语言和实现细节。
返回列表