Can I restrict access to all routes except one in vue-router? Is this a safe practice? Should I explore alternative methods for achieving this?

I am looking to create an online exam consisting of 5 pages, each with a countdown timer set at 120 seconds and 4 questions on each page. Once the timer runs out, users will be automatically redirected to the next page, or they can manually click the "next" button before that.

Utilizing Laravel 5.4 and VueJs, I have implemented an Ajax request for every question answered by the user. However, my main goal is to prevent users from navigating back to previous pages or viewing other pages until the designated time limit has elapsed. Is this even feasible?

My plan is to develop this application using Vuejs and vue-router, although I am unsure about how to integrate this functionality using vue-router. Despite conducting research, I haven't found much information regarding this particular issue!

Alternatively, should I consider abandoning vue-router and just implement a simple router of my own, like:

$("#page1").show();
$("#page2").hide();
$("#page3").hide();
.
.
// after 120 secs 
$("#page1").hide();
$("#page2").show();
$("#page3").hide();
.
.
 // Nevertheless, I believe this approach may not provide adequate security!

Any insights or suggestions would be highly valued. Thank you in advance.

UPDATE: This exam allows users to view a list of randomly chosen English words sourced from the words table exclusively! Users then proceed to click on any word whose meaning they know, triggering an ajax request for each selection to save the word's ID in the results table. Additionally, there exists a fake_words table wherein 50 random words are selected alongside genuine ones. If a user clicks on fake words more than 3 times, the test will result in failure. The final outcome will reveal the user's vocabulary proficiency level.

UPDATE 2: Although I attempted to implement this functionality using vue-router, I realized that all questions are randomly fetched from the database in one query, sent (via ajax) to the browser before the exam commences. This begs the question - should I segregate them into separate arrays and allocate each array to a distinct page? Do I have no choice but to do so? Can't I simply use a single v-for loop for all questions? Suppose I opt to modify the number of questions; would this necessitate manual code updates and creating new vue-router pages or removing existing ones?

Answer №1

If you are dealing with high-risk code, such as an exam, it is important to reassess your approach: "Never trust the client". Consider implementing backend solutions to address potential security issues.

1) Secure the endpoint using middleware that:

2) Generates a timestamp when the page is visited

3) Prevents users from submitting a new post (answer) after 120 seconds

Note: It's essential for users to answer online as well for better security. If the question is displayed in the browser window, users can always cache it and even take screenshots regardless of encryption measures.

edit: Utilize pagination to present questions one at a time within a specific timeframe.

edit 2: Implement a feature to send a notification to the server if devtools are opened. Check out https://github.com/sindresorhus/devtools-detect

Answer №2

Maybe these code snippets could provide some assistance:

let application = new Vue({
    element: '#application',
    data: {
        firstStep: 1,
    }
});

<step v-if="step==1"></step>

timeHandler = setInterval(function() {
    moveForwardToNextStep(2);
    this.$parent.firstStep = 0;
}.bind(this), 12000);

Answer №3

When it comes to security, the choice of a JS framework may not have a significant impact. Vue.js is a solid option for development. Here's a snippet of code to help you get 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 () {
        var url = 'https://myapi.com/question?curQuestionNo=' + this.curQuestionNo;

        axios.get(url)
          .then(res => {
            this.question = res.question;
            this.curQuestionNo++;
            this.stopTimer();
            if(this.hasNextQuestion()) {
              this.startTimer();
            }
          })
          .catch(() => {
            // handle errors here
          });
      },
      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) {
        var url = 'https://myapi.com/mark-complete?curQuestionNo=' + this.curQuestionNo;

        axios.post(url) 
          .then(res => {
            this.fetchQuestion();
          })
          .catch(() => {
            // error handling
          });
      },
      hasNextQuestion () {
        return this.maxQuestions - (this.curQuestionNo + 1) > 0;
      }
    },
    created () {
      this.nextQuestion();      

    }
  }
</script>

For server-side implementation, consider the following approach:

  1. Send one question at a time per request to the client.
  2. Ensure that the user has answered the previous question or the allowed time has expired before returning the next question. Keep track of the last answered question number (or expiry time) per user in the data store. The server should only send the next question after verifying this information.

Sample Code:

Route::get('question', function(){
    $curQuestionNo = intVal(Input::get('curQuestionNo'));
    $user = User::find($userId); 
    if($user->current_question_number === $curQuestionNo) {
      $question = Question::where('question_no', $curQuestionNo + 1);
      $question->sent_at = time(); 
      return $question
    } else {
      // deny access
    }
});

Route::post('mark-complete', function(){
    $curQuestionNo = intVal(Input::get('curQuestionNo'));
    $user = User::find($userId); 
    $question = Question::find($curQuestionNo);
    if($question->sent_at > 120 seconds) {
     // do not record answers
    } else {
      // record answers
    }
    $user->current_question_number = $curQuestionNo;
    $user->save();
});    

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Converting RSS title to HTML format with the help of JavaScript

