structure/first-structure #1
167
app/Controllers/AuthController.php
Normal file
167
app/Controllers/AuthController.php
Normal file
@ -0,0 +1,167 @@
|
||||
<?php
|
||||
|
||||
// Strenge Typprüfung für Parameter- und Rückgabetypen aktivieren.
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Services\Ldap\LdapAuthService;
|
||||
|
||||
/**
|
||||
* Zuständig für alles rund um den Login:
|
||||
* - Login-Formular anzeigen
|
||||
* - Login-Daten verarbeiten (Authentifizierung gegen LDAP/AD)
|
||||
* - Logout durchführen
|
||||
*/
|
||||
class AuthController
|
||||
{
|
||||
/** @var array<string, mixed> Konfigurationswerte der Anwendung (aus config.php) */
|
||||
private array $config;
|
||||
|
||||
/** @var LdapAuthService Service, der die eigentliche LDAP/AD-Authentifizierung übernimmt */
|
||||
private LdapAuthService $ldapAuthService;
|
||||
|
||||
/**
|
||||
* Übergibt die Konfiguration an den Controller und initialisiert den LDAP-Authentifizierungsservice.
|
||||
*
|
||||
* @param array<string, mixed> $config Vollständige Konfiguration aus config.php
|
||||
*/
|
||||
public function __construct(array $config)
|
||||
{
|
||||
// Komplette Config in der Instanz speichern (z. B. für Zugriff auf security- oder ldap-Settings)
|
||||
$this->config = $config;
|
||||
|
||||
// LdapAuthService mit dem Teilbereich "ldap" aus der Konfiguration initialisieren.
|
||||
// Wenn 'ldap' nicht gesetzt ist, wird ein leeres Array übergeben (Fail fast erfolgt dann im Service).
|
||||
$this->ldapAuthService = new LdapAuthService($config['ldap'] ?? []);
|
||||
}
|
||||
|
||||
/**
|
||||
* Zeigt das Login-Formular an.
|
||||
* Optional kann eine Fehlermeldung übergeben werden, die in der View dargestellt wird.
|
||||
*/
|
||||
public function showLoginForm(?string $errorMessage = null): void
|
||||
{
|
||||
// Pfad zur Login-View (Template-Datei) ermitteln.
|
||||
$viewPath = __DIR__ . '/../../public/views/login.php';
|
||||
|
||||
// Variable für die View vorbereiten (wird in der eingebundenen Datei verwendet).
|
||||
$error = $errorMessage;
|
||||
|
||||
// Falls die View-Datei (noch) nicht existiert, einen Fallback-HTML-Output verwenden.
|
||||
if (file_exists($viewPath) === false) {
|
||||
$this->renderInlineLogin($error);
|
||||
return;
|
||||
}
|
||||
|
||||
// View-Datei einbinden. Variablen aus dieser Methode (z. B. $error) sind dort verfügbar.
|
||||
require $viewPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verarbeitet das Login-Formular:
|
||||
* - Liest Benutzername und Passwort aus $_POST
|
||||
* - Ruft den LdapAuthService zur Authentifizierung auf
|
||||
* - Setzt bei Erfolg die Session und leitet zum Dashboard weiter
|
||||
* - Zeigt bei Fehlern erneut das Login-Formular mit Fehlermeldung an
|
||||
*/
|
||||
public function processLogin(): void
|
||||
{
|
||||
// Formulardaten aus dem POST-Request lesen.
|
||||
$username = trim($_POST['username'] ?? '');
|
||||
$password = (string)($_POST['password'] ?? '');
|
||||
|
||||
try {
|
||||
// Versuch, den Benutzer per LDAP/AD zu authentifizieren.
|
||||
// true = Authentifizierung erfolgreich
|
||||
// false = Anmeldedaten fachlich ungültig (Benutzer/Passwort falsch)
|
||||
$authenticated = $this->ldapAuthService->authenticate($username, $password);
|
||||
} catch (\Throwable $exception) {
|
||||
// Technischer Fehler (z. B. LDAP-Server nicht erreichbar, falsche Konfiguration).
|
||||
// In diesem Fall wird eine technische Fehlermeldung im Login-Formular angezeigt.
|
||||
$this->showLoginForm('Technischer Fehler bei der Anmeldung: ' . $exception->getMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
// Fachlich fehlgeschlagene Anmeldung (z. B. falsches Passwort).
|
||||
if ($authenticated === false) {
|
||||
$this->showLoginForm('Benutzername oder Passwort ist ungültig.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Ab hier ist die Anmeldung erfolgreich.
|
||||
|
||||
// Session-Key für den eingeloggten Benutzer aus der Konfiguration lesen.
|
||||
// Wenn nicht gesetzt, wird "admin_user" als Standard verwendet.
|
||||
$sessionKey = $this->config['security']['session_key_user'] ?? 'admin_user';
|
||||
|
||||
// Benutzerinformationen in der Session hinterlegen.
|
||||
// Diese Daten werden später von requireLogin() ausgewertet.
|
||||
$_SESSION[$sessionKey] = [
|
||||
'username' => $username,
|
||||
'login_at' => date('c'), // ISO-8601 Datum/Zeit der Anmeldung
|
||||
];
|
||||
|
||||
// Nach erfolgreicher Anmeldung zum Dashboard weiterleiten.
|
||||
header('Location: index.php?route=dashboard');
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Meldet den aktuell eingeloggten Benutzer ab, indem der entsprechende Session-Eintrag entfernt wird,
|
||||
* und leitet anschließend zurück auf die Login-Seite.
|
||||
*/
|
||||
public function logout(): void
|
||||
{
|
||||
// Session-Key für den eingeloggten Benutzer aus der Konfiguration lesen.
|
||||
$sessionKey = $this->config['security']['session_key_user'] ?? 'admin_user';
|
||||
|
||||
// Eintrag aus der Session entfernen → Benutzer gilt als ausgeloggt.
|
||||
unset($_SESSION[$sessionKey]);
|
||||
|
||||
// Zur Login-Seite zurückleiten.
|
||||
header('Location: index.php?route=login');
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fallback-Ausgabe für das Login-Formular, falls noch keine separate View-Datei existiert.
|
||||
* Gibt direkt HTML aus (inline-Template).
|
||||
*/
|
||||
private function renderInlineLogin(?string $errorMessage): void
|
||||
{
|
||||
?>
|
||||
<!doctype html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>AD Admin Tool – Login</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>AD Admin Tool – Login</h1>
|
||||
|
||||
<?php if ($errorMessage !== null): ?>
|
||||
<!-- Fehlermeldung ausgeben, HTML-Ausgabe wird dabei sicher maskiert -->
|
||||
<p style="color: red;"><?php echo htmlspecialchars($errorMessage, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); ?></p>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- Einfaches Login-Formular, das per POST an die Route "login.submit" gesendet wird -->
|
||||
<form action="index.php?route=login.submit" method="post">
|
||||
<div>
|
||||
<label for="username">Benutzername:</label>
|
||||
<input type="text" id="username" name="username" required>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="password">Passwort:</label>
|
||||
<input type="password" id="password" name="password" required>
|
||||
</div>
|
||||
|
||||
<button type="submit">Anmelden</button>
|
||||
</form>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
98
app/Services/Ldap/LdapAuthService.php
Normal file
98
app/Services/Ldap/LdapAuthService.php
Normal file
@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
// Strenge Typprüfung für Parameter- und Rückgabetypen aktivieren.
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Services\Ldap;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* Service zur Authentifizierung von Benutzern gegen ein Active Directory per LDAP/LDAPS.
|
||||
* Bekommt Benutzername und Passwort und liefert:
|
||||
* - true -> Anmeldedaten sind gültig
|
||||
* - false -> Anmeldedaten sind fachlich ungültig (z. B. falsches Passwort)
|
||||
* Technische Fehler (z. B. falsche Konfiguration, keine Verbindung) werden als Exception geworfen.
|
||||
*/
|
||||
class LdapAuthService
|
||||
{
|
||||
/** @var array<string, mixed> LDAP-spezifische Konfiguration (Server, Port, Domain-Suffix, Timeout, etc.) */
|
||||
private array $config;
|
||||
|
||||
/**
|
||||
* Erwartet den Teilbereich "ldap" aus der allgemeinen Konfiguration (config.php).
|
||||
*
|
||||
* @param array<string, mixed> $ldapConfig Konfiguration für die LDAP-Verbindung
|
||||
*/
|
||||
public function __construct(array $ldapConfig)
|
||||
{
|
||||
// LDAP-Konfiguration in der Instanz speichern.
|
||||
$this->config = $ldapConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Führt die eigentliche LDAP/AD-Authentifizierung durch.
|
||||
*
|
||||
* @param string $username Benutzername (ohne Domain-Suffix, z. B. "administrator")
|
||||
* @param string $password Passwort im Klartext (wird direkt an ldap_bind übergeben)
|
||||
*
|
||||
* @return bool true bei erfolgreicher Anmeldung, false bei fachlich ungültigen Anmeldedaten
|
||||
*
|
||||
* @throws RuntimeException bei technischen Problemen (z. B. fehlende Konfiguration, Verbindungsfehler)
|
||||
*/
|
||||
public function authenticate(string $username, string $password): bool
|
||||
{
|
||||
// Wenn Benutzername oder Passwort leer sind, gar nicht erst versuchen zu binden.
|
||||
// Das ist ein fachlich ungültiger Login und wird mit false behandelt.
|
||||
if ($username === '' || $password === '') {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Benötigte Werte aus der LDAP-Konfiguration auslesen.
|
||||
// Falls einzelne Werte fehlen, werden sinnvolle Standardwerte gesetzt.
|
||||
$server = (string)($this->config['server'] ?? '');
|
||||
$port = (int)($this->config['port'] ?? 636);
|
||||
$domainSuffix = (string)($this->config['domain_suffix'] ?? '');
|
||||
$timeout = (int)($this->config['timeout'] ?? 5);
|
||||
|
||||
// Ohne Server-Adresse oder Domain-Suffix ist eine sinnvolle Anmeldung nicht möglich.
|
||||
// Das ist ein Konfigurationsfehler und wird als technischer Fehler behandelt.
|
||||
if ($server === '' || $domainSuffix === '') {
|
||||
throw new RuntimeException('LDAP-Konfiguration ist unvollständig.');
|
||||
}
|
||||
|
||||
// Verbindung zum LDAP/AD-Server herstellen.
|
||||
// Rückgabewert ist eine Ressource (Verbindungshandle) oder false bei Fehlern.
|
||||
$connection = ldap_connect($server, $port);
|
||||
|
||||
if ($connection === false) {
|
||||
throw new RuntimeException('LDAP-Verbindung konnte nicht aufgebaut werden.');
|
||||
}
|
||||
|
||||
// LDAP-Optionen setzen:
|
||||
// - Protokollversion 3 (Standard in aktuellen Umgebungen)
|
||||
// - Netzwerk-Timeout, damit die Anfrage nicht unendlich hängt
|
||||
ldap_set_option($connection, LDAP_OPT_PROTOCOL_VERSION, 3);
|
||||
ldap_set_option($connection, LDAP_OPT_NETWORK_TIMEOUT, $timeout);
|
||||
|
||||
// UPN (User Principal Name) aus Benutzername und Domain-Suffix bilden.
|
||||
// Beispiel: "administrator" + "@ITFA-PROJ-DOM.local" -> "administrator@ITFA-PROJ-DOM.local"
|
||||
$bindRdn = $username . $domainSuffix;
|
||||
|
||||
// Eigentliche Authentifizierung:
|
||||
// ldap_bind versucht, sich mit den angegebenen Anmeldedaten am AD/LDAP anzumelden.
|
||||
// Rückgabewerte:
|
||||
// - true -> Anmeldedaten sind gültig
|
||||
// - false -> Anmeldedaten sind ungültig (z. B. falsches Passwort)
|
||||
//
|
||||
// Das @-Zeichen unterdrückt PHP-Warnings, damit Fehlermeldungen nicht unformatiert im HTML landen.
|
||||
$bindResult = @ldap_bind($connection, $bindRdn, $password);
|
||||
|
||||
// Verbindung zum LDAP-Server wieder schließen.
|
||||
ldap_unbind($connection);
|
||||
|
||||
// Bei erfolgreichem Bind (true) -> Authentifizierung erfolgreich.
|
||||
// Bei false -> fachlich fehlgeschlagene Anmeldung (z. B. falsche Credentials).
|
||||
return $bindResult === true;
|
||||
}
|
||||
}
|
||||
27
config/config.php
Normal file
27
config/config.php
Normal file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
/** Typsicherheit aktivieren
|
||||
* var = "1" != var = 1
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
return [
|
||||
'ldap' => [
|
||||
// LDAP-URL des Domain Controllers
|
||||
'server' => 'ITFA-PROJ-SRV.ITFA-PROJ-DOM.local',
|
||||
'port' => 389,
|
||||
|
||||
// wird an den Benutzernamen angehängt (z.B. "admin" + "@ITFA-PROJ-DOM.local")
|
||||
'domain_suffix' => '@ITFA-PROJ-DOM.local',
|
||||
|
||||
// Base DN der Domäne
|
||||
'base_dn' => 'DC=ITFA-PROJ-DOM,DC=local',
|
||||
|
||||
// Optional: Timeout in Sekunden
|
||||
'timeout' => 5,
|
||||
],
|
||||
|
||||
'security' => [
|
||||
// Session-Key unter dem der eingeloggte Admin gespeichert wird
|
||||
'session_key_user' => 'admin_user',
|
||||
],
|
||||
];
|
||||
100
public/index.php
Normal file
100
public/index.php
Normal file
@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
// Strenge Typprüfung für Parameter- und Rückgabetypen aktivieren.
|
||||
declare(strict_types=1);
|
||||
|
||||
// Eine neue Session wird gestartet und die entsprechende Variable ($_SESSION) angelegt oder eine bestehende wird fortgesetzt.
|
||||
session_start();
|
||||
|
||||
/*
|
||||
* Registriert eine Autoload-Funktion für Klassen mit dem Namespace-Präfix "App\".
|
||||
* Statt jede Klasse manuell über "require pfad_zur_klasse.php" einzubinden,
|
||||
* versucht PHP nun automatisch, die passende Datei zu laden, sobald eine Klasse
|
||||
* im Namespace "App\..." verwendet wird.
|
||||
*/
|
||||
spl_autoload_register(
|
||||
// Anonyme Funktion, die den Klassennamen prüft und den Dateipfad zur Klasse ermittelt.
|
||||
static function (string $class): void {
|
||||
$prefix = 'App\\';
|
||||
$baseDir = __DIR__ . '/../app/';
|
||||
|
||||
$len = strlen($prefix);
|
||||
if (strncmp($prefix, $class, $len) !== 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$relativeClass = substr($class, $len);
|
||||
$file = $baseDir . str_replace('\\', DIRECTORY_SEPARATOR, $relativeClass) . '.php';
|
||||
|
||||
if (file_exists($file) === true) {
|
||||
require $file;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Pfad zur Konfigurationsdatei prüfen und Konfiguration laden
|
||||
$configPath = __DIR__ . '/../config/config.php';
|
||||
if (file_exists($configPath) === false) {
|
||||
// Fail fast: ohne Konfiguration macht die App keinen Sinn
|
||||
http_response_code(500);
|
||||
echo 'Konfigurationsdatei config/config.php wurde nicht gefunden. '
|
||||
. 'Bitte config.example.php kopieren und anpassen.';
|
||||
exit;
|
||||
}
|
||||
|
||||
/** @var array<string, mixed> $config */
|
||||
$config = require $configPath;
|
||||
|
||||
use App\Controllers\AuthController;
|
||||
|
||||
// Hilfsfunktion für geschützte Routen
|
||||
function requireLogin(array $config): void
|
||||
{
|
||||
// session_key_user aus dem Config-Array lesen. Wenn nicht gesetzt oder null, Standard "admin_user" verwenden.
|
||||
$sessionKey = $config['security']['session_key_user'] ?? 'admin_user';
|
||||
|
||||
// Prüfen, ob in $_SESSION unter diesem Key ein eingeloggter Benutzer hinterlegt ist.
|
||||
// Falls nicht, zurück zur Login-Seite umleiten.
|
||||
if (isset($_SESSION[$sessionKey]) === false) {
|
||||
header('Location: index.php?route=login');
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
// Route aus dem GET-Parameter lesen. Wenn nicht gesetzt, Standardroute "login" verwenden.
|
||||
$route = $_GET['route'] ?? 'login';
|
||||
|
||||
// Neue Instanz der Klasse AuthController erstellen (wird bei Bedarf über den Autoloader geladen).
|
||||
$authController = new AuthController($config);
|
||||
|
||||
// Anhand des Routing-Ziels (route) entscheiden, welcher Code ausgeführt wird.
|
||||
switch ($route) {
|
||||
case 'login':
|
||||
$authController->showLoginForm();
|
||||
break;
|
||||
|
||||
case 'login.submit':
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
header('Location: index.php?route=login');
|
||||
exit;
|
||||
}
|
||||
$authController->processLogin();
|
||||
break;
|
||||
|
||||
case 'logout':
|
||||
$authController->logout();
|
||||
break;
|
||||
|
||||
case 'dashboard':
|
||||
requireLogin($config);
|
||||
// Später: DashboardController aufrufen
|
||||
echo '<h1>Dashboard (Platzhalter)</h1>';
|
||||
echo '<p>Hier kommt später dein SNMP/Server-Status hin.</p>';
|
||||
echo '<p><a href="index.php?route=logout">Logout</a></p>';
|
||||
break;
|
||||
|
||||
default:
|
||||
http_response_code(404);
|
||||
echo 'Route nicht gefunden.';
|
||||
break;
|
||||
}
|
||||
@ -1,33 +1,9 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once __DIR__ . '/../config/ldap.php';
|
||||
declare(strict_types=1);
|
||||
|
||||
$error = "";
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
var_dump($_POST);
|
||||
$username = isset($_POST['username']) ? trim($_POST['username']) : "";
|
||||
$password = isset($_POST['password']) ? $_POST['password'] : "";
|
||||
|
||||
$ldapConn = ldap_authenticate($username, $password);
|
||||
|
||||
if ($ldapConn === false) {
|
||||
$error = "Anmeldung fehlgeschlagen. Benutzername oder Passwort falsch.";
|
||||
} else {
|
||||
// Optional: User-Infos aus AD lesen, z. B. displayName
|
||||
// $result = ldap_search($ldapConn, $LDAP_BASE_DN, "(sAMAccountName=$username)", ["displayName"]);
|
||||
// $entries = ldap_get_entries($ldapConn, $result);
|
||||
|
||||
$_SESSION['logged_in'] = true;
|
||||
$_SESSION['username'] = $username;
|
||||
// $_SESSION['displayName'] = $entries[0]['displayname'][0] ?? $username;
|
||||
|
||||
ldap_unbind($ldapConn);
|
||||
|
||||
header("Location: dashboard.php");
|
||||
exit();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @var string|null $error
|
||||
*/
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
@ -73,12 +49,12 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
<div class="text-center">
|
||||
<h1 class="h4 text-gray-900 mb-4">Welcome Back!</h1>
|
||||
</div>
|
||||
<?php if ($error !== ""): ?>
|
||||
<?php if ($error !== null): ?>
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<?php echo htmlspecialchars($error); ?>
|
||||
<?php echo htmlspecialchars($error, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<form class="user" method="post" action="<?php echo $_SERVER['PHP_SELF']; ?>">
|
||||
<form class="user" method="post" action="index.php?route=login.submit">
|
||||
<div class="form-group">
|
||||
<input type="text" name="username" class="form-control form-control-user"
|
||||
id="username" aria-describedby="usernameHelp"
|
||||
|
||||
109
public/views/login.php
Normal file
109
public/views/login.php
Normal file
@ -0,0 +1,109 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @var string|null $error
|
||||
*/
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="description" content="">
|
||||
<meta name="author" content="">
|
||||
|
||||
<title>SB Admin 2 - Login</title>
|
||||
|
||||
<!-- Custom fonts for this template-->
|
||||
<link href="vendor/fontawesome-free/css/all.min.css" rel="stylesheet" type="text/css">
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Nunito:200,200i,300,300i,400,400i,600,600i,700,700i,800,800i,900,900i"
|
||||
rel="stylesheet">
|
||||
|
||||
<!-- Custom styles for this template-->
|
||||
<link href="css/sb-admin-2.min.css" rel="stylesheet">
|
||||
|
||||
</head>
|
||||
|
||||
<body class="bg-gradient-primary">
|
||||
|
||||
<div class="container">
|
||||
|
||||
<!-- Outer Row -->
|
||||
<div class="row justify-content-center">
|
||||
|
||||
<div class="col-xl-10 col-lg-12 col-md-9">
|
||||
|
||||
<div class="card o-hidden border-0 shadow-lg my-5">
|
||||
<div class="card-body p-0">
|
||||
<!-- Nested Row within Card Body -->
|
||||
<div class="row">
|
||||
<div class="col-lg-6 d-none d-lg-block bg-login-image"></div>
|
||||
<div class="col-lg-6">
|
||||
<div class="p-5">
|
||||
<div class="text-center">
|
||||
<h1 class="h4 text-gray-900 mb-4">Welcome Back!</h1>
|
||||
</div>
|
||||
<?php if ($error !== null): ?>
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<?php echo htmlspecialchars($error, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<form class="user" method="post" action="index.php?route=login.submit">
|
||||
<div class="form-group">
|
||||
<input type="text" name="username" class="form-control form-control-user"
|
||||
id="username" aria-describedby="usernameHelp"
|
||||
placeholder="Enter Username...">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="password" name="password" class="form-control form-control-user"
|
||||
id="password" placeholder="Password">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="custom-control custom-checkbox small">
|
||||
<input type="checkbox" class="custom-control-input" id="customCheck">
|
||||
<label class="custom-control-label" for="customCheck">Remember
|
||||
Me</label>
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary btn-user btn-block">
|
||||
Anmelden
|
||||
</button>
|
||||
</form>
|
||||
<hr>
|
||||
<div class="text-center">
|
||||
<a class="small" href="forgot-password.php">Forgot Password?</a>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<a class="small" href="register.php">Create an Account!</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Bootstrap core JavaScript-->
|
||||
<script src="vendor/jquery/jquery.min.js"></script>
|
||||
<script src="vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
|
||||
|
||||
<!-- Core plugin JavaScript-->
|
||||
<script src="vendor/jquery-easing/jquery.easing.min.js"></script>
|
||||
|
||||
<!-- Custom scripts for all pages-->
|
||||
<script src="js/sb-admin-2.min.js"></script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Loading…
Reference in New Issue
Block a user