ยท yebor974 ยท Getting Started, Tutorials, Plugins & Extensions
Enforcing password updates for admin-created user accounts
Learn how to set up mandatory password renewal for user accounts created by administrators, ensuring better security and user onboarding through Filament PHP.
Managing user accounts in web applications often involves administrators creating accounts for users. In such cases, ensuring account security is paramount. One effective measure is to force users to reset their password upon their first login. This practice not only reinforces security but also allows users to set a password they prefer.
This article uses the Filament Renew Password Plugin.
Step 1: Install and register the plugin on panel
composer require yebor974/filament-renew-password
Publish default plugin migration that will add two columns to users table : last_password_renew_at
and force_renew_password
php artisan vendor:publish --tag="filament-renew-password-migrations"
php artisan migrate
Register the plugin to panel and add force renewal process and timestamp management.
use Yebor974\Filament\RenewPassword\RenewPasswordPlugin;
public function panel(Panel $panel): Panel
{
return $panel
->plugin(
(new RenewPasswordPlugin())
->forceRenewPassword() // activate the force renewal process
->timestampColumn() // activate last_password_renew_at column, updating it with each password renewal.
)
);
}
Step 2: Setup User Model
Implement RenewPasswordContract
on User Model, add default RenewPassword
trait and declare fillable
attributes.
For example, we just declare a name and email attributes for user.
use Illuminate\Foundation\Auth\User as Authenticatable;
use Yebor974\Filament\RenewPassword\Contracts\RenewPasswordContract;
use Yebor974\Filament\RenewPassword\Traits\RenewPassword;
//...
class User extends Authenticatable implements RenewPasswordContract
{
use RenewPassword;
protected $fillable = [
'name',
'email',
'force_renew_password'
];
//...
}
If
force_renew_password
attribute is set to true, the user will be automatically redirect to the renewal password process.
Step 3: Create UserResource
php artisan make:filament-resource User
class UserResource extends Resource
{
protected static ?string $model = User::class;
protected static ?string $navigationIcon = 'heroicon-o-users';
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\Section::make()
->schema([
TextInput::make('name')
->required(),
TextInput::make('email')
->required()
->unique(ignoreRecord: true)
])->columns(2)
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('name')
->searchable(),
Tables\Columns\TextColumn::make('email')
->searchable(),
Tables\Columns\IconColumn::make('force_renew_password')
->boolean()
])
->filters([
//
])
->actions([
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
]),
]);
}
//...
}
Step 4: Generate a default password and send it with email notification
Now, need to generate default password and invite user to connect and renew password.
On CreateUser.php
page we have to override the mutateFormDataBeforeCreate
and handleRecordCreation
functions like that:
class CreateUser extends CreateRecord
{
protected static string $resource = UserResource::class;
protected string $password;
protected function mutateFormDataBeforeCreate(array $data): array
{
$this->password = Str::password(12); // generate a default password with length of 12 caracters
$data['password'] = bcrypt($this->password);
$data['force_renew_password'] = true; // to force user to renew password on next login
return $data;
}
protected function handleRecordCreation(array $data): Model
{
/** @var User $user */
$user = parent::handleRecordCreation($data); // handle the creation of the new user
$user->notify(new NewAccount($this->password)); // notify the new user with account details
return $user;
}
}
The NewAccount
notification class is:
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
use Illuminate\Support\HtmlString;
class NewAccount extends Notification
{
use Queueable;
/**
* Create a new notification instance.
*/
public function __construct(protected string $password, protected ?Model $tenant = null)
{
$this->afterCommit();
}
/**
* Get the notification's delivery channels.
*
* @return array<int, string>
*/
public function via(object $notifiable): array
{
return ['mail'];
}
/**
* Get the mail representation of the notification.
*/
public function toMail(object $notifiable): MailMessage
{
$appName = config('app.name');
return (new MailMessage)
->subject("Your account has been created on $appName")
->line("Here are your login details:")
->line(new HtmlString("<strong>Email</strong> : {$notifiable->email}"))
->line(new HtmlString("<strong>Temporary password</strong> : {$this->password}"))
->line("You will be prompted to change this temporary password at your next login.")
->action('Go to app', filament()->getUrl($this->tenant));
}
/**
* Get the array representation of the notification.
*
* @return array<string, mixed>
*/
public function toArray(object $notifiable): array
{
return [
//
];
}
}
That's all!
Screenshots
- Create user
- Receive notification (with smtp mailpit mailer)
- Login and renew password