Added recaptcha
This commit is contained in:
45
README.md
45
README.md
@@ -4,26 +4,47 @@
|
||||
|
||||
## Anpassung der Useranmeldung
|
||||
|
||||
#### Registrierung ohne Captcha und E-Mail-Verifikation
|
||||
#### Registrierung mit Google reCAPTCHA v3
|
||||
|
||||
**Beschreibung:**
|
||||
Die Registrierung wurde so angepasst, dass Benutzer ohne Captcha und E-Mail-Verifikation registriert werden können. Benutzer werden nach der Registrierung automatisch aktiviert.
|
||||
Die Registrierung wurde mit Google reCAPTCHA v3 abgesichert. reCAPTCHA v3 arbeitet unsichtbar im Hintergrund und analysiert das Benutzerverhalten, um Bots zu erkennen. E-Mail-Verifizierung ist deaktiviert - Benutzer werden nach der Registrierung automatisch aktiviert.
|
||||
|
||||
**Technische Umsetzung:**
|
||||
- Entfernung des Captcha-Features aus dem Registrierungsprozess
|
||||
- Deaktivierung der E-Mail-Verifizierung
|
||||
- Automatische Aktivierung neuer Benutzerkonten
|
||||
- Vereinfachung des Registrierungsformulars
|
||||
- Integration von Google reCAPTCHA v3 (unsichtbar, keine Checkbox)
|
||||
- Score-basierte Validierung (0.0 = Bot, 1.0 = Mensch)
|
||||
- Blockierung bei Score unter 0.5
|
||||
- Konfiguration über `RECAPTCHA_SITE_KEY` und `RECAPTCHA_SECRET_KEY`
|
||||
|
||||
**Admin-Funktion:**
|
||||
- Nur Administratoren können über das gleiche Formular neue Benutzer anlegen
|
||||
- Sicherstellung, dass nur autorisierte Personen Benutzerkonten erstellen können
|
||||
**Code-Beispiel (View):**
|
||||
```html
|
||||
<script src="https://www.google.com/recaptcha/api.js?render=SITE_KEY"></script>
|
||||
<script>
|
||||
grecaptcha.ready(function() {
|
||||
grecaptcha.execute('SITE_KEY', {action: 'register'}).then(function(token) {
|
||||
document.getElementById('recaptcha-response').value = token;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
**Code-Beispiel (Server-Validierung):**
|
||||
```php
|
||||
$response = file_get_contents('https://www.google.com/recaptcha/api/siteverify?secret=' . $secret_key . '&response=' . $recaptcha_response);
|
||||
$response_data = json_decode($response);
|
||||
if (!$response_data->success || $response_data->score < 0.5) {
|
||||
// Bot erkannt oder Validierung fehlgeschlagen
|
||||
}
|
||||
```
|
||||
|
||||
**Vorteile von v3:**
|
||||
- Keine Benutzerinteraktion erforderlich
|
||||
- Bessere User Experience
|
||||
- Intelligente Bot-Erkennung durch Verhaltensanalyse
|
||||
|
||||
```
|
||||
<!-- Screenshot Platzhalter -->
|
||||
[📸 Screenshot: Vereinfachtes Registrierungsformular]
|
||||
[📸 Screenshot: Admin-Benutzererstellung]
|
||||
[📸 Screenshot: Automatisch aktivierter Benutzer]
|
||||
[📸 Screenshot: Registrierungsformular]
|
||||
[📸 Screenshot: reCAPTCHA Badge]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -70,12 +70,10 @@ return array(
|
||||
'DB_PORT' => '3306',
|
||||
'DB_CHARSET' => 'utf8',
|
||||
/**
|
||||
* Configuration for: Captcha size
|
||||
* The currently used Captcha generator (https://github.com/Gregwar/Captcha) also runs without giving a size,
|
||||
* so feel free to use ->build(); inside CaptchaModel.
|
||||
* Configuration for: Google reCAPTCHA v2
|
||||
*/
|
||||
'CAPTCHA_WIDTH' => 359,
|
||||
'CAPTCHA_HEIGHT' => 100,
|
||||
'RECAPTCHA_SITE_KEY' => 'recaptcha-site-key',
|
||||
'RECAPTCHA_SECRET_KEY' => 'recaptcha-secret-key',
|
||||
/**
|
||||
* Configuration for: Cookies
|
||||
* 1209600 seconds = 2 weeks
|
||||
|
||||
@@ -22,23 +22,25 @@ class RegisterController extends Controller
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
// only admins can access registration; reuse existing admin auth check
|
||||
Auth::checkAdminAuthentication();
|
||||
if (Session::userIsLoggedIn()) {
|
||||
Redirect::to('index');
|
||||
return;
|
||||
}
|
||||
$this->View->render('register/index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Register page action
|
||||
* POST-request after form submit
|
||||
*/
|
||||
public function register_action()
|
||||
{
|
||||
// enforce admin-only for registration
|
||||
Auth::checkAdminAuthentication();
|
||||
if (Session::userIsLoggedIn()) {
|
||||
Redirect::to('index');
|
||||
return;
|
||||
}
|
||||
|
||||
RegistrationModel::registerNewUser();
|
||||
|
||||
Redirect::to('admin/index');
|
||||
if (RegistrationModel::registerNewUser()) {
|
||||
Redirect::to('login');
|
||||
} else {
|
||||
Redirect::to('register');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -15,15 +15,13 @@ class RegistrationModel
|
||||
*/
|
||||
public static function registerNewUser($isAdmin = false)
|
||||
{
|
||||
// clean the input
|
||||
$user_name = strip_tags(Request::post('user_name'));
|
||||
$user_email = strip_tags(Request::post('user_email'));
|
||||
// Use 'user_password' if provided (admin registration), otherwise 'user_password_new'
|
||||
$user_password_new = $isAdmin ? Request::post('user_password_new') : Request::post('user_password_new');
|
||||
$user_password_repeat = $user_password_new; // no repeat field
|
||||
$user_password_new = Request::post('user_password_new');
|
||||
$user_password_repeat = $user_password_new;
|
||||
|
||||
// validate using existing validators and messages
|
||||
$valid = true;
|
||||
if (!self::validateRecaptcha()) { $valid = false; }
|
||||
if (!self::validateUserName($user_name)) { $valid = false; }
|
||||
if (!self::validateUserEmail($user_email, $user_email)) { $valid = false; }
|
||||
if (!self::validateUserPassword($user_password_new, $user_password_repeat)) { $valid = false; }
|
||||
@@ -77,12 +75,35 @@ class RegistrationModel
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the username
|
||||
*
|
||||
* @param $user_name
|
||||
* @return bool
|
||||
*/
|
||||
public static function validateRecaptcha()
|
||||
{
|
||||
$recaptcha_response = Request::post('g-recaptcha-response');
|
||||
|
||||
if (empty($recaptcha_response)) {
|
||||
Session::add('feedback_negative', 'reCAPTCHA verification failed. Please try again.');
|
||||
return false;
|
||||
}
|
||||
|
||||
$secret_key = Config::get('RECAPTCHA_SECRET_KEY');
|
||||
$verify_url = 'https://www.google.com/recaptcha/api/siteverify';
|
||||
|
||||
$response = file_get_contents($verify_url . '?secret=' . $secret_key . '&response=' . $recaptcha_response);
|
||||
$response_data = json_decode($response);
|
||||
|
||||
if (!$response_data->success) {
|
||||
Session::add('feedback_negative', 'reCAPTCHA verification failed. Please try again.');
|
||||
return false;
|
||||
}
|
||||
|
||||
// v3 returns a score from 0.0 to 1.0 (1.0 = likely human, 0.0 = likely bot)
|
||||
if (isset($response_data->score) && $response_data->score < 0.5) {
|
||||
Session::add('feedback_negative', 'Registration blocked due to suspicious activity.');
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function validateUserName($user_name)
|
||||
{
|
||||
if (empty($user_name)) {
|
||||
@@ -90,7 +111,6 @@ class RegistrationModel
|
||||
return false;
|
||||
}
|
||||
|
||||
// if username is too short (2), too long (64) or does not fit the pattern (aZ09)
|
||||
if (!preg_match('/^[a-zA-Z0-9]{2,64}$/', $user_name)) {
|
||||
Session::add('feedback_negative', Text::get('FEEDBACK_USERNAME_DOES_NOT_FIT_PATTERN'));
|
||||
return false;
|
||||
|
||||
@@ -37,6 +37,9 @@
|
||||
<div class="link-forgot-my-password">
|
||||
<a href="<?php echo Config::get('URL'); ?>login/requestPasswordReset">I forgot my password</a>
|
||||
</div>
|
||||
<div class="link-register" style="margin-top: 15px;">
|
||||
<a href="<?php echo Config::get('URL'); ?>register" class="button">Register new account</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,18 +1,30 @@
|
||||
<div class="container">
|
||||
<script src="https://www.google.com/recaptcha/api.js?render=<?php echo Config::get('RECAPTCHA_SITE_KEY'); ?>"></script>
|
||||
|
||||
<!-- echo out the system feedback (error and success messages) -->
|
||||
<div class="container">
|
||||
<?php $this->renderFeedbackMessages(); ?>
|
||||
|
||||
<!-- login box on left side -->
|
||||
<div class="login-box" style="width: 50%; display: block;">
|
||||
<h2>Register a new account</h2>
|
||||
|
||||
<!-- register form -->
|
||||
<form method="post" action="<?php echo Config::get('URL'); ?>register/register_action">
|
||||
<form method="post" action="<?php echo Config::get('URL'); ?>register/register_action" id="register-form">
|
||||
<input type="text" pattern="[a-zA-Z0-9]{2,64}" name="user_name" placeholder="Username (letters/numbers, 2-64 chars)" required />
|
||||
<input type="text" name="user_email" placeholder="email address (a real address)" required />
|
||||
<input type="password" name="user_password_new" pattern=".{6,}" placeholder="Password (6+ characters)" required autocomplete="off" />
|
||||
<input type="hidden" name="g-recaptcha-response" id="recaptcha-response" />
|
||||
<input type="submit" value="Register" />
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.getElementById('register-form').addEventListener('submit', function(e) {
|
||||
e.preventDefault();
|
||||
var form = this;
|
||||
grecaptcha.ready(function() {
|
||||
grecaptcha.execute('<?php echo Config::get('RECAPTCHA_SITE_KEY'); ?>', {action: 'register'}).then(function(token) {
|
||||
document.getElementById('recaptcha-response').value = token;
|
||||
form.submit();
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user