Is it possible to block all but one route in vue-router? It is safe? Or maybe I should use a different method?

I want to create an online exam, this exam has 5 pages, each page has a countdown timer (120 seconds) and 4 questions. After 120 seconds, users are automatically transferred to the next page, or they can click on the next button before.

Laravel5.4 and VueJs, there is an Ajax request for every question that the user answers. I want the user not to see other pages. Each page should be visible for a maximum of 120 seconds. The user should not be able to click the "Back" button and see previous pages. Is it even possible?

I want to create this application with Vuejs and vue-router , but I do not know how to implement this with vue-router , I did some research, but got few results!

Or maybe I should not use vue-router and use my own simple router, for example:

 $("#page1").show(); $("#page2").hide(); $("#page3").hide(); . . // after 120 secs $("#page1").hide(); $("#page2").show(); $("#page3").hide(); . . // i think this is not secure ! 

Any thoughts are appreciated. Thanks.

UPDATE: In this exam, the user can see a list of English words , randomly selected from the words table, and nothing more! The user clicks on every word that he believes knows its meaning! And an ajax request for each click to save the word id in the results table. In addition, there is a table fake_words , in which 50 words are randomly selected instead of actual words , if the user clicks on fake words more than 3 times, the test will fail. The end result will tell the user how many vocabulary skills he has.

UPDATE 2: I tried to do this using vue-router , but before starting the code, I thought that perhaps this should not be implemented using vue-router , because all questions are randomly obtained from the DB in one query, then before the beginning of the exam they are all sent (ajax) to the browser, now what should I do? Cut them into separate arrays and send each array of questions to one of my pages? I must do it? can I use only one v-for ? What if I decide to change the number of questions? Then I think that I have to touch my code every time and create a new page for vue-router or delete one of the pages.

+5
source share
3 answers

In terms of security, choosing a JS framework will have little impact, if any. Vue.js is a great choice. Here is some sample code to get you started:

 <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> 

At the end of the server, I recommend something like the following approach:

  • Send one question to customer request
  • Make sure that the user answered the previous question or the time period for which it is allowed to answer the question has expired before the API returns the next question to the client. This can be achieved quite simply, just keep the counter in your data store to save the last response number (or expired) for each user. The user is not allowed to answer the question number equal to or less than the number in the record. The server should send only the question number, which is greater than the number indicated in the record.

Sample code (not sure about Laravel 5 syntax, but you should get an idea):

 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(); }); 
+1
source

If this is a really high risk code, such as an exam, you should reconsider your approach: " Never trust a client ." I would suggest writing code for the backend to solve your problem.

1) Protect the endpoint with middleware that:

2) creates a timestamp when visiting the page

3) Does not accept a new post (response) from the user after 120 seconds

Note. I hope that they should also answer on the Internet, otherwise it cannot be protected: if a question is inserted into the browser window, they can always cache this question, even with the best code that can take a screenshot.

edit: I would use pagination to send questions 1 on one with a deadline.

edit 2: I also sent a notification to the server when opening devtools. You can try https://github.com/sindresorhus/devtools-detect

+3
source

Perhaps these snippets will help:

 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); 
+2
source

Source: https://habr.com/ru/post/1270079/


All Articles