Skip to content

Commit 94f5be7

Browse files
committed
first commit
0 parents  commit 94f5be7

18 files changed

+1080
-0
lines changed

.gitattributes

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/.gitattributes export-ignore
2+
/.gitignore export-ignore
3+
/phpunit.xml export-ignore
4+
/tests export-ignore
5+
/README.md export-ignore

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/vendor
2+
composer.phar
3+
composer.lock
4+
.DS_Store
5+
.idea
6+
.phpunit.cache
7+
.phpunit.result.cache

LICENSE

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2024 ukeloop
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.
22+

README.md

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
# Laravel Impersonate Guard
2+
3+
This is a guard implementation in Laravel for handling user impersonation. It extends Laravel's `SessionGuard` and provides additional methods for impersonation-related functionality.
4+
5+
User impersonation is a feature that enables an administrator or privileged user to temporarily assume the identity of another user within the application. This capability proves valuable for troubleshooting, testing user-specific features, or providing support.
6+
7+
Moreover, It supports multiple authentication guards. For example, admin guard users can also impersonate web guard users.
8+
9+
## Security Considerations
10+
11+
User impersonation should be used with caution, especially in production environments. It's important to properly authenticate and authorize users before allowing them to impersonate others. Additionally, sensitive actions or pages should be protected from access while in impersonation mode to prevent unauthorized use.
12+
13+
## Installation
14+
15+
You can install this package via Composer:
16+
17+
```bash
18+
composer require ukeloop/laravel-impersonatable-guard
19+
```
20+
21+
## Configuration
22+
23+
Update your authentication configuration to use the `ImpersonatableSessionGuard` instead of Laravel's default `SessionGuard`. You need to replace the driver from `session` to `impersonatable.session`:
24+
25+
```php
26+
// config/auth.php
27+
28+
'guards' => [
29+
'web' => [
30+
'driver' => 'impersonatable.session',
31+
'provider' => 'users',
32+
],
33+
],
34+
```
35+
36+
## Usage
37+
38+
### Impersonate Users
39+
40+
Start impersonating the specified user. This method takes an instance of `Illuminate\Contracts\Auth\Authenticatable` representing the user to impersonate.
41+
42+
```php
43+
Auth::guard('web')->impersonate($user);
44+
```
45+
46+
### Once Impersonate Users
47+
48+
Temporarily impersonate the specified user for a single request. This method is useful for actions that need to be performed as another user without permanently switching the user context.
49+
50+
```php
51+
Auth::guard('web')->onceImpersonate($user);
52+
```
53+
54+
### Exit Impersonation
55+
56+
Stop impersonating the current user and return to the original user context.
57+
58+
```php
59+
Auth::guard('web')->exitImpersonation();
60+
```
61+
62+
### Get Original User
63+
64+
Get the original user that was being impersonated.
65+
66+
```php
67+
$originalUser = Auth::guard('web')->originalUser();
68+
```
69+
70+
### Check Currently impersonated state
71+
72+
Check if the guard is currently in an impersonated state.
73+
74+
```php
75+
$isImpersonated = Auth::guard('web')->impersonated();
76+
```
77+
78+
## Protect Impersonation With Middleware
79+
80+
You can use the middleware `impersonation.protect` to protect your routes against user impersonation. This middleware ensures that users cannot access certain routes while impersonating another user.
81+
82+
```php
83+
Route::get('/protect-form-impersonation', 'ExampleController@handleImportantRequest')->middleware('impersonation.protect');
84+
```
85+
86+
Protect with specified guards:
87+
88+
```php
89+
Route::get('/protect-form-impersonation', 'ExampleController@handleImportantRequest')->middleware('impersonation.protect:specified-guard');
90+
```
91+
92+
## Example Impersonation Controller
93+
94+
Example controller for impersonating users:
95+
96+
```php
97+
use App\Models\User;
98+
use Illuminate\Http\RedirectResponse;
99+
use Illuminate\Support\Facades\Auth;
100+
use RuntimeException;
101+
use Ukeloop\ImpersonatableGuard\Contracts\ImpersonatableGuard;
102+
103+
class ImpersonationController extends Controller
104+
{
105+
/**
106+
* Start impersonating the specified user.
107+
*/
108+
public function impersonate(User $user): RedirectResponse
109+
{
110+
$guard = Auth::guard('web');
111+
112+
if (!$guard instanceof ImpersonatableGuard) {
113+
throw new RuntimeException('This guard is not allowed to impersonate.');
114+
}
115+
116+
$guard->impersonate($user);
117+
118+
return redirect('/');
119+
}
120+
121+
/**
122+
* Stop impersonating the current user and return to the original user context.
123+
*/
124+
public function exit(): RedirectResponse
125+
{
126+
$guard = Auth::guard('web');
127+
128+
if (!$guard instanceof ImpersonatableGuard) {
129+
throw new RuntimeException('This guard is not allowed to impersonate.');
130+
}
131+
132+
$guard->exitImpersonation();
133+
134+
return redirect('/');
135+
}
136+
}
137+
```
138+
139+
## Custom Impersonate Guard
140+
141+
You can create custom impersonate guards by implementing `Ukeloop\ImpersonatableGuard\Contracts\ImpersonatableGuard`.
142+
143+
```php
144+
use Ukeloop\ImpersonatableGuard\Contracts\ImpersonatableGuard;
145+
146+
class CustomImpersonateGuard implements ImpersonatableGuard
147+
{
148+
// Define your own logic
149+
}
150+
```

