Laravel如何实现单路由密码保护限制SMS发送功能访问
实现方案
你要的点击提交触发密码校验的逻辑可以通过「前端交互拦截+后端强校验」的方式实现,核心是后端必须做密码校验,前端只负责交互,不能作为权限判断的依据。
方案1:点击提交按钮弹出密码输入框(完全匹配你的交互预期)
这个方案不需要改动你现有表单的布局,用户填完短信内容点提交按钮时才会弹出密码输入框,校验通过才提交表单。
前端修改
- 把原来的提交按钮从
type="submit"改成type="button",加id方便绑定事件:
<button type="button" id="smsSubmitBtn" class="btn btn-success">Send SMS Notification</button>
- 在表单
{!!Form::close()!!}标签后面加原生JS,处理点击事件和密码提交:
<script> const submitBtn = document.getElementById('smsSubmitBtn'); submitBtn.addEventListener('click', function() { const inputPwd = prompt('请输入短信功能访问密码:'); // 用户点取消直接终止流程 if (inputPwd === null) return; if (!inputPwd.trim()) { alert('密码不能为空'); return; } const form = this.closest('form'); // 移除重复的密码字段避免重复提交 const oldPwdField = form.querySelector('input[name="access_password"]'); if (oldPwdField) oldPwdField.remove(); // 动态插入隐藏字段传递密码 const pwdField = document.createElement('input'); pwdField.type = 'hidden'; pwdField.name = 'access_password'; pwdField.value = inputPwd.trim(); form.appendChild(pwdField); // 提交表单 form.submit(); }); </script>
后端修改(必须做,前端校验可被随意绕过)
你用的是Laravel框架,按照下面的逻辑加校验即可:
- 先在项目根目录的
.env文件里加一行配置,存你的专用访问密码,不要硬编码在控制器里:
SMS_ACCESS_PASSWORD=你自己设置的访问密码
- 在
config目录下新建sms.php配置文件,读取env配置:
<?php return [ 'access_password' => env('SMS_ACCESS_PASSWORD', ''), ];
- 打开你的
NotificationController,找到sms方法,在执行短信发送逻辑之前加校验:
public function sms(Request $request) { // 校验输入参数 $validated = $request->validate([ 'message' => 'required|string|max:160', 'access_password' => 'required|string', ]); // 校验密码,用hash_equals防止时序攻击 if (!hash_equals(config('sms.access_password'), $validated['access_password'])) { return back()->withErrors(['access_password' => '访问密码错误,请重试'])->withInput(); } // 下方保留你原来已经正常运行的短信发送逻辑即可 // ...... 原有短信发送代码 ...... return back()->with('status', '短信通知已发送'); }
- 命令行执行
php artisan config:cache让新配置生效。
方案2:表单内直接加密码输入框(兼容性更好)
如果担心浏览器拦截prompt弹窗,或者想要更稳定的交互,可以直接在现有表单的短信内容输入框下方,加一个固定的密码输入字段,不需要额外写JS:
<div class = "row"> <label class = "col-sm-2 col-form-label">访问密码: </label> <div class = "col-sm-6"> <div class = "form-group"> <input type = "password" class = "form-control" name="access_password" required> </div> </div> </div>
后端校验逻辑和方案1完全一致,不需要改动。
安全提示
- 不要依赖纯前端校验:用户可以通过浏览器控制台禁用JS、修改前端代码直接绕过前端校验发请求,后端校验是唯一的安全防线
- 可以给短信发送路由加Laravel自带的频次限制中间件,防止暴力破解密码,示例:
Route::post('/notification/sms', 'NotificationController@sms')->middleware('throttle:5,10');
上面的配置代表同一个IP10分钟内最多允许提交5次请求,超过就暂时拦截。
内容的提问来源于stack exchange,提问作者Brendan
相关产品推荐
相关产品推荐

