PHP code example of jot / hf-shield

1. Go to this page and download the library: Download jot/hf-shield library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

jot / hf-shield example snippets


return [
    'token_format' => 'JWT',            // token format. By default, JWT
    'private_key' => '',                // path or content of the private key
    'public_key' => '',                 // path or content of the public key
    'encryption_key' => '',             // string for data encryption
    'token_days' => 'P1D',              // token validity in PHP DateTimeInterval format
    'refresh_token_days' => 'P1M',      // refresh token validity in PHP DateTimeInterval format
    'revoke_user_old_tokens' => true,   // enables trigger that revokes previous user/client tokens
];

#[Scope(allow: 'service:resource:permission')]
public function myAction(string $id): PsrResponseInterface {
   // ...
}

#[Middleware(middleware: BearerStragegy::class)]



declare(strict_types=1);

use Hyperf\Context\ApplicationContext;
use Jot\HfElastic\Migration;
use Jot\HfElastic\Migration\Mapping;

return new class(ApplicationContext::getContainer()) extends Migration {

    public const INDEX_NAME = 'my_awesome_index';
    public bool $addPrefix = true;

    public function up(): void
    {
        $index = new Mapping(name: self::INDEX_NAME, dynamic: 'strict');

        $index->keyword('id');
        $index->keyword('name')->normalizer('normalizer_ascii_lower');
        $index->alias('my_awesome_index_id')->path('id');
        $index->defaults();

        $index->settings(
            [
              'index' =>   [
                'number_of_shards' => 1,
                'number_of_replicas' => 0,
              ],
              'analysis' =>   [
                'normalizer' =>     [
                  'normalizer_ascii_lower' =>       [
                    'type' => 'custom',
                    'char_filter' =>         [
                    ],
                    'filter' =>         [
                      0 => 'asciifolding',
                      1 => 'lowercase',
                    ],
                  ],
                ],
              ],
            ]
        );

        $this->create($index);

    }

    public function down(): void
    {
        $this->delete(self::INDEX_NAME);
    }
};



declare(strict_types=1);

use Hyperf\Context\ApplicationContext;
use Jot\HfElastic\Migration;
use Jot\HfElastic\Migration\Mapping;
use Jot\HfElastic\Migration\ElasticType\NestedType;
use Jot\HfElastic\Migration\ElasticType\ObjectType;

return new class(ApplicationContext::getContainer()) extends Migration {

    public const INDEX_NAME = 'my_users';
    public bool $addPrefix = true;

    public function up(): void
    {
        $index = new Mapping(name: self::INDEX_NAME, dynamic: 'strict');

        $index->addField('keyword', 'id');
        $index->addField('keyword', 'name');
        $index->addField('keyword', 'email');
        $index->addField('long', 'age');
        $index->addField('double', 'salary');
        $index->addField('boolean', 'active');
        $address = new ObjectType('address');
        $address->addField('keyword', 'line1');
        $address->addField('keyword', 'line2');
        $address->addField('keyword', 'city');
        $address->addField('keyword', 'state');
        $address->addField('keyword', 'country');
        $index->object($address);
        $last_attempt_logins = new NestedType('last_attempt_logins');
        $last_attempt_logins->addField('date', 'datetime');
        $last_attempt_logins->addField('ip', 'ip_address');
        $last_attempt_logins->addField('keyword', 'user_agent');
        $last_attempt_logins->addField('keyword', 'status');
        $last_attempt_logins->addField('keyword', 'error');
        $index->nested($last_attempt_logins);

        $index->alias('my_user_id')->path('id');
        $index->defaults();

        $index->settings(
            [
              'index' =>   [
                'number_of_shards' => 1,
                'number_of_replicas' => 0,
              ],
              'analysis' =>   [
                'normalizer' =>     [
                  'normalizer_ascii_lower' =>       [
                    'type' => 'custom',
                    'char_filter' =>         [
                    ],
                    'filter' =>         [
                      0 => 'asciifolding',
                      1 => 'lowercase',
                    ],
                  ],
                ],
              ],
            ]
        );

        $this->create($index);

    }

    public function down(): void
    {
        $this->delete(self::INDEX_NAME);
    }
};



declare(strict_types=1);

namespace App\Controller\V2;

use App\Service\MyUserService;
use Hyperf\Di\Annotation\Inject;
use Hyperf\HttpServer\Annotation\Controller;
use Hyperf\HttpServer\Annotation\Middleware;
use Hyperf\HttpServer\Annotation\RequestMapping;
use Hyperf\RateLimit\Annotation\RateLimit;
use Hyperf\Swagger\Annotation as SA;
use Jot\HfShield\Annotation\Scope;
use Jot\HfShield\Middleware\SessionStrategy;
use Psr\Http\Message\ResponseInterface as PsrResponseInterface;

