jardissupport/auth
Composer 安装命令:
composer require jardissupport/auth
包简介
Opaque token management, session handling, password hashing, and role-based access control for PHP DDD applications — framework-free, no JWT, no third-party runtime dependencies beyond PHP built-ins and the Jardis contract
关键字:
README 文档
README
Part of Jardis — the Domain-Driven Design platform for PHP. You model your domain; Jardis generates the production-ready hexagonal code (DTOs, Command/Query handlers, repositories, persistence). This package is part of the open-source foundation that generated code runs on.
Authentication and authorization without framework coupling. A focused RBAC for PHP covering opaque tokens, session management, password hashing, and role-based access control — designed for DDD applications. No HTTP layer, no JWT, no third-party runtime dependencies beyond PHP built-ins and the Jardis contract. Pure support package.
Why This Package?
- Four classes to learn —
SessionManager,PasswordHasher,Guard,PasswordAuthenticator. Everything else is data - Opaque tokens — server-side state, SHA-256 hashed storage, no JWT complexity
- Token rotation — automatic refresh with old-token revocation
- RBAC as Value Objects — policies are immutable, defined in code, not in a database
- No third-party runtime dependencies — PHP built-ins (
password_hash,random_bytes,hash_hmac,hash_equals) plus the Jardis contract
Installation
composer require jardissupport/auth
Quick Start
Create a Session
use JardisSupport\Auth\SessionManager; use JardisSupport\Auth\Data\Subject; $sessionManager = new SessionManager($tokenStore); $subject = Subject::from('user-42', 'user'); $result = $sessionManager->create($subject, ['role' => 'editor']); $accessToken = $result->accessToken; // send to client $refreshToken = $result->refreshToken; // store securely on client $session = $result->session; // use server-side // Dispatch events (optional — use your EventDispatcher) foreach ($result->events as $event) { $dispatcher->dispatch($event); }
Verify & Refresh Tokens
use JardisSupport\Auth\Handler\Token\VerifyToken; use JardisSupport\Auth\Data\TokenType; // Verify an access token $verifier = new VerifyToken(); $hash = hash('sha256', $accessToken); $stored = $tokenStore->find($hash); $verifier($accessToken, $stored, TokenType::Access); // throws TokenExpiredException or TokenRevokedException // Refresh — rotates tokens, revokes the old refresh token $newResult = $sessionManager->refresh($refreshToken); // $newResult->events contains SessionCreated + SessionRefreshed
Hash & Verify Passwords
use JardisSupport\Auth\PasswordHasher; $hasher = PasswordHasher::argon2id(); // Registration $hash = $hasher->hash('secret-password'); // Login $hasher->verify('secret-password', $hash); // true // Rehash check on every login if ($hasher->needsRehash($hash)) { $newHash = $hasher->hash('secret-password'); // update stored hash }
Authorize with RBAC
use JardisSupport\Auth\Guard; use JardisSupport\Auth\Data\Policy; $policy = Policy::create() ->role('admin')->allow('*') ->role('editor') ->allow('article:read', 'article:write', 'article:publish') ->deny('article:delete') ->role('viewer')->allow('article:read') ->role('moderator')->includes('editor')->allow('comment:delete') ->build(); $guard = new Guard($policy); $guard->check($session, 'article:publish'); // true/false $guard->authorize($session, 'article:delete'); // throws UnauthorizedException // Multi-role sessions — first matching role wins $session = new Session( subject: 'user:42', tokenHash: $hash, createdAt: new DateTimeImmutable(), expiresAt: null, metadata: ['role' => ['editor', 'moderator']], ); $guard->check($session, 'comment:delete'); // true (moderator has permission)
Authenticate with Password
use JardisSupport\Auth\PasswordAuthenticator; use JardisSupport\Auth\Data\Credential; $authenticator = new PasswordAuthenticator( $passwordHasher, $sessionManager, function (string $identifier): ?array { $user = $userRepository->findByEmail($identifier); if ($user === null) { return null; } return [ 'hash' => $user->passwordHash, 'subject' => Subject::from($user->id, 'user'), 'claims' => ['role' => $user->role], ]; }, ); $credential = Credential::password('john@example.com', 'secret123'); $result = $authenticator->authenticate($credential); if ($result->isSuccess()) { $session = $result->session; $accessToken = $result->accessToken; } // All events in one place: SessionCreated + AuthenticationSucceeded (or AuthenticationFailed) foreach ($result->events as $event) { $dispatcher->dispatch($event); }
Invalidate Sessions
// Single session (logout) — returns SessionInvalidated event $event = $sessionManager->invalidate($session); // All sessions for a subject (logout everywhere) — returns AllSessionsInvalidated event $event = $sessionManager->invalidateAll('user:user-42');
Token Store
The package defines TokenStoreInterface — you implement it in your infrastructure layer:
use JardisSupport\Contract\Auth\TokenStoreInterface; use JardisSupport\Auth\Data\HashedToken; class DatabaseTokenStore implements TokenStoreInterface { public function __construct(private PDO $pdo) {} public function store(HashedToken $token): void { /* INSERT */ } public function find(string $hash): ?HashedToken { /* SELECT */ } public function revoke(string $hash): void { /* UPDATE revoked = true */ } public function revokeAllForSubject(string $subject): void { /* UPDATE WHERE subject = ? */ } public function deleteExpired(): int { /* DELETE WHERE expires_at < NOW() */ } }
An InMemoryTokenStore is included in tests/Support/ for testing.
Password Hashing
// Argon2id (default, recommended) $hasher = PasswordHasher::argon2id(memoryCost: 65536, timeCost: 4, threads: 1); // Bcrypt (fallback) $hasher = PasswordHasher::bcrypt(cost: 12); // Default constructor uses Argon2id $hasher = new PasswordHasher();
Error Handling
| Exception | When |
|---|---|
AuthenticationException |
Authentication failed (base class) |
TokenExpiredException |
Token has expired |
TokenRevokedException |
Token was revoked |
InvalidCredentialException |
Invalid credentials provided |
UnauthorizedException |
Insufficient permissions (RBAC) |
use JardisSupport\Auth\Exception\TokenExpiredException; use JardisSupport\Auth\Exception\UnauthorizedException; try { $verifier($token, $storedToken, TokenType::Access); } catch (TokenExpiredException $e) { // Token expired — client should use refresh token } try { $guard->authorize($session, 'admin:delete'); } catch (UnauthorizedException $e) { // Access denied }
Architecture
The user sees four orchestrators. Internally, each delegates to invokable handlers:
SessionManager (Orchestrator)
├── Handler/Session/CreateSession create session + token pair + SessionCreated event
├── Handler/Session/RefreshSession rotate tokens + SessionRefreshed event
├── Handler/Session/InvalidateSession revoke single session + SessionInvalidated event
└── Handler/Session/InvalidateAllSessions revoke all + AllSessionsInvalidated event
PasswordAuthenticator (Orchestrator)
├── Handler/Authentication/LookupUser resolve user via $userLookup closure
├── Handler/Authentication/VerifyCredential verify password against hash
└── Handler/Authentication/BuildAuthResult assemble AuthenticationResult + events
PasswordHasher (Orchestrator)
├── Handler/Password/HashPassword hash via password_hash()
├── Handler/Password/VerifyPassword verify via password_verify()
└── Handler/Password/CheckRehash check via password_needs_rehash()
Guard (Orchestrator)
├── Handler/Authorization/CheckPermission check role(s) against policy
└── Handler/Authorization/AuthorizePermission check + throw on failure
Data (Value Objects, Enums, Builder, Events)
├── Token, HashedToken, TokenType
├── Session, SessionResult
├── Subject, Credential, CredentialType, AuthResult, AuthenticationResult
├── Permission, Policy, PolicyBuilder
└── Event/ (AuthenticationSucceeded, AuthenticationFailed, SessionCreated,
SessionRefreshed, SessionInvalidated, AllSessionsInvalidated)
Each handler is an invokable object (__invoke) — independently testable, replaceable, composable. The orchestrators contain no business logic, only delegation.
Test Structure
Tests mirror the src/ directory:
tests/Integration/
├── GuardTest.php ← src/Guard.php
├── SessionManagerTest.php ← src/SessionManager.php
├── PasswordHasherTest.php ← src/PasswordHasher.php
├── PasswordAuthenticatorTest.php ← src/PasswordAuthenticator.php
├── Data/
│ ├── AuthResultTest.php ← src/Data/AuthResult.php
│ ├── CredentialTest.php ← src/Data/Credential.php
│ ├── SubjectTest.php ← src/Data/Subject.php
│ ├── PermissionTest.php ← src/Data/Permission.php
│ ├── PolicyTest.php ← src/Data/Policy.php
│ ├── TokenTest.php ← src/Data/Token.php
│ └── HashedTokenTest.php ← src/Data/HashedToken.php
├── Handler/Token/
│ └── VerifyTokenTest.php ← src/Handler/Token/VerifyToken.php
└── Support/
└── InMemoryTokenStoreTest.php ← tests/Support/InMemoryTokenStore.php
Contracts
Defined in jardissupport/contract — implement these in your infrastructure:
| Interface | Purpose |
|---|---|
TokenStoreInterface |
Token persistence: store, find, revoke, deleteExpired |
PasswordHasherInterface |
Hash, verify, needsRehash |
GuardInterface |
Permission check + authorize |
AuthenticatorInterface |
Authenticate credentials, return AuthResult |
Foundation Integration
Auth is a support package — no service hook in DomainApp. Integration happens in your bounded context:
- TokenStore: Implement in infrastructure (database, Redis)
- Policy: Define as value object in application layer
- Guard: Instantiate in application layer, inject Policy
ENV Variables (optional)
# Password Hashing AUTH_HASH_ALGO=argon2id AUTH_HASH_MEMORY=65536 AUTH_HASH_TIME=4 AUTH_HASH_THREADS=1 # Token Defaults AUTH_TOKEN_LENGTH=32 AUTH_ACCESS_TOKEN_TTL=3600 AUTH_REFRESH_TOKEN_TTL=604800
What This Package Does NOT Do
- No JWT — opaque tokens only. JWT comes in v2 at the earliest
- No OAuth2/OIDC — no authorization server, no PKCE
- No HTTP layer — no cookies, no middleware, no
session_start() - No user management — no user model, no registration flow
- No rate limiting — brute-force protection is infrastructure concern
- No token persistence — only the interface. You implement the store
- No event dispatching — events are returned to the caller, not dispatched internally
Development
cp .env.example .env # One-time setup make install # Install dependencies make phpunit # Run tests make phpstan # Static analysis (Level 8) make phpcs # Coding standards (PSR-12)
Documentation
Full documentation, guides, and API reference:
docs.jardis.io/en/support/auth
License
MIT License — free for any use, including commercial.
AI-Assisted Development
This package ships with a skill for Claude Code, Cursor, Continue, and Aider. Install it in your consuming project:
composer require --dev jardis/dev-skills
More details: https://docs.jardis.io/en/skills
jardissupport/auth 适用场景与选型建议
jardissupport/auth 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 0 次下载、GitHub Stars 达 0, 最近一次更新时间为 2026 年 04 月 05 日, 在 PHP 生态内属于活跃度较高的组件。
它主要适用于以下技术方向: 「php」 「authorization」 「security」 「Authentication」 「session」 「auth」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。
我们在过去多个企业项目中使用过 jardissupport/auth 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 jardissupport/auth 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
与 jardissupport/auth 相关的其它包
同方向 / 同关键字的高下载量 PHP Composer 包推荐,方便对比选型:
Ory-Hydra OAuth 2.0 Client Provider for The PHP League OAuth2-Client
A lightweight and powerful OAuth 2.0 authorization and resource server library with support for all the core specification grants. This library will allow you to secure your API with OAuth and allow your applications users to approve apps that want to access their data from your API.
Provide a way to secure accesses to all routes of an symfony application.
It's a barebone security class written on PHP
Laravel JWT auth service package
Contao CMS integrity check for some files
统计信息
- 总下载量: 0
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 0
- 点击次数: 46
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2026-04-05