Laravel AT Protocol Client (alpha & unstable)
at dev 2.7 kB view raw
1<?php 2 3namespace SocialDept\AtpClient\Http\Middleware; 4 5use Closure; 6use Illuminate\Http\Request; 7use SocialDept\AtpClient\Auth\ScopeChecker; 8use SocialDept\AtpClient\Contracts\HasAtpSession; 9use SocialDept\AtpClient\Enums\ScopeAuthorizationFailure; 10use SocialDept\AtpClient\Exceptions\ScopeAuthorizationException; 11use SocialDept\AtpClient\Session\SessionManager; 12use Symfony\Component\HttpFoundation\Response; 13 14class RequiresScopeMiddleware 15{ 16 public function __construct( 17 protected SessionManager $sessions, 18 protected ScopeChecker $checker, 19 ) {} 20 21 /** 22 * Handle an incoming request. 23 * 24 * @param string ...$scopes 25 */ 26 public function handle(Request $request, Closure $next, string ...$scopes): Response 27 { 28 $user = $request->user(); 29 30 // Ensure user is authenticated 31 if (! $user) { 32 return $this->handleFailure( 33 new ScopeAuthorizationException($scopes, [], 'User not authenticated.') 34 ); 35 } 36 37 // Ensure user implements HasAtpSession 38 if (! $user instanceof HasAtpSession) { 39 return $this->handleFailure( 40 new ScopeAuthorizationException($scopes, [], 'User model must implement HasAtpSession interface.') 41 ); 42 } 43 44 $did = $user->getAtpDid(); 45 46 if (! $did) { 47 return $this->handleFailure( 48 new ScopeAuthorizationException($scopes, [], 'User has no ATP session.') 49 ); 50 } 51 52 try { 53 $session = $this->sessions->session($did); 54 } catch (\Exception $e) { 55 return $this->handleFailure( 56 new ScopeAuthorizationException($scopes, [], 'Could not retrieve ATP session: '.$e->getMessage()) 57 ); 58 } 59 60 // Check ALL scopes (AND logic) 61 if (! $this->checker->check($session, $scopes)) { 62 $granted = $session->scopes(); 63 $missing = array_diff($scopes, $granted); 64 65 return $this->handleFailure( 66 new ScopeAuthorizationException($missing, $granted) 67 ); 68 } 69 70 return $next($request); 71 } 72 73 protected function handleFailure(ScopeAuthorizationException $exception): Response 74 { 75 $action = config('atp-client.scope_authorization.failure_action', ScopeAuthorizationFailure::Abort); 76 77 return match ($action) { 78 ScopeAuthorizationFailure::Redirect => redirect( 79 config('atp-client.scope_authorization.redirect_to', '/login') 80 ), 81 ScopeAuthorizationFailure::Exception => throw $exception, 82 default => abort(403, $exception->getMessage()), 83 }; 84 } 85}