I am currently working on populating a menu on a webpage with the 5 latest topics from our site's RSS newsfeed using JavaScript (specifically jQuery version 1.9.1). I have been searching for a solution, but most answers I find reference deprecated scr ...

The request to sign up at 'https://identitytoolkit.googleapis.com/v1/accounts:/signUp? from the origin 'http://localhost:8080' has been denied

My attempt to create a new user in Firebase using Axios in Vue.js is resulting in an error message regarding CORS policy. The specific error states: "Access to XMLHttpRequest at 'https://identitytoolkit.googleapis.com/v1/accounts:/signUp?key=AIzaSyDvZ ...

PHP sending only a single space in an email

My HTML form works perfectly fine, except for one field! The issue arises with a particular text field that I fill out using a button and a short JavaScript function. Could this be causing a conflict with the PHP code? The problematic text field is: inpu ...

Using jQuery to iterate through elements of a PHP array

I've got a PHP array that outputs like this: Array ( [0] => Array ( [title] => Much title [end] => Such end [start] => Very start ) [1] => Array ( [title] ...

Prisma encountered an error with the database string: Invalid MongoDB connection string

I'm encountering an issue with my MongoDB data provider, as I am informed that my connection string is invalid. The specific error message states: The provided database string is invalid. MongoDB connection string error: Missing delimiting slash betw ...

Switching PHP include on an HTML page using JavaScript

I've been attempting to modify the content of the div with the ID "panel_alumno" using a JavaScript function that triggers when a button is clicked. My goal is to display a different table each time the button is pressed, but so far, I haven't be ...

I have a few inquiries about my nodejs studies. Can you assist me, please?

As I delve into my studies of nodejs, some burning questions have arisen. Is it true that nodejs supports all JavaScript? In the official documentation, it mentions using the latest v8 engine. However, I have reservations about whether all JavaScript ...

Guidelines for triggering an event on the select element in Vuejs only when a specific condition is satisfied

Is there a way to only open the modal when the selected option in the Select component is "I have a coupon"? <Select placeholder="Want to get a discount" @click="openModal" v-model="coupon.source&q ...

What are some best practices for managing object-level variables in TypeScript and Vue.js?

Uncertain about the optimal approach, I am looking to create a component and leverage some object level variables. Consider the example below: import Vue from "vue" import * as paper from "paper" export default Vue.extend({ template: ` <d ...

How to distinguish if a background tab is open using JavaScript or jQuery

Is there a way to determine if a new tab with target set to "_blank" was opened from the current page using JavaScript or jQuery? I want to increment a counter in the original window every time a background tab is opened. For example, if a link is clicked ...

React input field keeps losing focus during re-render operations

My current project involves using React to create an input text that displays a value from an in-memory data store and updates the store when the input value changes, triggering a re-render. However, I am facing an issue where the input text loses focus du ...

Having trouble retrieving a specific object from an array using EJS

When re-rendering my form with any errors, I am able to display the errors in a list. However, I would like to access each error individually to display them under the invalid input instead of all at the bottom of the form. Here is what I have tried so f ...

Manipulating a textarea in jQuery by inserting a string and selecting a specific portion of it

Just as seen on SO with the B button: **bold text** Including that bold text is automatically highlighted and the cursor is placed right before the b ...

Accessing the database variable in controller files with Node.js

I am new to node.js and currently using lowdb for my database as I start building my app. In the index.js file, I have set up my Express server along with routes: var express = require('express'); var app = express(); var bodyParser = require(& ...

Tips for avoiding page reloading with the use of vue, vue recaptcha, and axios

My experience with Vue and coding, in general, has gotten rusty. Currently, I'm tackling a small project that involves a form communicating with Python on the backend. While the backend part seems to be covered (knock on wood), the front end is giving ...

Is there a way to display an alert using JavaScript that only appears once per day?

I've created a website that displays an alert to the user upon logging in. Currently, the alert is shown each time the user logs in, but I'm looking to make it display only once per day at initial page loading. How can I achieve this? Below i ...

Getting the WebElement object by manually clicking an element while in an active WebDriver Session

I am currently developing a Java Swing application for managing object repositories in Selenium scripts. This application will launch a WebDriver instance and allow users to manually navigate to the desired element for inspection. My goal is to capture th ...

Exploring the world of JMeter: capturing sessions with JavaScript and jQuery

I need to capture a user session in order to conduct a performance test. I have been using the JMeter HTTP(S) Test Script Recorder, but unfortunately it is not recognizing javascript and jquery. The error message I'm receiving is: JQuery is not def ...

Creating UV coordinates in THREE.js

I've been working on bringing a model into a scene using the OBJ loader in THREE.js. Initially, I had no issues importing the geometry and visualizing it with MeshNormalMaterial. However, as soon as I tried to use textures that require UV coordinates ...

Struggling to create a regular expression for a particular scenario

I'm dealing with nodes and currently faced with the task of applying a UNIX-like grep command to filter out specific content from an HTTP GET response. Below is the raw text received as the body variable: <?xml version="1.0" encoding="UTF-8" stand ...