Authorization
In the MV framework, authorization is implemented using the Auth class and can be added to an existing model by passing an array of parameters.
Authorization parameters
Let's create a model with a minimum number of fields and add email and password authorization functionality to it.
//File models/accounts.model.php
class Accounts extends Model
{
protected $name = 'User accounts';
protected $model_elements = [
['Name', 'char', 'name', ['required' => true]],
['Email', 'email', 'email', ['required' => true, 'unique' => true]],
['Password', 'password', 'password', ['required' => true]]
];
protected $auth_settings = [
'login_field' => 'email',
'password_field' => 'password'
];
}Below are additional parameters for configuring authorization with broader functionality:
- active_field - the field name for determining record activity, bool data type
- remember_me - 'Remember me' functionality for auto-login using cookies (lifetime in days)
- last_login_field - the name of the date_time type field for recording the user's last login date
- token_field - a field with an individual token for each account, char data type
- watch_ip - track the user's IP address (and log out if it changes)
- watch_browser - track the user's browser (and log out if it changes)
//File models/accounts.model.php
class Accounts extends Model
{
...
protected $auth_settings = [
'login_field' => 'email',
'password_field' => 'password',
'active_field' => 'active',
'remember_me' => true,
'remember_me_lifetime' => 30,
'last_login_field' => 'last_login_date',
'token_field' => 'extra_token',
'recover_password_lifetime' => 3600,
'watch_ip' => true,
'watch_browser' => true
];
}Registration and Authorization
//Create a user (after registration or via admin panel)
$account = $mv -> Accounts -> getEmptyRecord();
$account -> name = 'User';
$account -> email = 'user@example.com';
$account -> password = 'mypassword';
$account -> save();
//Authorize the user
Auth::useModel(Accounts::class);
$user = Auth::login('user@example.com', 'mypassword');
//You can also authorize a user using Record or Form objects
//$record - Record class object of the Accounts model
$user = Auth::login($record);
//$form - form object with 'email' and 'password' fields
$user = Auth::login($form);
//If the account is found, $user is a Record class object of the Accounts model
Debug::pre($user -> all());
//Check if there is an authorized user of the Accounts class
Auth::useModel(Accounts::class);
$user = Auth::check();
//Logout the user
Auth::useModel(Accounts::class);
Auth::logout();
//Check result - null
$user = Auth::check();Auto-login user by cookie
//'Remember me on this device' functionality
//$user - authorized user
//The 'remember_me' option is enabled in the authorization settings
Auth::useModel(Accounts::class);
Auth::remember($user);
//Attempt to authorize the user via cookie
Auth::useModel(Accounts::class);
$user = Auth::loginWithRememberMeCookie();
//Cancel auto-login and delete the cookie
Auth::useModel(Accounts::class);
Auth::forget();Authorization check
For development convenience, the authorization check can be moved to the before-view.php file, and then the user account will be available in all templates of the project.
//File views/before-view.php
Auth::useModel(Accounts::class);
if(null === $user = Auth::check())
$user = Auth::loginWithRememberMeCookie();
//If the account is authorized, we can, for example, set a flag in the Registry
if(is_object($user))
{
Registry::set('UserIsAuthorized', true);
...
}Logout
To implement user logout, in addition to calling the Auth::logout() method, it is recommended to send a form to the desired URL using the POST method with a token to confirm the user logout.
<?
//Creating a hash code for logout (the user must be authorized)
Auth::useModel(Accounts::class);
$token = Auth::generateLogoutToken();
?>
//A small form with a logout button
<form method="POST" action="/account/logout">
<input type="hidden" name="logout_token" value="<? echo $token; ?>">
<button>Logout</button>
</form>
<?
//Token verification in the template file for the /account/logout URL
Auth::useModel(Accounts::class);
if('' !== $token = Http::fromPost('logout_token', ''))
if(Auth::hasAuthorizedUser() && $token === Auth::generateLogoutToken())
{
Auth::logout();
Http::redirect('/login');
}
?>Password recovery
To implement user password recovery, email sending with a special link is typically used. When the user follows this link, they are prompted to create a new password. The link's lifetime is also taken into account to prevent repeated use of the password reset link.
The main element of the link is a generated hash code, which can be used to find the user's record in the database.
To add password recovery functionality in MV, no changes to the database structure are required. All necessary parameters are passed encrypted within the link code.
//Creating a hash code for the link
//$user - Record class object of the Accounts model
//The link lifetime is specified in the 'recover_password_lifetime' parameter (default 1 hour)
Auth::useModel(Accounts::class);
$token = Auth::generatePasswordRecoveryToken($user);
//Creating a link to send via email
$link = Service::getAbsoluteHttpPath('/recover/'.$token);
$message = 'Your password recovery link: '.$link;
Email::send($user -> email, 'Password recovery', $message);
//When following the link, extract the code from the second part of the URL
//and search for the user record using it
$token = $mv -> router -> getUrlPart(1);
Auth::useModel(Accounts::class);
if(null !== $user = Auth::checkPasswordRecoveryToken($token))
{
//If the account is found, then show the form for a new password
$form = new Form([
['New password', 'password', 'password' ['required' => true]],
['Repeat password', 'password', 'password_repeat', [
'required' => true,
'must_match' => 'password'
]
]);
//If the form is filled out correctly, save the user's new password
if($form -> isSubmitted() && $form -> isValid())
{
Auth::recoverPassword($user, $form -> password);
Http::redirect('/login');
}
}Email address confirmation
By analogy with password recovery, the user's email address is confirmed. However, in this case, it is necessary to add a field to the model that will be responsible for confirming the user's address. You can use a field of type bool or date_time and set the address confirmation time there.
For the confirmation itself, you need to send a link with a special code to the user's email and handle the transition via this link similarly to password recovery.
//Adding a field to the model models/accounts.model.php
class Accounts extends Model
{
protected $model_elements = [
...
['Email confirmed', 'bool', 'email_confirmed'],
];
}
//Generating and sending an email address confirmation link
//$user - object of the Record class of the Accounts model
Auth::useModel(Accounts::class);
$token = Auth::generateEmailConfirmationToken($user);
$link = Service::getAbsoluteHttpPath('/confirm/email/'.$token);
$message = 'Your email confirmation link: '.$link;
Email::send($user -> email, 'Email confirmation', $message);
//When following the link, we search for the account
//and save the fact of address confirmation
$token = $mv -> router -> getUrlPart(2);
if(null !== $user = Auth::checkEmailConfirmationToken($token))
{
$user -> setValue('email_confirmed', true) -> save();
}
Previous section
AJAX