#[SA\HyperfServer('http')]
#[SA\Tag(
    name: 'MyUser',
    description: 'Endpoints related to my_users management'
)]
#[SA\Schema(
    schema: 'admin.error.response',
    te const RESPONSE_SCHEMA_CONTENT = '#/components/schemas/app.entity.my_user.my_user';

    private const RESPONSE_SCHEMA_ERROR = '#/components/schemas/admin.error.response';

    #[Inject]
    protected MyUserService $service;

    #[SA\Get(
        path: self::REQUEST_PATH,
        description: 'Retrieve a list of my_users with optional pagination and filters.',
        summary: 'Get MyUsers List',
        security: [['shieldBearerAuth' => ['admin:my_user:list']]],
        tags: ['MyUser'],
        parameters: [
            new SA\Parameter(
                name: self::QUERY_PAGE_NUMBER,
                description: self::DESCRIPTION_PAGE_NUMBER,
                in: 'query',
                e: 'array',
                            items: new SA\Items(ref: self::RESPONSE_SCHEMA_CONTENT)
                        ),
                        new SA\Property(
                            property: 'result',
                            type: 'string',
                            example: 'success'
                        ),
                        new SA\Property(
                            property: 'error',
                            type: 'string',
                            example: null,
                            nullable: true
                        ),
                    ],
                    type: 'object'
                )
            ),
            new SA\Response(
                response: 400,
                description: self::DESCRIPTION_BAD_REQUEST,
                content: new SA\JsonContent(ref: self::RESPONSE_SCHEMA_ERROR)
            ),
            new SA\Response(
                response: 401,
                description: self::DESCRIPTION_UNAUTHORIZED_ACCESS,
                content: new SA\JsonContent(ref: self::RESPONSE_SCHEMA_ERROR)
            ),
            new SA\Response(
                response: 403,
                description: self::DESCRIPTION_FORBIDDEN_ACCESS,
                content: new SA\JsonContent(ref: self::RESPONSE_SCHEMA_ERROR)
            ),
            new SA\Response(
                response: 500,
                description: self::DESCRIPTION_APPLICATION_ERROR,
                content: new SA\JsonContent(ref: self::RESPONSE_SCHEMA_ERROR)
            ),
        ]
    )]
    #[RateLimit(create: 1, capacity: 10)]
    #[Scope(allow: 'admin:my_user:list')]
    #[Middleware(middleware: SessionStrategy::class)]
    public function getMyUserList(): PsrResponseInterface
    {
        $result = $this->service->paginate($this->request->query());
        if ($result['result'] === 'error') {
            return $this->response->withStatus(400)->json($result);
        }

        return $this->response
            ->withHeader('Access-Control-Allow-Origin', '*')
            ->json($result);
    }

    #[SA\Get(
        path: self::REQUEST_PATH_ID,
        description: 'Retrieve the details of a specific my_users identified by ID.',
        summary: 'Get MyUser Data',
        security: [['shieldBearerAuth' => ['admin:my_user:view']]],
        tags: ['MyUser'],
        parameters: [
            new SA\Parameter(
                name: 'id',
                description: self::DESCRIPTION_PARAMETER_ID,
                in: 'path',
                CESS,
                content: new SA\JsonContent(ref: self::RESPONSE_SCHEMA_ERROR)
            ),
            new SA\Response(
                response: 500,
                description: self::DESCRIPTION_APPLICATION_ERROR,
                content: new SA\JsonContent(ref: self::RESPONSE_SCHEMA_ERROR)
            ),
        ]
    )]
    #[RateLimit(create: 1, capacity: 5)]
    #[Scope(allow: 'admin:my_user:create')]
    #[Middleware(middleware: SessionStrategy::class)]
    public function createMyUser(): PsrResponseInterface
    {
        $result = $this->service->create($this->request->all());
        return $this->response->withStatus(201)->json($result);
    }

    #[SA\Put(
        path: self::REQUEST_PATH_ID,
        description: 'Update the details of an existing my_users.',
        summary: 'Update an existing MyUser',
        security: [['shieldBearerAuth' => ['admin:my_user:update']]],
        requestBody: new SA\RequestBody(
            MyUser(string $id): PsrResponseInterface
    {
        $result = $this->service->delete($id);
        return $this->response->json($result);
    }

    #[SA\Head(
        path: self::REQUEST_PATH_ID,
        description: 'Check if a valid my_users exists by its unique identifier.',
        summary: 'Check my_users',
        security: [['shieldBearerAuth' => ['admin:my_user:verify']]],
        tags: ['MyUser'],
        parameters: [
            new SA\Parameter(
                name: 'id',
                description: 'Unique identifier of the my_users',
                in: 'path',
                



declare(strict_types=1);

namespace Jot\HfShield\Entity\MyUser;

use DateTimeInterface;
use Jot\HfRepository\Entity;
use Jot\HfRepository\Entity\Traits\HasLogicRemovalTrait as HasLogicRemoval;
use Jot\HfRepository\Entity\Traits\HasTimestampsTrait as HasTimestamps;
use Hyperf\Swagger\Annotation as SA;

#[SA\Schema(schema: "app.entity.my_user.my_user")]
class MyUser extends Entity
{
    use HasLogicRemoval;
    use HasTimestamps;

    #[SA\Property(
        property: 'id',
        type: 'string',
        readOnly: true,
        example: ''
    )]
    protected null|string $id = null;

    #[SA\Property(
        property: 'active',
        type: 'boolean',
        example: true
    )]
    protected null|bool|int $active = null;

    #[SA\Property(
        property: 'address',
        ref: '#/components/schemas/app.entity.my_user.address',
        x: ['php_type' => '\Jot\HfShield\Entity\MyUser\Address']
    )]
    protected null|\Jot\HfShield\Entity\MyUser\Address $address = null;

    #[SA\Property(
        property: 'age',
        type: 'integer',
        example: 5
    )]
    protected null|int $age = null;

    #[SA\Property(
        property: 'email',
        type: 'string',
        example: ''
    )]
    protected null|string $email = null;

    #[SA\Property(
        property: 'last_attempt_logins',
        type: 'array',
        items: new SA\Items(ref: '#/components/schemas/app.entity.my_user.last_attempt_login'),
        x: ['php_type' => '\Jot\HfShield\Entity\MyUser\LastAttemptLogin[]']
    )]
    protected null|array $lastAttemptLogins = null;

    #[SA\Property(
        property: 'name',
        type: 'string',
        example: ''
    )]
    protected null|string $name = null;

    #[SA\Property(
        property: 'salary',
        type: 'number',
        format: 'float',
        example: 123.45
    )]
    protected null|float $salary = null;

    #[SA\Property(
        property: 'created_at',
        type: 'string',
        format: 'date-time',
        x: ['php_type' => '\DateTime']
    )]
    protected null|DateTimeInterface $createdAt = null;

    #[SA\Property(
        property: 'updated_at',
        type: 'string',
        format: 'date-time',
        x: ['php_type' => '\DateTime']
    )]
    protected null|DateTimeInterface $updatedAt = null;
}


