feat: Benutzerverwaltung als neuen Reiter in Einstellungen-Seite integriert

This commit is contained in:
ISA
2025-04-28 15:47:28 +02:00
parent 0efaedb059
commit 79a535feae
4 changed files with 184 additions and 1 deletions

View File

@@ -237,3 +237,82 @@ Angezeigt mit [Mermaid.js](https://mermaid-js.github.io/).
## 👋 Kontakt für Fragen
Bei Fragen oder Problemen bitte an das CPLv4.0 Entwicklungsteam wenden.
# 🔐 Benutzerverwaltung und Sicherheit
## Backend TLS-Authentifizierung
- **TLS-Authentifizierung** erfolgt über das Backend (Embedded-System, CPL).
- Wird genutzt für HTTPS-Verbindungen und verschlüsselte OPC UA-Kommunikation.
- TLS-Benutzername und Passwort werden **nicht** vom Frontend verwaltet.
- Diese Login-Daten dienen **nur der sicheren Netzwerkverbindung** (z.B. HTTPS, Zertifikate).
## Frontend-Admin-Login (eigene Benutzerverwaltung)
- Das **Frontend** besitzt eine eigene **Benutzerverwaltung** für erweiterte Funktionen.
- Beispiele für geschützte Funktionen:
- Firmware-Update der Kabelüberwachungsmodule
- Erweiterte Systemeinstellungen
### Benutzerstruktur
Benutzer werden definiert unter:
```text
/components/main/settingsPageComponents/config/users.ts
```
Beispiel für die Benutzerstruktur:
```ts
const USERS = {
AdminUser: {
username: "admin",
password: "$2a$10$xpq/.tcOJN/LXfzdCcCVrenlBh2nRlM1R1ISY7dd1q2qGWC9Fyd2G", // bcrypt Hash von "admin"
role: "Admin",
},
};
export default USERS;
```
### Sicherheit
- **Passwörter sind verschlüsselt** mit `bcryptjs`.
- Klartext-Passwörter werden **niemals** im Quellcode gespeichert.
### Rollenbeschreibung
| Benutzerrolle | Beschreibung |
| :------------------- | :-------------------------------------------------------------- |
| TLS-User (Backend) | Anmeldung für sichere HTTPS-Verbindung, keine Frontend-Funktion |
| AdminUser (Frontend) | Darf Firmware-Updates durchführen, Konfiguration ändern |
### Anleitung für Entwickler: Passwort-Hash erzeugen
Um ein neues Passwort zu erstellen, benutze folgendes Script:
```ts
import bcrypt from "bcryptjs";
const hash = bcrypt.hashSync("meinNeuesPasswort", 10);
console.log(hash); // Kopieren und in users.ts einfügen
```
**Hinweis:** Stelle sicher, dass das neue Passwort korrekt gehasht ist, bevor es ins Repository hochgeladen wird.
---
## Zusammenfassung
| Thema | Hinweis |
| :--------------------- | :-------------------------------------------------------- |
| TLS-Login (Backend) | Nur für Netzwerkverschlüsselung |
| Admin-Login (Frontend) | Schutz für kritische Funktionen |
| Passwort-Handling | Immer bcrypt verwenden |
| Benutzerdatei | `/components/main/settingsPageComponents/config/users.ts` |
---
**Stand:** 28. April 2025
**Projekt:** CPLv4.0 Weboberfläche

View File

@@ -0,0 +1,92 @@
"use client";
// /components/main/settingsPageComponents/UserManagementSettings.tsx
import React, { useState } from "react";
import { useDispatch } from "react-redux";
import { AppDispatch } from "../../../redux/store";
import { useAdminAuth } from "./hooks/useAdminAuth";
import handleAdminLogin from "./handlers/handleAdminLogin";
const UserManagementSettings: React.FC = () => {
const dispatch = useDispatch<AppDispatch>();
const { isAdminLoggedIn, logoutAdmin } = useAdminAuth(true);
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const [loginSuccess, setLoginSuccess] = useState(false);
const [error, setError] = useState("");
const handleLogin = async () => {
handleAdminLogin(
username,
password,
() => {
setLoginSuccess(true);
setError("");
},
(errorMsg) => {
setLoginSuccess(false);
setError(errorMsg);
},
dispatch
);
};
return (
<div className="p-6 md:p-3 bg-gray-100 max-w-5xl mr-auto">
<h2 className="text-sm md:text-md font-bold mb-4">
Benutzerverwaltung (nur Login)
</h2>
{/* Admin Login/Logout */}
<div className="flex flex-col gap-1">
{isAdminLoggedIn ? (
<button
type="button"
className="bg-littwin-blue text-white px-4 py-2 h-8 text-xs rounded whitespace-nowrap"
onClick={logoutAdmin}
>
Admin abmelden
</button>
) : (
<>
<div className="flex flex-row gap-3">
<input
type="text"
placeholder="Benutzername"
className="border border-gray-300 rounded h-8 p-1 w-full text-xs"
value={username}
onChange={(e) => setUsername(e.target.value)}
/>
<input
type="password"
placeholder="Passwort"
className="border border-gray-300 rounded h-8 p-1 w-full text-xs"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
<button
type="button"
className="bg-littwin-blue text-white px-4 py-2 h-8 text-xs rounded whitespace-nowrap"
onClick={handleLogin}
>
Admin anmelden
</button>
</div>
</>
)}
</div>
{loginSuccess && (
<p className="text-green-600 text-xs mt-2">Login erfolgreich!</p>
)}
{error && <p className="text-red-500 text-xs mt-2">{error}</p>}
{/*
// Benutzerverwaltungstabelle (kommt später)
<table>...</table>
*/}
</div>
);
};
export default UserManagementSettings;

View File

@@ -6,5 +6,5 @@
2: Patch oder Hotfix (Bugfixes oder kleine Änderungen).
*/
const webVersion = "1.6.292";
const webVersion = "1.6.293";
export default webVersion;

View File

@@ -6,6 +6,7 @@ import GeneralSettings from "../components/main/settingsPageComponents/GeneralSe
import OPCUAInterfaceSettings from "../components/main/settingsPageComponents/OPCUAInterfaceSettings";
import DatabaseSettings from "../components/main/settingsPageComponents/DatabaseSettings";
import NTPSettings from "../components/main/settingsPageComponents/NTPSettings";
import UserManagementSettings from "../components/main/settingsPageComponents/UserManagementSettings";
export default function Settings() {
const [activeTab, setActiveTab] = useState("tab1");
@@ -59,6 +60,16 @@ export default function Settings() {
>
NTP
</button>
<button
className={`px-4 py-2 ${
activeTab === "tab5"
? "border-b-2 border-blue-500 text-blue-500"
: ""
}`}
onClick={() => setActiveTab("tab5")}
>
Benutzerverwaltung
</button>
</div>
{/* Tab-Inhalt */}
@@ -67,6 +78,7 @@ export default function Settings() {
{activeTab === "tab2" && <OPCUAInterfaceSettings />}
{activeTab === "tab3" && <DatabaseSettings />}
{activeTab === "tab4" && <NTPSettings />}
{activeTab === "tab5" && <UserManagementSettings />}
</div>
</div>
);