当用户尝试在 laravel 中使用 nexmo 呼叫 phone 号码时验证用户
Validate user when they try to call phone number with nexmo in laravel
我有客户服务应用程序使用 nexmo 和 laravel 作为框架在应用程序浏览器调用中使用。我有一些用户,每个用户在 table 中都有他们的列表 phone 号码,每一行都有联系操作按钮来调用。 phone 数字的目标是这样放在按钮中的:
<a href="#" class="btn btn-sm btn-info call-button" data-toggle="modal" data-number="6281299054899">Contact</a>
但用户可以检查元素并编辑这些按钮,然后输入他们想要的另一个 phone 数字。我如何防止这种作弊并在示例中提醒用户“您未授权呼叫此 phone 号码。”他们什么时候做那个动作?
这是我在单击 .call-button 时的处理程序:
dataTableAdminLeader.on('click', '.call-button', function(){
let id = $(this).data('id');
let master_number_id = $(this).data('master_numbers_id');
let target_number = $(this).data('number');
const trashButton = document.querySelector('.btn-trash');
const updateButton = document.querySelector(".btn-update");
trashButton.setAttribute('disabled', 'disabled');
updateButton.setAttribute('disabled', 'disabled');
$('#phone-call-modal').modal('show');
// input reset
document.querySelector('#target-phone').value = target_number;
document.querySelector('#id-edit').value = id;
document.querySelector('#master-numbers-id-edit').value = master_number_id;
document.querySelector('#member-id').value = $(this).data('id-member');
document.querySelector('#member-name').value = $(this).data('name');
trashButton.removeAttribute('disabled');
updateButton.removeAttribute('disabled');
// all constant needed for call
const USER_JWT = "{{ $jwt_token }}";
const phoneNumberInput = document.querySelector("#cs-phone");
const statusElement = document.querySelector("#status-call");
// button object selector
const callButton = document.querySelector(".btn-call");
callButton.setAttribute('disabled', 'disabled');
const hangupButton = document.querySelector(".btn-hangup");
const closeButton = document.querySelector('.btn-close');
closeButton.style.removeProperty('display');
const statusButton = document.querySelector('.btn-status');
// input object selector
let campaign_result = document.querySelector('#campaignresult');
let note_contacted = document.querySelector('#note_contacted');
let note_container = document.querySelector('.note_container');
let nameContainer = document.querySelector('.name-container');
let campaignContainer = document.querySelector('.campaign-container');
let waContainer = document.querySelector('.wa-container');
let inputCallStatus = document.querySelector('#call-status');
// call status check
let callStatusCompleted = false;
let callStatusAnswered = false;
// reset property
campaign_result.value = "";
note_container.style = 'display: none';
nameContainer.style = 'display: none';
// sound object
var sndAnswered = new Audio("{{ asset('storage/sounds/answered.wav') }}");
// listening to event
campaign_result.addEventListener('change', function(){
if(campaign_result.value != ''){
note_container.style.removeProperty('display');
note_contacted.setAttribute('required', 'required');
}else{
note_container.style = 'display: none';
note_contacted.removeAttribute('required');
}
});
// nexmo status reset
statusElement.innerText = '';
inputCallStatus.value = '';
// nexmo call button reset
callButton.style.display = "inline";
hangupButton.style.display = "none";
// timeouts set
setTimeout(() => {
callButton.removeAttribute('disabled');
}, 5000);
// nexmo object start
new NexmoClient({ debug: true }).login(USER_JWT).then(app => {
callButton.addEventListener("click", event => {
event.preventDefault();
let number = String(target_number);
console.log(number);
if (number !== ""){
app.callServer(number).catch(function(error){
console.log('debug: ',error);
});
} else {
statusElement.innerText = 'Please enter your phone number.';
}
});
app.on("member:call", (member, call) => {
// object selector reset
callButton.style.display = 'none';
closeButton.style.display = 'none';
hangupButton.style.removeProperty('display');
statusButton.style.removeProperty('display');
$('#wa-valid').removeAttr('checked');
// event when hangup button clicked
hangupButton.addEventListener("click", () => {
call.hangUp();
});
});
app.on("call:status:changed",(call) => {
console.log('Periodik : ', call.status);
// animation call
let statusAnimation = `<p class="saving">Call status: ${call.status}<span>.</span><span>.</span><span>.</span></p>`;
// assign call animation to nexmo status display
statusElement.innerHTML = statusAnimation;
// filter nexmo status condition
switch(call.status) {
case call.CALL_STATUS.STARTED:
console.log('Case call status: ', call.status);
break;
case call.CALL_STATUS.RINGING:
console.log('Case call status: ', call.status);
break;
case call.CALL_STATUS.FAILED:
inputCallStatus.value = call.status;
callStatusAnswered = false;
callButton.style.display = 'none';
hangupButton.style.display = 'none';
statusButton.style.removeProperty('display');
updateButton.style.removeProperty('display');
trashButton.style.removeProperty('display');
waContainer.style.removeProperty('display');
closeButton.style.removeProperty('dispaly');
nameContainer.style.removeProperty('display');
console.log('Case call status: ', call.status);
break;
case call.CALL_STATUS.CANCELLED:
inputCallStatus.value = call.status;
callStatusAnswered = false;
callButton.style.removeProperty('display');
hangupButton.style.display = 'none';
statusButton.style.display = 'none';
nameContainer.style.removeProperty('display');
updateButton.style.removeProperty('display');
trashButton.style.removeProperty('display');
waContainer.style.removeProperty('display');
closeButton.style.removeProperty('dispaly');
console.log('Case call status: ', call.status);
break;
case call.CALL_STATUS.COMPLETED:
callStatusCompleted = true;
callButton.style.display = 'none';
hangupButton.style.display = 'none';
updateButton.style.removeProperty('display');
closeButton.style.display = 'none';
statusButton.style.display = 'none';
campaign_result.setAttribute('required', 'required');
nameContainer.style.removeProperty('display');
campaignContainer.style.removeProperty('display');
dataTableAdminLeader.ajax.reload();
console.log('Case call status: ', call.status);
break;
case call.CALL_STATUS.ANSWERED:
// play sound
sndAnswered.play();
inputCallStatus.value = call.status;
callStatusAnswered = true;
callButton.style.display = 'none';
hangupButton.style.removeProperty('display');
nameContainer.style.removeProperty('display');
closeButton.style.display = 'none';
statusButton.style.display = 'none';
console.log('Case call status: ', call.status);
break;
default:
// BUSY
// REJECTED
// TIMEOUT
// UNANSWERED
inputCallStatus.value = call.status;
callStatusAnswered = false;
callButton.style.display = 'none';
hangupButton.style.display = 'none';
updateButton.style.removeProperty('display');
trashButton.style.removeProperty('display');
statusButton.style.display = 'none';
nameContainer.style.removeProperty('display');
waContainer.style.removeProperty('display');
closeButton.style.removeProperty('dispaly');
console.log('Case call status: ', call.status);
console.log('Case call status default: ', call.status);
break;
}
});
}).catch(function(){
alert('Network Problem, refresh page and try again later. Please contact dev team if this problem not fix in few minutes.');
console.error;
$('#phone-call-modal').modal('hide');
});
});
Vonage (Nexmo) Voice API 无法验证您的用户是否应该能够拨打他们在您的应用程序中有权访问的 phone 号码。听起来您已经为应用程序的用户提供了使用您的 Vonage API 凭据发起语音对话的能力。您的用户的验证逻辑必须在您的应用程序中。
您可以考虑的一个解决方案是,在发起新的语音通话之前,您可以检查您的数据库是否有用户访问权限。如果他们没有访问权限,您可以将他们重定向到应用程序中的另一个视图,如果他们有访问权限,您可以发起呼叫。 Laravel 有一整套 validation tooling 可能对您有所帮助。
我有客户服务应用程序使用 nexmo 和 laravel 作为框架在应用程序浏览器调用中使用。我有一些用户,每个用户在 table 中都有他们的列表 phone 号码,每一行都有联系操作按钮来调用。 phone 数字的目标是这样放在按钮中的:
<a href="#" class="btn btn-sm btn-info call-button" data-toggle="modal" data-number="6281299054899">Contact</a>
但用户可以检查元素并编辑这些按钮,然后输入他们想要的另一个 phone 数字。我如何防止这种作弊并在示例中提醒用户“您未授权呼叫此 phone 号码。”他们什么时候做那个动作?
这是我在单击 .call-button 时的处理程序:
dataTableAdminLeader.on('click', '.call-button', function(){
let id = $(this).data('id');
let master_number_id = $(this).data('master_numbers_id');
let target_number = $(this).data('number');
const trashButton = document.querySelector('.btn-trash');
const updateButton = document.querySelector(".btn-update");
trashButton.setAttribute('disabled', 'disabled');
updateButton.setAttribute('disabled', 'disabled');
$('#phone-call-modal').modal('show');
// input reset
document.querySelector('#target-phone').value = target_number;
document.querySelector('#id-edit').value = id;
document.querySelector('#master-numbers-id-edit').value = master_number_id;
document.querySelector('#member-id').value = $(this).data('id-member');
document.querySelector('#member-name').value = $(this).data('name');
trashButton.removeAttribute('disabled');
updateButton.removeAttribute('disabled');
// all constant needed for call
const USER_JWT = "{{ $jwt_token }}";
const phoneNumberInput = document.querySelector("#cs-phone");
const statusElement = document.querySelector("#status-call");
// button object selector
const callButton = document.querySelector(".btn-call");
callButton.setAttribute('disabled', 'disabled');
const hangupButton = document.querySelector(".btn-hangup");
const closeButton = document.querySelector('.btn-close');
closeButton.style.removeProperty('display');
const statusButton = document.querySelector('.btn-status');
// input object selector
let campaign_result = document.querySelector('#campaignresult');
let note_contacted = document.querySelector('#note_contacted');
let note_container = document.querySelector('.note_container');
let nameContainer = document.querySelector('.name-container');
let campaignContainer = document.querySelector('.campaign-container');
let waContainer = document.querySelector('.wa-container');
let inputCallStatus = document.querySelector('#call-status');
// call status check
let callStatusCompleted = false;
let callStatusAnswered = false;
// reset property
campaign_result.value = "";
note_container.style = 'display: none';
nameContainer.style = 'display: none';
// sound object
var sndAnswered = new Audio("{{ asset('storage/sounds/answered.wav') }}");
// listening to event
campaign_result.addEventListener('change', function(){
if(campaign_result.value != ''){
note_container.style.removeProperty('display');
note_contacted.setAttribute('required', 'required');
}else{
note_container.style = 'display: none';
note_contacted.removeAttribute('required');
}
});
// nexmo status reset
statusElement.innerText = '';
inputCallStatus.value = '';
// nexmo call button reset
callButton.style.display = "inline";
hangupButton.style.display = "none";
// timeouts set
setTimeout(() => {
callButton.removeAttribute('disabled');
}, 5000);
// nexmo object start
new NexmoClient({ debug: true }).login(USER_JWT).then(app => {
callButton.addEventListener("click", event => {
event.preventDefault();
let number = String(target_number);
console.log(number);
if (number !== ""){
app.callServer(number).catch(function(error){
console.log('debug: ',error);
});
} else {
statusElement.innerText = 'Please enter your phone number.';
}
});
app.on("member:call", (member, call) => {
// object selector reset
callButton.style.display = 'none';
closeButton.style.display = 'none';
hangupButton.style.removeProperty('display');
statusButton.style.removeProperty('display');
$('#wa-valid').removeAttr('checked');
// event when hangup button clicked
hangupButton.addEventListener("click", () => {
call.hangUp();
});
});
app.on("call:status:changed",(call) => {
console.log('Periodik : ', call.status);
// animation call
let statusAnimation = `<p class="saving">Call status: ${call.status}<span>.</span><span>.</span><span>.</span></p>`;
// assign call animation to nexmo status display
statusElement.innerHTML = statusAnimation;
// filter nexmo status condition
switch(call.status) {
case call.CALL_STATUS.STARTED:
console.log('Case call status: ', call.status);
break;
case call.CALL_STATUS.RINGING:
console.log('Case call status: ', call.status);
break;
case call.CALL_STATUS.FAILED:
inputCallStatus.value = call.status;
callStatusAnswered = false;
callButton.style.display = 'none';
hangupButton.style.display = 'none';
statusButton.style.removeProperty('display');
updateButton.style.removeProperty('display');
trashButton.style.removeProperty('display');
waContainer.style.removeProperty('display');
closeButton.style.removeProperty('dispaly');
nameContainer.style.removeProperty('display');
console.log('Case call status: ', call.status);
break;
case call.CALL_STATUS.CANCELLED:
inputCallStatus.value = call.status;
callStatusAnswered = false;
callButton.style.removeProperty('display');
hangupButton.style.display = 'none';
statusButton.style.display = 'none';
nameContainer.style.removeProperty('display');
updateButton.style.removeProperty('display');
trashButton.style.removeProperty('display');
waContainer.style.removeProperty('display');
closeButton.style.removeProperty('dispaly');
console.log('Case call status: ', call.status);
break;
case call.CALL_STATUS.COMPLETED:
callStatusCompleted = true;
callButton.style.display = 'none';
hangupButton.style.display = 'none';
updateButton.style.removeProperty('display');
closeButton.style.display = 'none';
statusButton.style.display = 'none';
campaign_result.setAttribute('required', 'required');
nameContainer.style.removeProperty('display');
campaignContainer.style.removeProperty('display');
dataTableAdminLeader.ajax.reload();
console.log('Case call status: ', call.status);
break;
case call.CALL_STATUS.ANSWERED:
// play sound
sndAnswered.play();
inputCallStatus.value = call.status;
callStatusAnswered = true;
callButton.style.display = 'none';
hangupButton.style.removeProperty('display');
nameContainer.style.removeProperty('display');
closeButton.style.display = 'none';
statusButton.style.display = 'none';
console.log('Case call status: ', call.status);
break;
default:
// BUSY
// REJECTED
// TIMEOUT
// UNANSWERED
inputCallStatus.value = call.status;
callStatusAnswered = false;
callButton.style.display = 'none';
hangupButton.style.display = 'none';
updateButton.style.removeProperty('display');
trashButton.style.removeProperty('display');
statusButton.style.display = 'none';
nameContainer.style.removeProperty('display');
waContainer.style.removeProperty('display');
closeButton.style.removeProperty('dispaly');
console.log('Case call status: ', call.status);
console.log('Case call status default: ', call.status);
break;
}
});
}).catch(function(){
alert('Network Problem, refresh page and try again later. Please contact dev team if this problem not fix in few minutes.');
console.error;
$('#phone-call-modal').modal('hide');
});
});
Vonage (Nexmo) Voice API 无法验证您的用户是否应该能够拨打他们在您的应用程序中有权访问的 phone 号码。听起来您已经为应用程序的用户提供了使用您的 Vonage API 凭据发起语音对话的能力。您的用户的验证逻辑必须在您的应用程序中。
您可以考虑的一个解决方案是,在发起新的语音通话之前,您可以检查您的数据库是否有用户访问权限。如果他们没有访问权限,您可以将他们重定向到应用程序中的另一个视图,如果他们有访问权限,您可以发起呼叫。 Laravel 有一整套 validation tooling 可能对您有所帮助。