简单的JWT代码库

3.0 2024-08-04 21:48 UTC

This package is auto-updated.

Last update: 2024-09-04 22:16:27 UTC


README

Build

使用此仓库的帮助,完全控制JWS身份验证。

安装

composer require rafalswierczek/jwt

使用

请记住,这个库是一个代码库,所以将其视为您的源代码。注意合同中定义的异常,并捕获它们。

除非您对要实施的整个架构有100%的了解,否则什么都不会工作。

对称签名系统

  • 非常安全地保管您的JWS密钥,并在应用程序之间共享,以便一个JWS可用于与多个应用程序进行身份验证。这几乎就是使用JWT系统的主要原因。
  • 在认证服务器或单体中的认证模块
    • 创建自己的端点,该端点将检查用户凭据,并在成功响应中返回生成的JWS。
    • 创建自己的JWSIssuerInterfaceJWSHeaderJWSPayload实例,并生成应在认证端点返回的新JWS。
    • 创建自己的RefreshTokenProviderInterface实例,并生成应与JWS一起返回的新刷新令牌。
    • 您**必须**为每个刷新令牌有1个唯一的密钥。将它们存储在具有唯一索引的表中。如果刷新令牌被破解或有人使用它应该被禁止,那么根据JWT系统的定义,您无法做任何事情。处理这种情况的唯一方法是使与刷新令牌关联的密钥在该表中无效,以防止用户生成新的JWS,该JWS应根据安全措施在3~15分钟内有效。
    // Issuer example:
    namespace YourApp\AuthServer\Infrastructure;
    
    use YourApp\AuthServer\Application\JWSIssuer;
    use YourApp\AuthServer\Domain\Header;
    use YourApp\AuthServer\Domain\Payload;
    use YourApp\AuthServer\Domain\User;
    use rafalswierczek\JWT\JWS\Enum\Header\AlgorithmType;
    use rafalswierczek\JWT\JWS\Enum\Header\TokenType;
    use rafalswierczek\JWT\JWS\Issuer\JWSIssuerInterface;
    use rafalswierczek\JWT\JWS\Model\JWSHeader;
    use rafalswierczek\JWT\JWS\Model\JWSPayload;
    use rafalswierczek\Uuid4\Uuid4Factory;
    
    final class RafalswierczekJWSIssuer implements JWSIssuer
    {
        public function __construct(private JWSIssuerInterface $issuer)
        {
        }
    
        public function issueToken(User $user): string
        {
            $header = Header::create();
    
            $payload = Payload::create(
                jwtId: Uuid4Factory::create()->toHex(),
                userId: $user->id,
            );
    
            return $this->issuer->generateCompactJWS(
                header: $this->mapHeader($header),
                payload: $this->mapPayload($payload, $user),
                secret: $_ENV['JWS_PRIVATE_KEY'],
            );
        }
    
        private function mapHeader(Header $header): JWSHeader
        {
            return new JWSHeader(
                tokenType: TokenType::from($header->typ),
                algorithmType: AlgorithmType::from($header->alg),
            );
        }
    
        private function mapPayload(Payload $payload, User $user): JWSPayload
        {
            return new JWSPayload(
                id: $payload->jti, // globally unique JWT id
                issuer: $payload->iss, // domain of auth server (might be the same as audience element)
                subject: $payload->sub, // user-uuid
                issuedAt: (new \DateTimeImmutable())->setTimestamp($payload->iat),
                expirationTime: (new \DateTimeImmutable())->setTimestamp($payload->exp),
                audience: $payload->aud, // ['yourdomain1.com', 'yourdomain2.com']
                data: ['user' => $user], // user metadata known to all audience applications
            );
        }
    }
  • 在匹配受众的每个应用程序中
    • 创建自己的认证器,并从那里使用您的JWSVerifierInterface实例验证请求头中的JWS。
    • 如果JWS已过期(JWSHasExpiredException),则尝试请求您的认证服务器使用当前刷新令牌生成新的JWS。返回403。
    • JWSCompromisedSignatureException是一个红旗,很可能是攻击或错误。将其记录为错误或警报,并返回403。
    • CannotMatchAudienceException可能是旧域名的问题,或者JWS根本不应该用于该特定应用程序。将其记录为警告,并返回403。
    • 如果刷新令牌无效,请注销用户并强制他们使用您使用的任何凭据登录(认证服务器端点)。