1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace App\Middleware; |
4
|
|
|
|
5
|
|
|
use App\Common\Acl; |
6
|
|
|
use App\Common\Auth; |
7
|
|
|
use App\Common\JsonException; |
8
|
|
|
use App\Model\AccessToken; |
9
|
|
|
|
10
|
|
|
use Psr\Http\Message\ServerRequestInterface; |
11
|
|
|
use Psr\Http\Message\ResponseInterface; |
12
|
|
|
|
13
|
|
|
class Authentication |
14
|
|
|
{ |
15
|
|
|
/** |
16
|
|
|
* @var Acl |
17
|
|
|
*/ |
18
|
|
|
private $acl; |
19
|
|
|
|
20
|
|
|
/** |
21
|
|
|
* @var |
22
|
|
|
*/ |
23
|
|
|
private $settings; |
24
|
|
|
|
25
|
|
|
/** |
26
|
|
|
* Authentication constructor. |
27
|
|
|
* |
28
|
|
|
* @param Acl $acl |
29
|
|
|
* @param $settings |
30
|
|
|
*/ |
31
|
|
|
public function __construct(Acl $acl, $settings) |
32
|
|
|
{ |
33
|
|
|
$this->acl = $acl; |
34
|
|
|
$this->settings = $settings; |
35
|
|
|
} |
36
|
|
|
|
37
|
|
|
/** |
38
|
|
|
* Execute the middleware. |
39
|
|
|
* |
40
|
|
|
* @param ServerRequestInterface $request |
41
|
|
|
* @param ResponseInterface $response |
42
|
|
|
* @param callable $next |
43
|
|
|
* |
44
|
|
|
* @return ResponseInterface |
45
|
|
|
* @throws JsonException |
46
|
|
|
* @throws \Exception |
47
|
|
|
*/ |
48
|
|
|
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next) |
49
|
|
|
{ |
50
|
|
|
// Request has to have Authorization header |
51
|
|
|
if (!$request->getHeader('Authorization')) { |
52
|
|
|
throw new JsonException(null, 401, 'Not authorized', 'The user must be authorized'); |
53
|
|
|
} |
54
|
|
|
|
55
|
|
|
// HTTP Authorization header available |
56
|
|
|
// Authorization: Bearer XXXXXXXXXXXXXXXXXXX |
57
|
|
|
// fetch XXXXXXXXXXXXX part |
58
|
|
|
$token = @explode(' ', @$request->getHeader('Authorization')[0]); |
59
|
|
|
$token = is_array($token) && (count($token) == 2) ? $token[1] : null; |
60
|
|
|
if (empty($token)) { |
61
|
|
|
throw new JsonException(null, 401, 'Not authorized', 'The user must be authorized'); |
62
|
|
|
} |
63
|
|
|
|
64
|
|
|
// provided token must be valid |
65
|
|
|
if (!AccessToken::validateToken($token, $this->settings['accessToken'])) { |
66
|
|
|
throw new JsonException(null, 401, 'Not authorized', 'The user must be authorized'); |
67
|
|
|
} |
68
|
|
|
|
69
|
|
|
// find user by token |
70
|
|
|
$user = AccessToken::getUserByToken($token); |
71
|
|
|
if (empty($user)) { |
72
|
|
|
throw new JsonException(null, 401, 'Not authorized', 'The user must be authorized'); |
73
|
|
|
} |
74
|
|
|
|
75
|
|
|
Auth::setUser($user); |
76
|
|
|
|
77
|
|
|
$isAllowed = false; |
78
|
|
|
$route = $request->getAttribute('route'); |
79
|
|
|
|
80
|
|
|
if ($route) { |
81
|
|
|
// check access for the route |
82
|
|
|
$resource = Acl::buildResourceName(Acl::GUARD_TYPE_ROUTE, $route->getPattern()); |
83
|
|
|
$privilege = Acl::getPrivilegeByHTTPMethod($request->getMethod()); |
84
|
|
View Code Duplication |
if ($this->acl->hasResource($resource)) { |
|
|
|
|
85
|
|
|
$isAllowed = $isAllowed || $this->acl->isAllowed($user->role->name, $resource, $privilege); |
86
|
|
|
} |
87
|
|
|
|
88
|
|
|
// check access for the callable |
89
|
|
|
$resource = Acl::buildResourceName(Acl::GUARD_TYPE_CALLABLE, $route->getCallable()); |
90
|
|
|
$privilege = null; |
91
|
|
View Code Duplication |
if ($this->acl->hasResource($resource)) { |
|
|
|
|
92
|
|
|
$isAllowed = $isAllowed || $this->acl->isAllowed($user->role->name, $resource, $privilege); |
93
|
|
|
} |
94
|
|
|
|
95
|
|
|
if (!$isAllowed) { |
96
|
|
|
throw new JsonException(null, 403, 'Not allowed', 'Access to this location is not allowed'); |
97
|
|
|
} |
98
|
|
|
} |
99
|
|
|
|
100
|
|
|
// access allowed, move to next middleware |
101
|
|
|
return $next($request, $response); |
102
|
|
|
} |
103
|
|
|
} |
104
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.