Update documentation and examples, add new nominal accounts features and authentication methods

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
2026-01-24 17:18:59 +03:00
parent 2964c391b5
commit bb5f91d399
13 changed files with 290 additions and 157 deletions

View File

@@ -11,36 +11,10 @@ use Apoloz\AlfaBank\Core\AlfaConfig;
use Apoloz\AlfaBank\Enums\Environment;
use Apoloz\AlfaBank\Services\OpenSslCmsSigner;
use Apoloz\AlfaBank\Sbp\SbpConnector;
use Apoloz\AlfaBank\Services\H2HAuthService;
use Apoloz\AlfaBank\Requests\Accounts\GetAccountsRequest;
class AlfaBank
{
/**
* Creates a helper service for H2H Authorization (Authorization Code Flow).
*/
public static function auth(
string $clientId,
string $clientSecret,
string $redirectUri,
string $certificatePath,
string $privateKeyPath,
Environment $environment = Environment::SANDBOX
): H2HAuthService {
$config = new \Apoloz\AlfaBank\Core\AlfaConfig(
baseUrl: $environment->value,
certificatePath: $certificatePath,
privateKeyPath: $privateKeyPath,
clientId: $clientId,
clientSecret: $clientSecret
);
$signer = new \Apoloz\AlfaBank\Services\OpenSslCmsSigner($certificatePath, $privateKeyPath);
$connector = new \Apoloz\AlfaBank\Core\AlfaBankConnector($config, $signer);
return new H2HAuthService($connector, $clientId, $redirectUri, $environment);
}
/**
* Performs a health check on the connection.
* Throws an exception if authentication or account listing fails.
@@ -64,6 +38,9 @@ class AlfaBank
string $privateKeyPath,
Environment $environment = Environment::SANDBOX,
?string $caBundlePath = null,
?string $clientId = null,
?string $clientSecret = null,
?string $redirectUri = null,
?string $signingCertificatePath = null,
?string $signingPrivateKeyPath = null
): AlfaBankConnector {
@@ -72,6 +49,9 @@ class AlfaBank
certificatePath: $certificatePath,
privateKeyPath: $privateKeyPath,
caBundlePath: $caBundlePath,
clientId: $clientId,
clientSecret: $clientSecret,
redirectUri: $redirectUri,
signingCertificatePath: $signingCertificatePath,
signingPrivateKeyPath: $signingPrivateKeyPath
);

View File

@@ -9,8 +9,9 @@ namespace Apoloz\AlfaBank\Core;
use Apoloz\AlfaBank\Contracts\SignerInterface;
use Apoloz\AlfaBank\Http\Middleware\RequestIdMiddleware;
use Apoloz\AlfaBank\Http\Pagination\AlfaOffsetPaginator;
use Apoloz\AlfaBank\Requests\Auth\GetTokenRequest;
use Apoloz\AlfaBank\Requests\Auth\GetTokenRequest; // Will be removed
use Apoloz\AlfaBank\Traits\HasAlfaErrorHandling;
use Saloon\Helpers\OAuth2\OAuthConfig;
use Saloon\Http\Connector;
use Saloon\Http\Request;
use Saloon\PaginationPlugin\Contracts\HasPagination;
@@ -18,13 +19,17 @@ use Saloon\PaginationPlugin\OffsetPaginator;
use Saloon\Traits\Plugins\AlwaysThrowOnErrors;
use Saloon\Traits\RequestProperties\HasTries;
use Saloon\Traits\Plugins\HasTimeout;
use Saloon\Contracts\OAuth2\OAuth2Api;
use Saloon\Traits\OAuth2\AuthorizationCodeGrant;
use Apoloz\AlfaBank\Enums\Environment;
class AlfaBankConnector extends Connector implements HasPagination
class AlfaBankConnector extends Connector implements HasPagination, OAuth2Api
{
use HasTimeout;
use HasTries;
use AlwaysThrowOnErrors;
use HasAlfaErrorHandling;
use AuthorizationCodeGrant;
public function __construct(
protected AlfaConfig $alfaConfig,
@@ -39,6 +44,20 @@ class AlfaBankConnector extends Connector implements HasPagination
return $this->alfaConfig->baseUrl;
}
protected function resolveOauth2Config(): OAuthConfig
{
$idUrl = $this->alfaConfig->baseUrl === Environment::PRODUCTION->value
? Environment::ID_PRODUCTION->value
: Environment::ID_SANDBOX->value;
return OAuthConfig::make()
->setClientId($this->alfaConfig->clientId ?? '')
->setClientSecret($this->alfaConfig->clientSecret ?? '')
->setRedirectUri($this->alfaConfig->redirectUri ?? '')
->setAuthorizeEndpoint($idUrl . '/oidc/authorize')
->setTokenEndpoint('/oidc/token');
}
protected function defaultConfig(): array
{
$config = [
@@ -79,55 +98,7 @@ class AlfaBankConnector extends Connector implements HasPagination
return new AlfaOffsetPaginator($this, $request);
}
/**
* Exchange Authorization Code for tokens (H2H Flow).
*/
public function authWithCode(string $code, string $redirectUri): \Apoloz\AlfaBank\Data\Auth\TokenData
{
if (!$this->alfaConfig->clientId || !$this->alfaConfig->clientSecret) {
throw new \RuntimeException("Client ID/Secret not configured.");
}
$request = new GetTokenRequest(
clientId: $this->alfaConfig->clientId,
clientSecret: $this->alfaConfig->clientSecret,
code: $code,
redirectUri: $redirectUri,
grantType: 'authorization_code'
);
$response = $this->send($request);
$data = $response->dto();
$this->authenticate(new \Saloon\Http\Auth\TokenAuthenticator($data->access_token));
return $data;
}
/**
* Refresh access token using refresh token.
*/
public function refreshToken(string $refreshToken): \Apoloz\AlfaBank\Data\Auth\TokenData
{
if (!$this->alfaConfig->clientId || !$this->alfaConfig->clientSecret) {
throw new \RuntimeException("Client ID/Secret not configured.");
}
$request = new GetTokenRequest(
clientId: $this->alfaConfig->clientId,
clientSecret: $this->alfaConfig->clientSecret,
refreshToken: $refreshToken,
grantType: 'refresh_token'
);
$response = $this->send($request);
$data = $response->dto();
$this->authenticate(new \Saloon\Http\Auth\TokenAuthenticator($data->access_token));
return $data;
}
// login() kept for ClientCredentials compatibility (legacy/simple flow)
public function login(?string $clientId = null, ?string $clientSecret = null): static
{
// Allow overriding config via method arguments
@@ -144,9 +115,6 @@ class AlfaBankConnector extends Connector implements HasPagination
grantType: 'client_credentials'
);
// Send request (using self to reuse cert/ssl config)
// We temporarily disable auth middleware if we had any,
// but here we are raw, so it's fine.
$response = $this->send($request);
$data = $response->dto();
@@ -155,6 +123,7 @@ class AlfaBankConnector extends Connector implements HasPagination
return $this;
}
// </SECTION>
// </SECTION>
// <SECTION name="signer_accessor" intent="Provide access to the configured signing service for requests that require a digital signature.">
// <BELIEF_STATE "Requests should not instantiate their own signing logic. The connector acts as a service locator, providing the globally-configured Signer service. This ensures that all signatures are generated consistently.">

View File

@@ -33,6 +33,8 @@ readonly class AlfaConfig
public ?string $clientId = null,
// <BELIEF_STATE "Optional: The OAuth client secret, required for token-based authentication.">
public ?string $clientSecret = null,
// <BELIEF_STATE "Optional: The OAuth redirect URI, required for authorization code flow.">
public ?string $redirectUri = null,
// <BELIEF_STATE "Optional: Path to the certificate used specifically for signing requests (JWS/CMS), if different from the transport certificate.">
public ?string $signingCertificatePath = null,
// <BELIEF_STATE "Optional: Path to the private key used specifically for signing requests (JWS/CMS), if different from the transport key.">

View File

@@ -26,5 +26,8 @@ enum Environment: string
case SBP_PRODUCTION = 'https://pay.alfabank.ru/fsCryptoProxy';
case SBP_SANDBOX = 'https://217.12.103.132:2443/fsCryptoProxy';
// </SECTION>
case ID_PRODUCTION = 'https://id.alfabank.ru';
case ID_SANDBOX = 'https://id-sandbox.alfabank.ru';
}
// </SECTION>