abc-da-construcao / autenticacao-package
Requires
- php: ^7.4|^8.0|^8.1
- guzzlehttp/guzzle: ^7.0.1
- illuminate/auth: ^5.6|^6|^7|^8|^9
- illuminate/contracts: ^5.6|^6|^7|^8|^9
- illuminate/http: ^5.6|^6|^7|^8|^9
- illuminate/routing: ^5.6|^6|^7|^8|^9
- illuminate/support: ^5.6|^6|^7|^8|^9
README
Laravel 和 Lumen 资源包,用于辅助实现全局认证系统 (SAG)。
此 Lumen 和 Laravel 包提供定制的认证/授权驱动程序、中间件、Facade 和命令,以便在 ABC 标准中使用全局认证系统。
安装
使用以下命令。
composer require abc-da-construcao/autenticacao-package
配置
通用
根据 SAG 注册信息,填写项目 .env
文件中的 APP_NAME
和 APP_KEY
密钥。
APP_NAME="api_pedidos-production"
APP_KEY=Gb4E7xqR74Pat9gefb7nidcWFZNW8S66
Laravel
打开 config/auth.php
文件,将认证驱动程序更改为 jwt
并注释掉相应的 provider
行。
//... 'guards' => [ // ... 'sag' => [ 'driver' => 'sag-jwt' ], ] //...
Lumen
将以下文件复制到项目的 config
目录。如果不存在,请创建该目录。
vendor/laravel/lumen-framework/config/auth.php
打开 config/auth.php
文件,将认证驱动程序更改为 jwt
。
'guards' => [ // ... 'sag' => ['driver' => 'sag-jwt'], ]
确保在 bootstrap/app.php
文件中存在以下配置。
/* |-------------------------------------------------------------------------- | Create The Application |-------------------------------------------------------------------------- | | Here we will load the environment and create the application instance | that serves as the central piece of this framework. We'll use this | application as an "IoC" container and router for this framework. | */ // ... $app->withFacades(); // ... /* |-------------------------------------------------------------------------- | Register Config Files |-------------------------------------------------------------------------- | | Now we will register the "app" configuration file. If the file exists in | your configuration directory it will be loaded; otherwise, we'll load | the default version. You may register other files below as needed. | */ // ... $app->configure('auth'); // ... /* |-------------------------------------------------------------------------- | Register Middleware |-------------------------------------------------------------------------- | | Next, we will register the middleware with the application. These can | be global middleware that run before and after each request into a | route or middleware that'll be assigned to some specific routes. | */ // ... $app->routeMiddleware([ 'auth' => App\Http\Middleware\Authenticate::class, ]); // ... /* |-------------------------------------------------------------------------- | Register Service Providers |-------------------------------------------------------------------------- | | Here we will register all of the application's service providers which | are used to bind services into the container. Service providers are | totally optional, so you are not required to uncomment this line. | */ // ... // $app->register(App\Providers\AuthServiceProvider::class); $app->register(AbcDaConstrucao\AutenticacaoPackage\Providers\AuthServiceProvider::class); // ...
保护路由
尽管具有与标准路由保护相同的特性,但该包不仅验证 JWT 令牌是否有效,还验证用户在应用中的权限,同时执行 ACL 功能。
认证保护的路由组示例。
// Lumen $router->group(['middleware' => ['auth:sag', 'sag-acl']], function () use ($router) { // Routes }); // Laravel API Route::middleware(['auth:sag', 'sag-acl'])->group(function () { // Routes });
认证
认证辅助方法。
Http::loginRequest($username, $base64_password)
.
Lumen API 示例
<?php use AbcDaConstrucao\AutenticacaoPackage\Facades\Http; use Illuminate\Http\Request; $router->post('/login', function (Request $request) { // A senha deve ser enviada com base64 encode para API de Autenticação. $response = Http::loginRequest($request->username, base64_encode($request->password)); // Devolve o token caso status 200 ou o erro específico // Ver abaixo resultado esperado do $response. return response()->json($response['data'], $response['status']); });
Laravel/Lumen 前端示例
如果存在 Illuminate\Session\SessionManager
类,则 Http::loginRequest()
方法还会在会话中保存令牌,简化令牌处理并保持用户在令牌有效期间登录。
<?php use AbcDaConstrucao\AutenticacaoPackage\Facades\Http; use Illuminate\Http\Request; Route::post('/login', function (Request $request) { // A senha deve ser enviada com base64 encode para API de Autenticação. $response = Http::loginRequest($request->username, base64_encode($request->password)); // token obtido e salvo em sessão. // Redireciona o usuário a página desejada. if ($response['status'] == 200) { return redirect()->route('home'); } // Se o token não for emitido retorna o usuário a página de login com os erros. return back()->with('errors', $response['data']['message']); });
之后,可以通过以下方式访问令牌并在后续请求中将其传递给后端。
use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\Session; $token = Session::get(Config::get('sag.session.token')); $tokenType = Session::get(Config::get('sag.session.token_type')); $tokenValidate = Session::get(Config::get('sag.session.token_validate'));
$response
中的预期结果。
// statuscode 200 [ "status" => 200, "data" => [ "token_tipo" => "Bearer", "token_validade" => "2022-04-28T17:49:21-03:00", "token" => "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwOlwvXC9zYWctc2VydmVyLmxvY2FsXC9hdXRoXC9sb2dpbiIsImlhdCI6MTY1MTE3NTIzOCwiZXhwIjoxNjUxMTc4ODM4LCJqaXQiOiJqd3RfNSIsInN1YiI6NX0.aSYc0iMkPzVb2EluK7rtXwnkjfv0TdjFFFHuSvd7VMQ", "payload" => "eyJpZCI6NSwibmFtZSI6IlRhbGxlcyBHYXplbCIsInVzZXJuYW1lIjoidGFsbGVzIiwiZW1haWwiOiJ0YWxsZXMuZ2F6ZWxAYWJjZGFjb25zdHJ1Y2FvLmNvbS5iciIsImVtYWlsX3ZlcmlmaWVkX2F0IjpudWxsLCJwYXNzd29yZCI6IiQyeSQxMCRnTGF0dk9zcmYwb25PUElodzV1N2hlRTFlTXNZb1Bta3M1cU5EMVdpc0x6bmZnSkdYNHUuZSIsImFjdGl2ZSI6MSwicm9vdCI6MCwiZXhwaXJlIjoxLCJjcmVhdGVkX2J5IjoxLCJ1cGRhdGVkX2J5IjoxLCJyZW1lbWJlcl90b2tlbiI6bnVsbCwiY3JlYXRlZF9hdCI6IjIwMjItMDQtMjggMTU6MDI6NDQiLCJ1cGRhdGVkX2F0IjoiMjAyMi0wNC0yOCAxNTowMzowMyIsImFwcHMiOlt7ImlkIjoxLCJuYW1lIjoiYXBpX3BlZGlkb3Nfc2VydmVyLXByb2R1Y3Rpb24iLCJ1cmwiOiJodHRwOlwvXC9sb2NhbGhvc3Q6ODAwMSIsImFjdGl2ZSI6MSwic3VwZXJfYWRtaW4iOjAsImNyZWF0ZWRfYnkiOjEsInVwZGF0ZWRfYnkiOjEsImNyZWF0ZWRfYXQiOiIyMDIyLTA0LTI4IDEwOjM4OjU2IiwidXBkYXRlZF9hdCI6IjIwMjItMDQtMjggMTA6Mzg6NTYiLCJncm91cHMiOlt7ImlkIjoyLCJhcHBfaWQiOjEsIm5hbWUiOiJGQVJNIiwiZGVzY3JpcHRpb24iOiJHcnVwbyBkbyBSYW1vbiIsImFjdGl2ZSI6MSwiY3JlYXRlZF9ieSI6MSwidXBkYXRlZF9ieSI6MSwiY3JlYXRlZF9hdCI6IjIwMjItMDQtMjggMTU6MDI6MDciLCJ1cGRhdGVkX2F0IjoiMjAyMi0wNC0yOCAxNTowMjowNyIsInBlcm1pc3Npb25zIjpbeyJhcHBfaWQiOjEsImdyb3VwX2lkIjoyLCJpZCI6NCwibWV0aG9kIjoiUE9TVCIsInVyaSI6IlwvbG9nb3V0IiwibmFtZSI6ImxvZ291dCIsInB1YmxpYyI6MH0seyJhcHBfaWQiOjEsImdyb3VwX2lkIjoyLCJpZCI6MywibWV0aG9kIjoiR0VUIiwidXJpIjoiXC9wcm9maWxlIiwibmFtZSI6InByb2ZpbGUiLCJwdWJsaWMiOjB9XX1dLCJyb3V0ZXMiOlt7ImlkIjoxLCJhcHBfaWQiOjEsIm1ldGhvZCI6IlBPU1QiLCJ1cmkiOiJcL2xvZ2luIiwibmFtZSI6ImxvZ2luIiwicHVibGljIjoxfSx7ImlkIjoyLCJhcHBfaWQiOjEsIm1ldGhvZCI6IkdFVCIsInVyaSI6Ilwvcm90YS1wdWJsaWNhIiwibmFtZSI6InJvdGEtcHVibGljYSIsInB1YmxpYyI6MX0seyJpZCI6MywiYXBwX2lkIjoxLCJtZXRob2QiOiJHRVQiLCJ1cmkiOiJcL3Byb2ZpbGUiLCJuYW1lIjoicHJvZmlsZSIsInB1YmxpYyI6MH0seyJpZCI6NCwiYXBwX2lkIjoxLCJtZXRob2QiOiJQT1NUIiwidXJpIjoiXC9sb2dvdXQiLCJuYW1lIjoibG9nb3V0IiwicHVibGljIjowfSx7ImlkIjo1LCJhcHBfaWQiOjEsIm1ldGhvZCI6IkdFVCIsInVyaSI6IlwvIiwibmFtZSI6ImhvbWUiLCJwdWJsaWMiOjB9XX0seyJpZCI6MywibmFtZSI6ImFwaV9wZWRpZG9zX2Zyb250LXByb2R1Y3Rpb24iLCJ1cmwiOiJodHRwOlwvXC9sb2NhbGhvc3Q6ODAwMiIsImFjdGl2ZSI6MSwic3VwZXJfYWRtaW4iOjAsImNyZWF0ZWRfYnkiOjEsInVwZGF0ZWRfYnkiOjEsImNyZWF0ZWRfYXQiOiIyMDIyLTA0LTI4IDE1OjMyOjI5IiwidXBkYXRlZF9hdCI6IjIwMjItMDQtMjggMTU6MzI6MjkiLCJncm91cHMiOlt7ImlkIjozLCJhcHBfaWQiOjMsIm5hbWUiOiJGQVJNIiwiZGVzY3JpcHRpb24iOm51bGwsImFjdGl2ZSI6MSwiY3JlYXRlZF9ieSI6MSwidXBkYXRlZF9ieSI6MSwiY3JlYXRlZF9hdCI6IjIwMjItMDQtMjggMTU6MzM6NDMiLCJ1cGRhdGVkX2F0IjoiMjAyMi0wNC0yOCAxNTozMzo0MyIsInBlcm1pc3Npb25zIjpbeyJhcHBfaWQiOjMsImdyb3VwX2lkIjozLCJpZCI6MTEsIm1ldGhvZCI6IkdFVHxIRUFEIiwidXJpIjoiXC9hcGlcL2hvbWUiLCJuYW1lIjoiYXBpLmhvbWUiLCJwdWJsaWMiOjB9LHsiYXBwX2lkIjozLCJncm91cF9pZCI6MywiaWQiOjksIm1ldGhvZCI6IlBPU1QiLCJ1cmkiOiJcL2FwaVwvbG9nb3V0IiwibmFtZSI6ImFwaS5sb2dvdXQiLCJwdWJsaWMiOjB9LHsiYXBwX2lkIjozLCJncm91cF9pZCI6MywiaWQiOjEwLCJtZXRob2QiOiJHRVR8SEVBRCIsInVyaSI6IlwvYXBpXC9wcm9maWxlIiwibmFtZSI6ImFwaS5wcm9maWxlIiwicHVibGljIjowfSx7ImFwcF9pZCI6MywiZ3JvdXBfaWQiOjMsImlkIjoxNSwibWV0aG9kIjoiR0VUfEhFQUQiLCJ1cmkiOiJcL2hvbWUiLCJuYW1lIjoiaG9tZSIsInB1YmxpYyI6MH0seyJhcHBfaWQiOjMsImdyb3VwX2lkIjozLCJpZCI6MTYsIm1ldGhvZCI6IkdFVHxIRUFEIiwidXJpIjoiXC9sb2dvdXQiLCJuYW1lIjoibG9nb3V0IiwicHVibGljIjowfV19XSwicm91dGVzIjpbeyJpZCI6NiwiYXBwX2lkIjozLCJtZXRob2QiOiJHRVR8SEVBRCIsInVyaSI6Ilwvc2FuY3R1bVwvY3NyZi1jb29raWUiLCJuYW1lIjpudWxsLCJwdWJsaWMiOjF9LHsiaWQiOjcsImFwcF9pZCI6MywibWV0aG9kIjoiR0VUfEhFQUQiLCJ1cmkiOiJcL2FwaVwvcHVibGljYSIsIm5hbWUiOiJhcGkucHVibGljYSIsInB1YmxpYyI6MX0seyJpZCI6OCwiYXBwX2lkIjozLCJtZXRob2QiOiJQT1NUIiwidXJpIjoiXC9hcGlcL2xvZ2luIiwibmFtZSI6ImFwaS5sb2dpbiIsInB1YmxpYyI6MX0seyJpZCI6OSwiYXBwX2lkIjozLCJtZXRob2QiOiJQT1NUIiwidXJpIjoiXC9hcGlcL2xvZ291dCIsIm5hbWUiOiJhcGkubG9nb3V0IiwicHVibGljIjowfSx7ImlkIjoxMCwiYXBwX2lkIjozLCJtZXRob2QiOiJHRVR8SEVBRCIsInVyaSI6IlwvYXBpXC9wcm9maWxlIiwibmFtZSI6ImFwaS5wcm9maWxlIiwicHVibGljIjowfSx7ImlkIjoxMSwiYXBwX2lkIjozLCJtZXRob2QiOiJHRVR8SEVBRCIsInVyaSI6IlwvYXBpXC9ob21lIiwibmFtZSI6ImFwaS5ob21lIiwicHVibGljIjowfSx7ImlkIjoxMiwiYXBwX2lkIjozLCJtZXRob2QiOiJHRVR8SEVBRCIsInVyaSI6IlwvIiwibmFtZSI6InN0YXJ0IiwicHVibGljIjoxfSx7ImlkIjoxMywiYXBwX2lkIjozLCJtZXRob2QiOiJHRVR8SEVBRCIsInVyaSI6IlwvbG9naW4iLCJuYW1lIjoibG9naW4iLCJwdWJsaWMiOjF9LHsiaWQiOjE0LCJhcHBfaWQiOjMsIm1ldGhvZCI6IlBPU1QiLCJ1cmkiOiJcL2xvZ2luIiwibmFtZSI6InBvc3QubG9naW4iLCJwdWJsaWMiOjF9LHsiaWQiOjE1LCJhcHBfaWQiOjMsIm1ldGhvZCI6IkdFVHxIRUFEIiwidXJpIjoiXC9ob21lIiwibmFtZSI6ImhvbWUiLCJwdWJsaWMiOjB9LHsiaWQiOjE2LCJhcHBfaWQiOjMsIm1ldGhvZCI6IkdFVHxIRUFEIiwidXJpIjoiXC9sb2dvdXQiLCJuYW1lIjoibG9nb3V0IiwicHVibGljIjowfV19XX0=" ] ] // statuscode 401 [ "status" => 401, "data" => [ "message" => "Credenciais inválidas." ] ] // statuscode 401 [ "status" => 401, "data" => [ "message" => "Usuário desativado." ] ] // statuscode 422 [ "status" => 422, "data" => [ "message" => "The given data was invalid." "errors" => [ "username" => "O campo username é obrigatório", "password" => "O campo password é obrigatório" ] ] ]
用户数据访问方法。
认证后,用户数据将在 Laravel 或 Lumen 的 Auth
Facade 中可用。请注意,如果不是默认守卫,则需要指定守卫。访问示例。
use Illuminate\Support\Facades\Auth; $user = Auth::guard('sag')->user(); dd($user->toArray()); // result [ 'id' => 3, 'name' => 'Nome Sobrenome', 'username' => 'nome.sobrenome', 'email' => 'nome.sobrenome@abcdaconstrucao.com.br', 'email_verified_at' => '2022-02-09 18:04:12', 'active' => '1', 'root' => '0', 'expire' => '1', 'created_by' => '1', 'updated_by' => '1', 'created_at' => '2022-02-09 21:04:12', 'updated_at' => '2022-02-09 21:04:12', 'apps' => [ 0 => [ 'id' => 1, 'name' => 'API_PEDIDOS_SERVER-DEV', 'url' => 'https://:3000', 'created_by' => '1', 'updated_by' => '1', 'active' => '1', 'created_at' => '2022-02-09 21:04:13', 'updated_at' => '2022-02-09 21:04:13', 'super_admin' => '1', 'groups' => [ 0 => [ 'id' => 1, 'app_id' => '1', 'name' => 'Farming', 'description' => 'Usuários do grupo Farming API_PEDIDOS_SERVER-DEV', 'active' => '1', 'created_by' => '3', 'updated_by' => '3', 'created_at' => '2022-02-09 21:04:13', 'updated_at' => '2022-02-09 21:04:13', 'permissions' => [ 0 => [ 'id' => 10, 'app_id' => '1', 'method' => 'GET', 'uri' => '/', 'name' => 'home', 'public' => '0', ], ], ], ], ], 1 => [ 'id' => 2, 'name' => 'API_PEDIDOS_FRONT-DEV', 'url' => 'https://:3100', 'created_by' => '1', 'updated_by' => '1', 'active' => '1', 'created_at' => '2022-02-09 21:04:13', 'updated_at' => '2022-02-09 21:04:13', 'super_admin' => '0', 'groups' => [ 0 => [ 'id' => 2, 'app_id' => '2', 'name' => 'Farming', 'description' => 'Usuários do grupo Farming API_PEDIDOS_FRONT-DEV', 'active' => '1', 'created_by' => '3', 'updated_by' => '3', 'created_at' => '2022-02-09 21:04:13', 'updated_at' => '2022-02-09 21:04:13', 'permissions' => [ 0 => [ 'id' => 4, 'app_id' => '2', 'method' => 'GET|HEAD', 'uri' => '/home', 'name' => 'home', 'public' => '0', ], ], ], ], ], ], ]
为登录用户提供补充数据。
如果您的应用程序需要为登录用户添加更多字段,只需在配置中指定一个实现了接口 \AbcDaConstrucao\AutenticacaoPackage\Contracts\MergeLocalUserInterface
的类。该类必须包含一个名为 getUserFromMerge(int $abcUserId)
的方法,该方法返回一个数组,该数组将与登录用户的数据合并。该方法接收登录用户的 id 作为参数,以方便与本地数据关联。示例实现。
<?php namespace App\Repositories; use AbcDaConstrucao\AutenticacaoPackage\Contracts\MergeLocalUserInterface; class UserRepository implements MergeLocalUserInterface { /** * @param int $abcUserId * @return array */ public function getUserFromMerge(int $abcUserId) { $userLocal = User::getByAbcId($abcUserId); return [ 'cpf' => $userLocal->cpf ]; } }
打开 .env
文件并在下面的键中添加类的命名空间。
USER_LOCAL_CLASS=\App\Repositories\UserRepository
现在访问 Auth
面板时,用户的新键将可访问。
[ 'id' => 3, 'name' => 'Nome Sobrenome', 'username' => 'nome.sobrenome', 'email' => 'nome.sobrenome@abcdaconstrucao.com.br', 'email_verified_at' => '2022-02-09 18:04:12', 'active' => '1', 'root' => '0', 'created_by' => '1', 'updated_by' => '1', 'created_at' => '2022-02-09 21:04:12', 'updated_at' => '2022-02-09 21:04:12', 'apps' => [...], 'cpf' => '03614568953' // dado adicionado pela aplicação local ]
辅助注销方法
Http::logoutRequest($tokenTipo, $token);
在所有应用程序的 SAG 中使令牌无效。
JWT::forgetToken();
仅在当前应用程序的缓存中删除令牌,但不在 SAG 中使令牌无效。其他应用程序将继续登录。
API 应用程序
全局注销
use AbcDaConstrucao\AutenticacaoPackage\Facades\Http; $router->post('/logout', ['as' => 'logout', function (Request $request) { $header = $request->header('Authorization'); $token = explode(' ', $header); $response = Http::logoutRequest($token[0], $token[1]); return response()->json($response['data'], $response['status']); }]);
对于 Laravel/Lumen 前端应用程序
全局注销
use AbcDaConstrucao\AutenticacaoPackage\Facades\Http; Route::post('/logout', ['as' => 'logout', function (Request $request) { $response = Http::logoutRequest(); // Redireciona a página desejada. if ($response['status'] == 200) { return redirect()->route('login'); } // Retorna erro caso exista. return back()->with('error', $response['data']); }]);
预期结果在 $response。
[ 'status' => 200, 'data' => [ 'message' => 'Desconectado com sucesso.' ] ]
本地应用程序注销
use AbcDaConstrucao\AutenticacaoPackage\Facades\JWT; Route::post('/logout', ['as' => 'logout', function (Request $request) { JWT::forgetToken(); return redirect()->route('login'); }]);
辅助验证访问权限方法
ACL::hasRouteAccess(string $routeNameOrUri)
方法接收一个路由的 名称
或 uri
,并返回一个布尔值,表示当前用户是否有访问权限。这可以在多种使用情况下应用。
// Lumen - routes/web.php $router->get('/api/profile', ['as' => 'api.profile', function (Request $request) use ($router) { // ... }]); use AbcDaConstrucao\AutenticacaoPackage\Facades\ACL; // Nome da rota. ACL::hasRouteAccess('api.profile'); // URI da rota ACL::hasRouteAccess('/api/profile');
授权
同步应用程序路由与认证 API
在创建或更新应用程序的路由后,必须使用同步命令。
php artisan abc-sag:sync-routes
可选地,可以在代码的任何位置使用辅助器。
use AbcDaConstrucao\AutenticacaoPackage\Facades\ACL;
ACL::syncRoutes();