POST /whatsapp/login/start
{
    "federal_document": "A registered user CPF"
}
shell
php bin/hyperf.php vendor:publish hyperf/etcd
shell
php bin/hyperf.php vendor:publish hyperf/redis
shell
php bin/hyperf.php etcd:put redis
shell
php bin/hyperf.php vendor:publish jot/hf-elastic
shell
php bin/hyperf.php etcd:put hf_elastic
shell
php bin/hyperf.php vendor:publish jot/hf-repository
shell
php bin/hyperf.php vendor:publish hyperf/rate-limit
shell
php bin/hyperf.php vendor:publish jot/hf-shield
shell
php bin/hyperf.php elastic:migrate
shell
php bin/hyperf.php vendor:publish hyperf/translation 
php bin/hyperf.php vendor:publish jot/hf-shield 
shell
php bin/hyperf.php vendor:publish jot/hf-elastic 
php bin/hyperf.php vendor:publish jot/hf-validator 
php bin/hyperf.php vendor:publish jot/hf-repository 
shell
php bin/hyperf.php oauth:scope sync
json
{
  "id": "abc-1234",
  "name": "John Doe",
  "email": "[email protected]",
  "age": 40,
  "salary": 1234.56,
  "active": true,
  "address": {
    "line1": "Street name, number",
    "line2": "Business Office Tower, 8th floor",
    "city": "New York",
    "state": "NY",
    "country": "USA"
  },
  "last_attempt_logins": [
    {
      "datetime": "2025-01-01T16:00:00-03:00",
      "ip_address": "200.242.30.253",
      "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:138.0) Gecko/20100101 Firefox/138.0",
      "status": "failed",
      "error": "Invalid user and password combination."
    },
    {
      "datetime": "2025-01-01T16:00:00-03:00",
      "ip_address": "200.242.30.253",
      "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:138.0) Gecko/20100101 Firefox/138.0",
      "status": "success",
      "error": ""
    }
  ]
}
shell
php bin/hyperf.php elastic:migration users --json=migration/samples/user_example.json
shell
php bin/hyperf.php elastic:migrate
shell
php bin/hyperf.php elastic:migrate --index=users
shell
php bin/hyperf.php elastic
shell
php bin/hyperf.php repo:controller --index=my_users
shell
php bin/hyperf.php repo:repository --index=my_users
shell
php bin/hyperf.php repo:service --index=my_users
shell
php bin/hyperf.php repo:entity --index=my_users

app/Entity
└── MyUser
    ├── Address.php
    ├── LostAttemptLogin.php
    └── MyUser.php