### Backend (Node.
js and Express with MongoDB)
#### 1. Installation of libraries
```bash
npm install express mongoose passport passport-local passport-jwt express-validator bcrypt
```
#### 2. Passport configuration
```javascript
// config/passport.js
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const JwtStrategy = require('passport-jwt').Strategy;
const ExtractJwt = require('passport-jwt').ExtractJwt;
const bcrypt = require('bcrypt');
const User = require('../models/user');
passport.use('register', new LocalStrategy({
usernameField: 'username',
passwordField: 'password',
passReqToCallback: true,
}, async (req, username, password, done) => {
try {
// Data validation
req.checkBody('username', 'Username is required').notEmpty();
req.checkBody('password', 'Password is required').notEmpty();
req.checkBody('password', 'Password must be at least 6 characters long').isLength({ min: 6 });
const errors = req.validationErrors();
if (errors) {
return done(null, false, { message: errors[0].msg });
}
const existingUser = await User.findOne({ username });
if (existingUser) {
return done(null, false, { message: 'Username already taken' });
}
const hashedPassword = await bcrypt.hash(password, 10);
const newUser = new User({
username,
password: hashedPassword,
});
const savedUser = await newUser.save();
return done(null, savedUser);
} catch (error) {
return done(error);
}
}));
passport.use(new JwtStrategy({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: 'your_secret_key',
}, async (payload, done) => {
try {
const user = await User.findById(payload.id);
if (user) {
done(null, user);
} else {
done(null, false);
}
} catch (error) {
done(error, false);
}
}));
module.exports = passport;
```
#### 3. Models and Routes for Users and Results
```javascript
// models/user.js
const mongoose = require('mongoose');
const userSchema = new mongoose.Schema({
username: { type: String, required: true, unique: true },
password: { type: String, required: true },
});
const User = mongoose.model('User', userSchema);
module.exports = User;
```
```javascript
// models/result.js
const mongoose = require('mongoose');
const resultSchema = new mongoose.Schema({
userId: { type: String, required: true }, // Your user identification mechanism
score: { type: Number, required: true },
date: { type: Date, default: Date.now },
});
const Result = mongoose.model('Result', resultSchema);
module.exports = Result;
``` #### 4. Routes for Authentication, Resource Protection, and Receiving Questions
```javascript
// routes/auth.js
const express = require('express');
const router = express.Router();
const passport = require('../config/passport');
const jwt = require('jsonwebtoken');
router.post('/login', (req, res, next) => {
passport.authenticate('local', { session: false }, (err, user, info) => {
if (err) { return next(err); }
if (!user) { return res.status(401).json({ message: 'Invalid credentials' }); }
// Create and sign a JWT for the authenticated user
const token = jwt.sign({ id: user._id, username: user.username }, 'your_secret_key', { expiresIn:
'1h' });
return res.json({ token });
})(req, res, next);});
router.post('/register', (req, res, next) => {
passport.authenticate('register', { session: false }, (err, user, info) => {
if (err) { return next(err); }
if (!user) { return res.status(400).json({ message: info.message }); }
// Створення та підпис JWT для зареєстрованого користувача
const token = jwt.sign({ id: user._id, username: user.username }, 'your_secret_key', { expiresIn:
'1h' });
return res.status(201).json({ token });
})(req, res, next);
});
router.get('/profile', passport.authenticate('jwt', { session: false }), (req, res) => {
// Захищений ресурс, до якого може звертатися тільки аутентифікований користувач
res.json({ message: 'You have access to this protected resource!' });
});
module.exports = router;
```
```javascript
// routes/questions.js
const express = require('express');
const router = express.Router();
const Question = require('../models/question');
router.get('/', async (req, res) => {
try {
// Отримати випадкове питання з бази даних
const question = await Question.findOne().skip(Math.floor(Math.random() * await
Question.countDocuments()));
res.json(question);
} catch (error) {
res.status(500).json({ message: error.message });
}
});
module.exports = router;
```
#### 5. Загальний Маршрутизатор
```javascript
// routes/index.js
const express = require('express');
const router = express.Router();
const questionsRouter = require('./questions');
const
resultsRouter = require('./results');
const authRouter = require('./auth');
// Підключення маршрутів
router.use('/api/questions', questionsRouter);
router.use('/api/results', resultsRouter);
router.use('/api/auth', authRouter);
module.exports = router;
```
#### 6. Головний Файл Запуску Сервера (app.js або index.js)
```javascript
// app.js
const express = require('express');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const expressValidator = require('express-validator');
const passport = require('./config/passport');
const routes = require('./routes');
const app = express();
// Підключення до MongoDB (вам потрібно вказати свої параметри підключення)
mongoose.connect('mongodb://localhost:27017/your_database', {
useNewUrlParser: true,
useUnifiedTopology: true,
});
app.use(bodyParser.json());
app.use(expressValidator());
app.use(passport.initialize());
// Встановлення маршрутів
app.use('/', routes);
// Запуск сервера
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
});
```