'Remember me' on login. Issue #81.

This commit is contained in:
Dmitry Khomutov 2017-08-28 21:23:27 +07:00
parent 4ce3c94798
commit 07359d82f6
No known key found for this signature in database
GPG key ID: 7EB36C9576F9ECB9
8 changed files with 158 additions and 147 deletions

View file

@ -1,6 +1,5 @@
<?php
session_set_cookie_params(43200); // Set session cookie to last 12 hours.
session_start();
require_once(dirname(__DIR__) . '/bootstrap.php');

View file

@ -42,6 +42,18 @@ class SessionController extends Controller
*/
public function login()
{
if (!empty($_COOKIE['remember_key'])) {
$user = $this->userStore->getByRememberKey($_COOKIE['remember_key']);
if ($user) {
$_SESSION['php-censor-user-id'] = $user->getId();
$response = new b8\Http\Response\RedirectResponse();
$response->setHeader('Location', $this->getLoginRedirect());
return $response;
}
}
$isLoginFailure = false;
if ($this->request->getMethod() == 'POST') {
@ -53,10 +65,10 @@ class SessionController extends Controller
$email = $this->getParam('email');
$password = $this->getParam('password', '');
$rememberMe = (bool)$this->getParam('remember_me', 0);
$isLoginFailure = true;
$user = $this->userStore->getByEmailOrName($email);
$user = $this->userStore->getByEmailOrName($email);
$providers = $this->authentication->getLoginPasswordProviders();
if (null !== $user) {
@ -67,7 +79,7 @@ class SessionController extends Controller
// Ask each providers to provision the user
foreach ($providers as $provider) {
$user = $provider->provisionUser($email);
if ($user !== null && $provider->verifyPassword($user, $password)) {
if ($user && $provider->verifyPassword($user, $password)) {
$this->userStore->save($user);
$isLoginFailure = false;
break;
@ -77,8 +89,27 @@ class SessionController extends Controller
if (!$isLoginFailure) {
$_SESSION['php-censor-user-id'] = $user->getId();
if ($rememberMe) {
$rememberKey = md5(microtime(true));
$user->setRememberKey($rememberKey);
$this->userStore->save($user);
setcookie(
'remember_key',
$rememberKey,
(time() + 60 * 60 * 24 * 30),
null,
null,
null,
true
);
}
$response = new b8\Http\Response\RedirectResponse();
$response->setHeader('Location', $this->getLoginRedirect());
return $response;
}
}
@ -102,6 +133,12 @@ class SessionController extends Controller
$pwd->setClass('form-control');
$form->addField($pwd);
$remember = b8\Form\Element\Checkbox::create('remember_me', Lang::get('remember_me'), false);
$remember->setContainerClass('form-group');
$remember->setCheckedValue(1);
$remember->setValue(0);
$form->addField($remember);
$pwd = new b8\Form\Element\Submit();
$pwd->setValue(Lang::get('log_in'));
$pwd->setClass('btn-success');
@ -129,6 +166,16 @@ class SessionController extends Controller
session_destroy();
setcookie(
'remember_key',
null,
(time() - 1),
null,
null,
null,
true
);
$response = new b8\Http\Response\RedirectResponse();
$response->setHeader('Location', APP_URL);
return $response;

View file

@ -32,11 +32,12 @@ Thank you,
PHP Censor',
'reset_email_title' => 'PHP Censor Password Reset for %s',
'reset_invalid' => 'Invalid password reset request.',
'email_address' => 'Email Address',
'login' => 'Login / Email Address',
'password' => 'Password',
'log_in' => 'Log in',
'reset_invalid' => 'Invalid password reset request.',
'email_address' => 'Email Address',
'login' => 'Login / Email Address',
'password' => 'Password',
'remember_me' => 'Remember me',
'log_in' => 'Log in',
// Top Nav

View file

@ -31,11 +31,12 @@ return [
PHP Censor',
'reset_email_title' => 'Сброс пароля PHP Censor для %s',
'reset_invalid' => 'Некорректный запрос на сброс пароля.',
'email_address' => 'Email',
'login' => 'Логин / Email',
'password' => 'Пароль',
'log_in' => 'Войти',
'reset_invalid' => 'Некорректный запрос на сброс пароля.',
'email_address' => 'Email',
'login' => 'Логин / Email',
'password' => 'Пароль',
'remember_me' => 'Запомнить меня',
'log_in' => 'Войти',
// Top Nav
'toggle_navigation' => 'Скрыть/показать панель навигации',

View file

@ -0,0 +1,24 @@
<?php
use Phinx\Migration\AbstractMigration;
class AddedRememberMeLogin extends AbstractMigration
{
public function up()
{
$table = $this->table('user');
if (!$table->hasColumn('remember_key')) {
$table->addColumn('remember_key', 'string', ['limit' => 32, 'null' => true])->save();
}
}
public function down()
{
$table = $this->table('user');
if ($table->hasColumn('remember_key')) {
$table->removeColumn('remember_key')->save();
}
}
}

View file

@ -38,6 +38,7 @@ class User extends Model
'per_page' => null,
'provider_key' => null,
'provider_data' => null,
'remember_key' => null,
];
/**
@ -54,6 +55,7 @@ class User extends Model
'per_page' => 'getPerPage',
'provider_key' => 'getProviderKey',
'provider_data' => 'getProviderData',
'remember_key' => 'getRememberKey',
// Foreign key getters:
];
@ -71,6 +73,7 @@ class User extends Model
'per_page' => 'setPerPage',
'provider_key' => 'setProviderKey',
'provider_data' => 'setProviderData',
'remember_key' => 'setRememberKey',
// Foreign key setters:
];
@ -125,6 +128,12 @@ class User extends Model
'nullable' => true,
'default' => null,
],
'remember_key' => [
'type' => 'varchar',
'length' => 32,
'nullable' => true,
'default' => null,
],
];
/**
@ -226,6 +235,18 @@ class User extends Model
return $rtn;
}
/**
* Get the value of RememberKey / remember_key.
*
* @return string
*/
public function getRememberKey()
{
$rtn = $this->data['remember_key'];
return $rtn;
}
/**
* Get the value of Language / language.
*
@ -388,6 +409,24 @@ class User extends Model
$this->setModified('provider_data');
}
/**
* Set the value of RememberKey / remember_key.
*
* @param $value string
*/
public function setRememberKey($value)
{
$this->validateString('RememberKey', $value);
if ($this->data['remember_key'] === $value) {
return;
}
$this->data['remember_key'] = $value;
$this->setModified('remember_key');
}
/**
* Set the value of Language / language.
*

View file

@ -94,7 +94,36 @@ class UserStore extends Store
}
$query = 'SELECT * FROM {{user}} WHERE {{email}} = :value OR {{name}} = :value LIMIT 1';
$stmt = Database::getConnection()->prepareCommon($query);
$stmt = Database::getConnection()->prepareCommon($query);
$stmt->bindValue(':value', $value);
if ($stmt->execute()) {
if ($data = $stmt->fetch(\PDO::FETCH_ASSOC)) {
return new User($data);
}
}
return null;
}
/**
*
* Get a single User by RememberKey.
*
* @param string $value
*
* @throws HttpException
*
* @return User
*/
public function getByRememberKey($value)
{
if (is_null($value)) {
throw new HttpException('Value passed to ' . __FUNCTION__ . ' cannot be null.');
}
$query = 'SELECT * FROM {{user}} WHERE {{remember_key}} = :value LIMIT 1';
$stmt = Database::getConnection()->prepareCommon($query);
$stmt->bindValue(':value', $value);
if ($stmt->execute()) {
@ -108,6 +137,9 @@ class UserStore extends Store
/**
* Get multiple User by Name.
*
* @throws HttpException
*
* @return array
*/
public function getByName($value, $limit = 1000, $useConnection = 'read')

View file

@ -1,132 +0,0 @@
<?php use PHPCensor\Helper\Lang; ?>
<?php if (isset($_GET['saved']) && $_GET['saved'] == 1): ?>
<p class="alert alert-success" style="margin-bottom: 20px;">
<?php Lang::out('settings_saved'); ?>
</p>
<?php endif; ?>
<?php if (isset($_GET['saved']) && $_GET['saved'] == 2): ?>
<p class="alert alert-danger" style="margin-bottom: 20px;">
<?php Lang::out('settings_check_perms'); ?>
</p>
<?php endif; ?>
<?php if (!$isWriteable): ?>
<p class="alert alert-danger" style="margin-bottom: 20px;">
<?php Lang::out('settings_cannot_write'); ?>
</p>
<?php endif; ?>
<?php if (isset($_GET['linked']) && $_GET['linked'] == 1): ?>
<p class="alert alert-success" style="margin-bottom: 20px;">
<?php Lang::out('settings_github_linked'); ?>
</p>
<?php endif; ?>
<?php if (isset($_GET['linked']) && $_GET['linked'] == 2): ?>
<p class="alert alert-danger" style="margin-bottom: 20px;">
<?php Lang::out('settings_github_not_linked'); ?>
</p>
<?php endif; ?>
<div class="box">
<div class="box-body clearfix">
<?php print $basicSettings; ?>
</div>
</div>
<div class="box">
<div class="box-header"><h3 class="box-title"><?php Lang::out('build_settings'); ?></h3></div>
<div class="box-body clearfix">
<?php print $buildSettings; ?>
</div>
</div>
<div class="box">
<div class="box-header"><h3 class="box-title"><?php Lang::out('github_application'); ?></h3></div>
<div class="box-body clearfix">
<div class="row">
<div class="col-lg-12">
<?php
$id = null;
if (isset($settings['php-censor']['github']['id'])) {
$id = $settings['php-censor']['github']['id'];
}
$returnTo = APP_URL . 'settings/github-callback';
$githubUri = 'https://github.com/login/oauth/authorize?client_id='.$id.'&scope=repo&redirect_uri=' . $returnTo;
?>
<?php if (!empty($id)): ?>
<?php if (empty($githubUser['name']) || empty($settings['php-censor']['github']['token'])): ?>
<p class="alert alert-warning clearfix">
<?php Lang::out('github_sign_in', $githubUri); ?>
</p>
<?php else: ?>
<p class="alert alert-success">
<?php Lang::out('github_app_linked'); ?>
<strong>
<a href="<?php echo $githubUser['html_url']; ?>"><?php echo $githubUser['name']; ?></a>
</strong>
</p>
<?php endif; ?>
<?php endif; ?>
</div>
<div class="col-lg-8">
<?php print $github; ?>
</div>
<div class="col-lg-4">
<div class="box">
<div class="box-header">
<h3 class="box-title"><?php Lang::out('github_where_to_find'); ?></h3>
</div>
<div class="box-body">
<p>
<?php Lang::out('github_where_help'); ?>
</p>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="box">
<div class="box-header">
<h3 class="box-title"><?php Lang::out('email_settings'); ?></h3>
</div>
<div class="box-body clearfix">
<?php if (!isset($settings['php-censor']['email_settings'])): ?>
<p class="alert alert-warning clearfix">
<?php Lang::out('email_settings_help'); ?>
</p>
<?php endif; ?>
<?php print $emailSettings; ?>
</div>
</div>
<div class="box">
<div class="box-header">
<h3 class="box-title">Authentication Settings</h3>
</div>
<div class="box-body clearfix">
<p class="alert alert-warning clearfix">
Be careful: This setting disables authentication and uses your current admin account for all actions within PHP Censor with admin rights.
</p>
<?php print $securitySettings; ?>
</div>
</div>