composer.json

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
{
2+
"name": "ukeloop/laravel-impersonatable-guard",
3+
"description": "Laravel Impersonate Guard enables seamless user impersonation with enhanced security features for Laravel applications.",
4+
"keywords": [
5+
"laravel"
6+
],
7+
"type": "library",
8+
"license": "MIT",
9+
"authors": [
10+
{
11+
"name": "ukeloop"
12+
}
13+
],
14+
"require": {
15+
"php": "^8.1",
16+
"illuminate/auth": "^10.0|^11.0",
17+
"illuminate/contracts": "^10.0|^11.0",
18+
"illuminate/http": "^10.0|^11.0",
19+
"illuminate/support": "^10.0|^11.0",
20+
"illuminate/queue": "^10.0|^11.0"
21+
},
22+
"require-dev": {
23+
"orchestra/testbench": "^8.8|^9.0",
24+
"larastan/larastan": "^2.0",
25+
"laravel/pint": "^1.13"
26+
},
27+
"autoload": {
28+
"psr-4": {
29+
"Ukeloop\\ImpersonatableGuard\\": "src/"
30+
}
31+
},
32+
"autoload-dev": {
33+
"psr-4": {
34+
"Ukeloop\\ImpersonatableGuard\\Tests\\": "tests/"
35+
}
36+
},
37+
"extra": {
38+
"laravel": {
39+
"providers": [
40+
"Ukeloop\\ImpersonatableGuard\\ImpersonatableGuardServiceProvider"
41+
]
42+
}
43+
},
44+
"minimum-stability": "dev",
45+
"prefer-stable": true,
46+
"scripts": {
47+
"pint": "./vendor/bin/pint -v",
48+
"phpstan": "phpstan analyse --memory-limit=1G",
49+
"test": "phpunit"
50+
}
51+
}

phpstan.neon

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
includes:
2+
- ./vendor/larastan/larastan/extension.neon
3+
4+
parameters:
5+
6+
paths:
7+
- src
8+
9+
level: 9
10+
11+
checkMissingIterableValueType: false

phpunit.xml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<phpunit
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
bootstrap="vendor/autoload.php"
5+
backupGlobals="false"
6+
colors="true"
7+
processIsolation="false"
8+
stopOnFailure="false"
9+
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.5/phpunit.xsd"
10+
backupStaticProperties="false"
11+
>
12+
<testsuites>
13+
<testsuite name="Package Test Suite">
14+
<directory>tests</directory>
15+
</testsuite>
16+
</testsuites>
17+
<source>
18+
<include>
19+
<directory suffix=".php">src/</directory>
20+
</include>
21+
</source>
22+
</phpunit>
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
namespace Ukeloop\ImpersonatableGuard\Contracts;
4+
5+
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
6+
use Illuminate\Contracts\Auth\StatefulGuard;
7+
8+
interface ImpersonatableGuard extends StatefulGuard
9+
{
10+
public function impersonate(AuthenticatableContract $user): void;
11+
12+
public function onceImpersonate(AuthenticatableContract $user): void;
13+
14+
public function exitImpersonation(): void;
15+
16+
public function originalUser(): ?AuthenticatableContract;
17+
18+
public function impersonated(): bool;
19+
}

src/Events/ExitImpersonation.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
namespace Ukeloop\ImpersonatableGuard\Events;
4+
5+
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
6+
use Illuminate\Queue\SerializesModels;
7+
8+
class ExitImpersonation
9+
{
10+
use SerializesModels;
11+
12+
public function __construct(
13+
public string $guard,
14+
public ?AuthenticatableContract $user,
15+
public ?AuthenticatableContract $originalUser,
16+
) {
17+
}
18+
}

src/Events/Impersonate.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
namespace Ukeloop\ImpersonatableGuard\Events;
4+
5+
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
6+
use Illuminate\Queue\SerializesModels;
7+
8+
class Impersonate
9+
{
10+
use SerializesModels;
11+
12+
public function __construct(
13+
public string $guard,
14+
public AuthenticatableContract $user,
15+
public ?AuthenticatableContract $originalUser,
16+
) {
17+
}
18+
}

0 commit comments

Comments
 (0)