Füge verbesserte Fehlerbehandlung und Wiederholungslogik zur Benutzerregistrierung im authController hinzu, aktualisiere die Router-Konfiguration für die Registrierungsseite und implementiere ein Dialogfeld zur Benutzerinteraktion in der RegisterContent-Komponente.
This commit is contained in:
@@ -3,6 +3,10 @@ const { User } = require('../models');
|
|||||||
const jwt = require('jsonwebtoken');
|
const jwt = require('jsonwebtoken');
|
||||||
const { addTokenToBlacklist } = require('../utils/blacklist');
|
const { addTokenToBlacklist } = require('../utils/blacklist');
|
||||||
|
|
||||||
|
function delay(ms) {
|
||||||
|
return new Promise(resolve => setTimeout(resolve, ms));
|
||||||
|
}
|
||||||
|
|
||||||
exports.register = async (req, res) => {
|
exports.register = async (req, res) => {
|
||||||
const { name, email, password } = req.body;
|
const { name, email, password } = req.body;
|
||||||
if (!name || !email || !password) {
|
if (!name || !email || !password) {
|
||||||
@@ -10,13 +14,52 @@ exports.register = async (req, res) => {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const hashedPassword = await bcrypt.hash(password, 10);
|
const hashedPassword = await bcrypt.hash(password, 10);
|
||||||
const user = await User.create({ name, email, password: hashedPassword, active: true });
|
console.log('Register: creating user', { email });
|
||||||
res.status(201).json({ message: 'Benutzer erfolgreich registriert', user });
|
|
||||||
|
const maxAttempts = 3;
|
||||||
|
let attempt = 0;
|
||||||
|
let createdUser = null;
|
||||||
|
let lastError = null;
|
||||||
|
|
||||||
|
while (attempt < maxAttempts && !createdUser) {
|
||||||
|
try {
|
||||||
|
createdUser = await User.create({ name, email, password: hashedPassword, active: true });
|
||||||
|
} catch (err) {
|
||||||
|
lastError = err;
|
||||||
|
// Spezifisch auf Lock-Timeout reagieren und erneut versuchen
|
||||||
|
if ((err.code === 'ER_LOCK_WAIT_TIMEOUT' || err?.parent?.code === 'ER_LOCK_WAIT_TIMEOUT') && attempt < maxAttempts - 1) {
|
||||||
|
const backoffMs = 300 * (attempt + 1);
|
||||||
|
console.warn(`Register: ER_LOCK_WAIT_TIMEOUT, retry in ${backoffMs}ms (attempt ${attempt + 1}/${maxAttempts})`);
|
||||||
|
await delay(backoffMs);
|
||||||
|
attempt++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!createdUser && lastError) {
|
||||||
|
console.error('Register error (after retries):', lastError);
|
||||||
|
return res.status(503).json({ message: 'Zeitüberschreitung beim Zugriff auf die Datenbank. Bitte erneut versuchen.' });
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Register: user created', { id: createdUser.id });
|
||||||
|
|
||||||
|
const safeUser = {
|
||||||
|
id: createdUser.id,
|
||||||
|
name: createdUser.name,
|
||||||
|
email: createdUser.email,
|
||||||
|
active: createdUser.active,
|
||||||
|
created_at: createdUser.created_at
|
||||||
|
};
|
||||||
|
|
||||||
|
return res.status(201).json({ message: 'Benutzer erfolgreich registriert', user: safeUser });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.name === 'SequelizeUniqueConstraintError') {
|
if (error.name === 'SequelizeUniqueConstraintError') {
|
||||||
return res.status(400).json({ message: 'Email-Adresse bereits in Verwendung' });
|
return res.status(400).json({ message: 'Email-Adresse bereits in Verwendung' });
|
||||||
}
|
}
|
||||||
res.status(500).json({ message: 'Ein Fehler ist aufgetreten' });
|
console.error('Register error:', error);
|
||||||
|
return res.status(500).json({ message: 'Ein Fehler ist aufgetreten', error: error.message });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -38,9 +81,9 @@ exports.login = async (req, res) => {
|
|||||||
return res.status(403).json({ message: 'Benutzerkonto ist nicht aktiv' });
|
return res.status(403).json({ message: 'Benutzerkonto ist nicht aktiv' });
|
||||||
}
|
}
|
||||||
const token = jwt.sign({ id: user.id, name: user.name, email: user.email }, 'zTxVgptmPl9!_dr%xxx9999(dd)', { expiresIn: '1h' });
|
const token = jwt.sign({ id: user.id, name: user.name, email: user.email }, 'zTxVgptmPl9!_dr%xxx9999(dd)', { expiresIn: '1h' });
|
||||||
res.status(200).json({ message: 'Login erfolgreich', token, 'user': user });
|
return res.status(200).json({ message: 'Login erfolgreich', token, 'user': user });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
res.status(500).json({ message: 'Ein Fehler ist aufgetreten' });
|
return res.status(500).json({ message: 'Ein Fehler ist aufgetreten' });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -52,9 +95,9 @@ exports.logout = async (req, res) => {
|
|||||||
const token = authHeader.replace('Bearer ', '');
|
const token = authHeader.replace('Bearer ', '');
|
||||||
try {
|
try {
|
||||||
addTokenToBlacklist(token);
|
addTokenToBlacklist(token);
|
||||||
res.status(200).json({ message: 'Logout erfolgreich' });
|
return res.status(200).json({ message: 'Logout erfolgreich' });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
res.status(500).json({ message: 'Ein Fehler ist beim Logout aufgetreten' });
|
return res.status(500).json({ message: 'Ein Fehler ist beim Logout aufgetreten' });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -19,10 +19,19 @@
|
|||||||
<p>
|
<p>
|
||||||
<router-link to="/forgot-password">Passwort vergessen?</router-link>
|
<router-link to="/forgot-password">Passwort vergessen?</router-link>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<div v-if="dialogVisible" class="dialog">
|
||||||
|
<div class="dialog-content">
|
||||||
|
<h3>{{ dialogTitle }}</h3>
|
||||||
|
<p>{{ dialogMessage }}</p>
|
||||||
|
<button type="button" @click="closeDialog">Schließen</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import axios from '../../axios';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'RegisterComponent',
|
name: 'RegisterComponent',
|
||||||
@@ -41,32 +50,27 @@ export default {
|
|||||||
methods: {
|
methods: {
|
||||||
async register() {
|
async register() {
|
||||||
try {
|
try {
|
||||||
const response = await fetch('/register', {
|
const response = await axios.post('/auth/register', {
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
name: this.name,
|
name: this.name,
|
||||||
email: this.email,
|
email: this.email,
|
||||||
password: this.password
|
password: this.password
|
||||||
})
|
|
||||||
});
|
});
|
||||||
if (response.ok) {
|
this.showDialog('Registrierung erfolgreich', response.data?.message || 'Ihr Konto wurde erfolgreich erstellt.');
|
||||||
await response.json();
|
this.name = '';
|
||||||
this.showDialog('Registrierung erfolgreich', 'Ihr Konto wurde erfolgreich erstellt.');
|
this.email = '';
|
||||||
} else {
|
this.password = '';
|
||||||
const error = await response.json();
|
|
||||||
this.showDialog('Fehler', error.message);
|
|
||||||
}
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.showDialog('Ein Fehler ist aufgetreten', err.message);
|
const message = err?.response?.data?.message || err?.message || 'Ein unbekannter Fehler ist aufgetreten';
|
||||||
|
this.showDialog('Fehler', message);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
showDialog(title, message) {
|
showDialog(title, message) {
|
||||||
this.dialogTitle = title;
|
this.dialogTitle = title;
|
||||||
this.dialogMessage = message;
|
this.dialogMessage = message;
|
||||||
this.dialogVisible = true;
|
this.dialogVisible = true;
|
||||||
|
},
|
||||||
|
closeDialog() {
|
||||||
|
this.dialogVisible = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -87,4 +91,22 @@ label {
|
|||||||
button {
|
button {
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
}
|
}
|
||||||
|
.dialog {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: rgba(0, 0, 0, 0.4);
|
||||||
|
}
|
||||||
|
.dialog-content {
|
||||||
|
background: #fff;
|
||||||
|
padding: 16px;
|
||||||
|
border-radius: 4px;
|
||||||
|
max-width: 420px;
|
||||||
|
width: 90%;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ router.beforeEach(async (to, from, next) => {
|
|||||||
const routes = generateRoutesFromMenu(store.state.menuData);
|
const routes = generateRoutesFromMenu(store.state.menuData);
|
||||||
routes.forEach(route => router.addRoute(route));
|
routes.forEach(route => router.addRoute(route));
|
||||||
addEditPagesRoute();
|
addEditPagesRoute();
|
||||||
|
addRegisterRoute();
|
||||||
router.addRoute({
|
router.addRoute({
|
||||||
path: '/:pathMatch(.*)*',
|
path: '/:pathMatch(.*)*',
|
||||||
components: {
|
components: {
|
||||||
@@ -83,6 +84,21 @@ function addEditPagesRoute() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addRegisterRoute() {
|
||||||
|
if (router.hasRoute('/register')) {
|
||||||
|
router.removeRoute('/register');
|
||||||
|
}
|
||||||
|
router.addRoute({
|
||||||
|
path: '/register',
|
||||||
|
components: {
|
||||||
|
default: () => import('./content/authentication/RegisterContent.vue'),
|
||||||
|
rightColumn: loadComponent('ImageContent')
|
||||||
|
},
|
||||||
|
name: 'register'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
addEditPagesRoute();
|
addEditPagesRoute();
|
||||||
|
addRegisterRoute();
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
|||||||
Reference in New Issue
Block a user