Laravel AT Protocol Client (alpha & unstable)
3
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add ScopeGate service for scope authorization

+176
+176
src/Auth/ScopeGate.php
··· 1 + <?php 2 + 3 + namespace SocialDept\AtpClient\Auth; 4 + 5 + use Illuminate\Contracts\Auth\Authenticatable; 6 + use SocialDept\AtpClient\Contracts\HasAtpSession; 7 + use SocialDept\AtpClient\Enums\Scope; 8 + use SocialDept\AtpClient\Enums\ScopeAuthorizationFailure; 9 + use SocialDept\AtpClient\Exceptions\ScopeAuthorizationException; 10 + use SocialDept\AtpClient\Session\Session; 11 + use SocialDept\AtpClient\Session\SessionManager; 12 + 13 + class ScopeGate 14 + { 15 + protected ?Session $session = null; 16 + 17 + public function __construct( 18 + protected SessionManager $sessions, 19 + protected ScopeChecker $checker, 20 + ) {} 21 + 22 + /** 23 + * Set the session context directly. 24 + */ 25 + public function forSession(Session $session): self 26 + { 27 + $instance = new self($this->sessions, $this->checker); 28 + $instance->session = $session; 29 + 30 + return $instance; 31 + } 32 + 33 + /** 34 + * Set the session context via handle or DID. 35 + */ 36 + public function forUser(string $handleOrDid): self 37 + { 38 + $instance = new self($this->sessions, $this->checker); 39 + $instance->session = $this->sessions->session($handleOrDid); 40 + 41 + return $instance; 42 + } 43 + 44 + /** 45 + * Check if the session has the given scope. 46 + */ 47 + public function can(string|Scope $scope): bool 48 + { 49 + $session = $this->resolveSession(); 50 + 51 + if (! $session) { 52 + return false; 53 + } 54 + 55 + return $this->checker->hasScope($session, $scope); 56 + } 57 + 58 + /** 59 + * Check if the session has any of the given scopes. 60 + * 61 + * @param array<string|Scope> $scopes 62 + */ 63 + public function canAny(array $scopes): bool 64 + { 65 + $session = $this->resolveSession(); 66 + 67 + if (! $session) { 68 + return false; 69 + } 70 + 71 + foreach ($scopes as $scope) { 72 + if ($this->checker->hasScope($session, $scope)) { 73 + return true; 74 + } 75 + } 76 + 77 + return false; 78 + } 79 + 80 + /** 81 + * Check if the session has all of the given scopes. 82 + * 83 + * @param array<string|Scope> $scopes 84 + */ 85 + public function canAll(array $scopes): bool 86 + { 87 + $session = $this->resolveSession(); 88 + 89 + if (! $session) { 90 + return false; 91 + } 92 + 93 + return $this->checker->check($session, $scopes); 94 + } 95 + 96 + /** 97 + * Check if the session does NOT have the given scope. 98 + */ 99 + public function cannot(string|Scope $scope): bool 100 + { 101 + return ! $this->can($scope); 102 + } 103 + 104 + /** 105 + * Authorize the session has all given scopes, or handle failure. 106 + * 107 + * @param string|Scope ...$scopes 108 + * 109 + * @throws ScopeAuthorizationException 110 + */ 111 + public function authorize(string|Scope ...$scopes): void 112 + { 113 + if ($this->canAll($scopes)) { 114 + return; 115 + } 116 + 117 + $session = $this->resolveSession(); 118 + $granted = $session ? $session->scopes() : []; 119 + $required = array_map( 120 + fn ($scope) => $scope instanceof Scope ? $scope->value : $scope, 121 + $scopes 122 + ); 123 + $missing = array_diff($required, $granted); 124 + 125 + $exception = new ScopeAuthorizationException($missing, $granted); 126 + 127 + $action = config('atp-client.scope_authorization.failure_action', ScopeAuthorizationFailure::Abort); 128 + 129 + if ($action === ScopeAuthorizationFailure::Exception) { 130 + throw $exception; 131 + } 132 + 133 + // For Abort and Redirect, let the exception render itself 134 + throw $exception; 135 + } 136 + 137 + /** 138 + * Get the granted scopes for the current session. 139 + */ 140 + public function granted(): array 141 + { 142 + $session = $this->resolveSession(); 143 + 144 + return $session ? $session->scopes() : []; 145 + } 146 + 147 + /** 148 + * Resolve the session from context. 149 + */ 150 + protected function resolveSession(): ?Session 151 + { 152 + // If session was explicitly set, use it 153 + if ($this->session) { 154 + return $this->session; 155 + } 156 + 157 + // Try to resolve from authenticated user 158 + $user = auth()->user(); 159 + 160 + if (! $user instanceof HasAtpSession) { 161 + return null; 162 + } 163 + 164 + $did = $user->getAtpDid(); 165 + 166 + if (! $did) { 167 + return null; 168 + } 169 + 170 + try { 171 + return $this->sessions->session($did); 172 + } catch (\Exception) { 173 + return null; 174 + } 175 + } 176 + }