是否可以在 vue-router 中锁定除一条以外的所有路由?安全吗?或者我应该使用另一种方法?
Is it Possible to lock all routes except one, in vue-router ? Is it secure? Or maybe I should use another method?
我想做一个在线考试,这个考试有 5 页,有一个倒计时计时器(120 秒),每页有 4 个问题。 120 秒后用户将自动转到下一页,或者他们可以在此之前单击下一步按钮。
Laravel5.4 和 VueJs,用户回答的每个问题都有一个 Ajax 请求。我想要的是阻止用户看到其他页面。每个页面最多只能显示 120 秒。用户不应该能够点击后退按钮并查看之前的页面。这可能吗?
我想用 Vuejs
和 vue-router
创建这个应用程序,但我不知道如何用 vue-router
实现它,我做了一些研究,但没有太多结果!
或者我不应该使用 vue-router
,而是使用我自己的简单路由器,例如:
$("#page1").show();
$("#page2").hide();
$("#page3").hide();
.
.
// after 120 secs
$("#page1").hide();
$("#page2").show();
$("#page3").hide();
.
.
// i think this is not secure !
如有任何想法,我们将不胜感激。谢谢。
更新:
在此考试中,用户可以看到从 words
table 中随机选择的 English words
的列表,除此之外什么都没有!用户点击他认为他知道其含义的每一个词!并且每次点击 ajax 请求保存 results
table 中单词的 id。另外,除了actual words
之外,还有一个fake_words
table是随机选择50个词,如果用户点击假词超过3次,测试就会失败。最终结果将告诉用户他有多少词汇量。
更新 2: 我试着用 vue-router
来做这个,但在开始编码之前,我想也许它不应该用 vue-router
来实现因为所有问题都是在一个查询中随机从数据库中获取的,所以在考试开始之前,所有问题都被发送(ajax)到浏览器,现在我该怎么办?将它们分成不同的数组并将每个问题数组发送到我的一个页面?我必须这样做吗?我不能只为他们使用一个 v-for
吗?如果我决定更改问题数量怎么办?然后我想我每次都必须触摸我的代码并为 vue-router
创建新页面或删除其中一个页面。
如果这真的是像考试一样的高风险代码,您应该重新考虑您的方法:“Never trust the client”。我建议为后端编写代码来解决你的问题。
1) 使用中间件保护端点,即:
2) 在访问页面时创建时间戳
3) 120 秒后不接受用户的新post(回答)
注意:我希望他们也必须在线回答,否则无法确保安全:如果将问题放在浏览器中 window,他们可以始终缓存此问题,即使是最好的他们可以给屏幕拍照的代码。
编辑: 我会使用 pagination 一个一个地发送问题,但有时间限制。
edit 2: 当开发工具打开时,我也会向服务器发送通知。你可以试试https://github.com/sindresorhus/devtools-detect
也许这些片段会有所帮助:
const app = new Vue({
el: '#app',
data: {
stepOne: 1,
}
});
<step v-if="step==1"></step>
timeInterval = setInterval(function() {
goToNextStep(2);
this.$parent.stepOne = 0;
}.bind(this), 12000);
就安全性而言,选择JS框架影响不大。 Vue.js 是一个很好的选择。这是一个可以帮助您入门的示例代码:
<template>
<div>
<div id="question" v-if="question">
{{question}}
<button @click="nextQuestion();" v-if="hasNextQuestion()"></button>
</div>
</div>
</template>
<script>
export default {
data() {
return {
curQuestionNo: 0,
maxQuestions: 4
question: null,
timer: null
}
},
methods: {
fetchQuestion () {
// return one question at a time from the server. Storing all questions on the client is not recommended.
var url = 'https://myapi.com/question?curQuestionNo=' + this.curQuestionNo;
axios.get(url) // or however you prefer to make ajax calls
.then(res => {
this.question = res.question;
this.curQuestionNo++;
this.stopTimer();
if(this.hasNextQuestion()) {
this.startTimer();
}
})
.catch(() => {
// do some error handling
});
},
startTimer () {
this.timer = setTimeout(() => {
this.nextQuestion();
}, 120 * 1000);
},
stopTimer () {
clearTimeout(this.timer);
},
nextQuestion () {
if(this.curQuestionNo > 0) {
this.markAnswered(function() {
this.fetchQuestion();
})
} else {
this.fetchQuestion();
}
},
markAnswered (cb) {
// record the answered question on server
// server should only send the next question after this
var url = 'https://myapi.com/mark-complete?curQuestionNo=' + this.curQuestionNo;
axios.post(url)
.then(res => {
this.fetchQuestion();
})
.catch(() => {
// do some error handling
});
},
hasNextQuestion () {
return this.maxQuestions - (this.curQuestionNo + 1) > 0;
}
},
created () {
this.nextQuestion();
}
}
</script>
在服务器端,我推荐类似下面的方法:
- 每个请求向客户发送一个问题
- 确保在 API returns 给客户的下一个问题之前,用户已经回答了上一个问题或允许回答问题的时间范围已经过期。这可以非常简单地实现,只需在您的数据存储中保留一个计数器来记录每个用户最后回答(或过期)的问题编号。不应允许用户回答等于或小于记录中数字的问题。服务器应该只发送比记录中的数字大一的问题编号。
示例代码(不确定 Laravel 5 语法,但您应该明白了):
Route::get('question', function(){
$curQuestionNo = intVal(Input::get('curQuestionNo'));
$user = User::find($userId); // get the logged in user, for example
if($user->current_question_number === $curQuestionNo) {
$question = Question::where('question_no', $curQuestionNo + 1);
$question->sent_at = time(); // store the time when the question was sent
return $question
} else {
// deny access
}
});
Route::post('mark-complete', function(){
$curQuestionNo = intVal(Input::get('curQuestionNo'));
$user = User::find($userId); // get the logged in user, for example
$question = Question::find($curQuestionNo);
if($question->sent_at > 120 seconds) {
// do not record answers
} else {
// record answers
}
$user->current_question_number = $curQuestionNo;
$user->save();
});
我想做一个在线考试,这个考试有 5 页,有一个倒计时计时器(120 秒),每页有 4 个问题。 120 秒后用户将自动转到下一页,或者他们可以在此之前单击下一步按钮。
Laravel5.4 和 VueJs,用户回答的每个问题都有一个 Ajax 请求。我想要的是阻止用户看到其他页面。每个页面最多只能显示 120 秒。用户不应该能够点击后退按钮并查看之前的页面。这可能吗?
我想用 Vuejs
和 vue-router
创建这个应用程序,但我不知道如何用 vue-router
实现它,我做了一些研究,但没有太多结果!
或者我不应该使用 vue-router
,而是使用我自己的简单路由器,例如:
$("#page1").show();
$("#page2").hide();
$("#page3").hide();
.
.
// after 120 secs
$("#page1").hide();
$("#page2").show();
$("#page3").hide();
.
.
// i think this is not secure !
如有任何想法,我们将不胜感激。谢谢。
更新:
在此考试中,用户可以看到从 words
table 中随机选择的 English words
的列表,除此之外什么都没有!用户点击他认为他知道其含义的每一个词!并且每次点击 ajax 请求保存 results
table 中单词的 id。另外,除了actual words
之外,还有一个fake_words
table是随机选择50个词,如果用户点击假词超过3次,测试就会失败。最终结果将告诉用户他有多少词汇量。
更新 2: 我试着用 vue-router
来做这个,但在开始编码之前,我想也许它不应该用 vue-router
来实现因为所有问题都是在一个查询中随机从数据库中获取的,所以在考试开始之前,所有问题都被发送(ajax)到浏览器,现在我该怎么办?将它们分成不同的数组并将每个问题数组发送到我的一个页面?我必须这样做吗?我不能只为他们使用一个 v-for
吗?如果我决定更改问题数量怎么办?然后我想我每次都必须触摸我的代码并为 vue-router
创建新页面或删除其中一个页面。
如果这真的是像考试一样的高风险代码,您应该重新考虑您的方法:“Never trust the client”。我建议为后端编写代码来解决你的问题。
1) 使用中间件保护端点,即:
2) 在访问页面时创建时间戳
3) 120 秒后不接受用户的新post(回答)
注意:我希望他们也必须在线回答,否则无法确保安全:如果将问题放在浏览器中 window,他们可以始终缓存此问题,即使是最好的他们可以给屏幕拍照的代码。
编辑: 我会使用 pagination 一个一个地发送问题,但有时间限制。
edit 2: 当开发工具打开时,我也会向服务器发送通知。你可以试试https://github.com/sindresorhus/devtools-detect
也许这些片段会有所帮助:
const app = new Vue({
el: '#app',
data: {
stepOne: 1,
}
});
<step v-if="step==1"></step>
timeInterval = setInterval(function() {
goToNextStep(2);
this.$parent.stepOne = 0;
}.bind(this), 12000);
就安全性而言,选择JS框架影响不大。 Vue.js 是一个很好的选择。这是一个可以帮助您入门的示例代码:
<template>
<div>
<div id="question" v-if="question">
{{question}}
<button @click="nextQuestion();" v-if="hasNextQuestion()"></button>
</div>
</div>
</template>
<script>
export default {
data() {
return {
curQuestionNo: 0,
maxQuestions: 4
question: null,
timer: null
}
},
methods: {
fetchQuestion () {
// return one question at a time from the server. Storing all questions on the client is not recommended.
var url = 'https://myapi.com/question?curQuestionNo=' + this.curQuestionNo;
axios.get(url) // or however you prefer to make ajax calls
.then(res => {
this.question = res.question;
this.curQuestionNo++;
this.stopTimer();
if(this.hasNextQuestion()) {
this.startTimer();
}
})
.catch(() => {
// do some error handling
});
},
startTimer () {
this.timer = setTimeout(() => {
this.nextQuestion();
}, 120 * 1000);
},
stopTimer () {
clearTimeout(this.timer);
},
nextQuestion () {
if(this.curQuestionNo > 0) {
this.markAnswered(function() {
this.fetchQuestion();
})
} else {
this.fetchQuestion();
}
},
markAnswered (cb) {
// record the answered question on server
// server should only send the next question after this
var url = 'https://myapi.com/mark-complete?curQuestionNo=' + this.curQuestionNo;
axios.post(url)
.then(res => {
this.fetchQuestion();
})
.catch(() => {
// do some error handling
});
},
hasNextQuestion () {
return this.maxQuestions - (this.curQuestionNo + 1) > 0;
}
},
created () {
this.nextQuestion();
}
}
</script>
在服务器端,我推荐类似下面的方法:
- 每个请求向客户发送一个问题
- 确保在 API returns 给客户的下一个问题之前,用户已经回答了上一个问题或允许回答问题的时间范围已经过期。这可以非常简单地实现,只需在您的数据存储中保留一个计数器来记录每个用户最后回答(或过期)的问题编号。不应允许用户回答等于或小于记录中数字的问题。服务器应该只发送比记录中的数字大一的问题编号。
示例代码(不确定 Laravel 5 语法,但您应该明白了):
Route::get('question', function(){
$curQuestionNo = intVal(Input::get('curQuestionNo'));
$user = User::find($userId); // get the logged in user, for example
if($user->current_question_number === $curQuestionNo) {
$question = Question::where('question_no', $curQuestionNo + 1);
$question->sent_at = time(); // store the time when the question was sent
return $question
} else {
// deny access
}
});
Route::post('mark-complete', function(){
$curQuestionNo = intVal(Input::get('curQuestionNo'));
$user = User::find($userId); // get the logged in user, for example
$question = Question::find($curQuestionNo);
if($question->sent_at > 120 seconds) {
// do not record answers
} else {
// record answers
}
$user->current_question_number = $curQuestionNo;
$user->save();
});