承接 ra-devs/jwt-auth 相关项目开发

从需求分析到上线部署,全程专人跟进,保证项目质量与交付效率

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

ra-devs/jwt-auth

最新稳定版本:v1.4.4

Composer 安装命令:

composer require ra-devs/jwt-auth

包简介

Universal JWT auth for Laravel (tymon/jwt-auth + ra-devs/api-json-response)

README 文档

README

Production-ready JWT authentication package for Laravel

Built on top of tymon/jwt-auth + ra-devs/api-json-response

Laravel PHP License

✨ Features

Feature Description
🔑 Authentication Complete auth flow: Login, Register, Logout, Token Refresh
🔒 Password Reset Secure 8-character alphanumeric codes (A–Z, 2–9) via email
🛡️ Security Rate limiting, event logging, custom exceptions
📊 Monitoring Security event logging for audit trails
🎯 Error Handling Structured error responses with error codes
Performance Database indexes, optimized queries
🧪 Testing Comprehensive test suite with >80% coverage
📚 Documentation OpenAPI spec, examples, FAQ
🔧 Customizable User model, Resources, Repositories, Notifications
📦 Publishable Config, migrations, routes, views

📋 Table of Contents

🚀 Installation

Step 1: Install Dependencies

Install the required packages via Composer:

composer require tymon/jwt-auth "^2.0"
composer require ra-devs/api-json-response "^1.0"
composer require ra-devs/jwt-auth:dev-main

Step 2: Publish Package Resources

Publish the configuration, migrations, and views:

# Publish configuration
php artisan vendor:publish --provider="RaDevs\JwtAuth\Providers\JwtAuthServiceProvider" --tag=ra-jwt-auth-config

# Publish migrations
php artisan vendor:publish --provider="RaDevs\JwtAuth\Providers\JwtAuthServiceProvider" --tag=ra-jwt-auth-migrations

# Publish views (optional - for email templates)
php artisan vendor:publish --provider="RaDevs\JwtAuth\Providers\JwtAuthServiceProvider" --tag=ra-jwt-auth-views

Step 3: Configure JWT Auth

Publish and configure the base JWT package:

# Publish JWT config
php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"

# Generate JWT secret key
php artisan jwt:secret

Step 4: Configure Auth Guard

Update your config/auth.php file:

<?php

return [
    'defaults' => [
        'guard' => 'api',
        'passwords' => 'users',
    ],

    'guards' => [
        'api' => [
            'driver' => 'jwt',
            'provider' => 'users',
        ],
    ],

    'providers' => [
        'users' => [
            'driver' => 'eloquent',
            'model' => App\Models\User::class,
        ],
    ],
];

Step 5: Run Migrations

Run the database migrations:

php artisan migrate

This will create the following tables:

  • password_reset_codes - Stores password reset codes
  • Adds refresh_token column to users table

🎯 Quick Start

1. Register a New User

curl -X POST http://your-app.test/api/auth/register \
  -H "Content-Type: application/json" \
  -d '{
    "email": "user@example.com",
    "name": "John",
    "last_name": "Doe",
    "phone": "+1234567890",
    "password": "SecurePass123!",
    "password_confirmation": "SecurePass123!"
  }'

Response:

{
  "success": true,
  "status": "success",
  "message": "User registered successfully",
  "data": {
    "user": {
      "id": 1,
      "name": "John",
      "email": "user@example.com"
    }
  }
}

2. Login

curl -X POST http://your-app.test/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{
    "email": "user@example.com",
    "password": "SecurePass123!"
  }'

Response:

{
  "success": true,
  "status": "success",
  "message": "The user has been successfully logged in",
  "data": {
    "user": {
      "id": 1,
      "name": "John",
      "email": "user@example.com"
    },
    "token": {
      "access_token": "eyJ0eXAiOiJKV1QiLCJhbGci...",
      "token_type": "bearer",
      "expires_in": 3600
    }
  }
}

3. Access Protected Route

curl -X GET http://your-app.test/api/auth/me \
  -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGci..." \
  -H "Accept: application/json"

4. Refresh Token

The refresh token is automatically sent as an HTTP-only cookie. To refresh:

curl -X POST http://your-app.test/api/auth/refresh \
  -H "Cookie: refresh_token=your_refresh_token" \
  -H "Accept: application/json"

📡 API Endpoints

All endpoints are prefixed with /api/auth by default (configurable).

Method Endpoint Description Auth Required Rate Limit
POST /login Authenticate user and get tokens 5/min
POST /register Register a new user 3/min
GET /me Get current authenticated user -
POST /logout Logout and clear refresh token -
POST /refresh Refresh access token via cookie 10/min
POST /forgot-password Request password reset code 3/min
POST /reset-password Reset password using code 3/min

Request/Response Examples

POST /api/auth/login

Request:

{
  "email": "user@example.com",
  "password": "password123"
}

Success Response (200):

{
  "success": true,
  "status": "success",
  "message": "The user has been successfully logged in",
  "data": {
    "user": {
      "id": 1,
      "name": "John Doe",
      "email": "user@example.com"
    },
    "token": {
      "access_token": "eyJ0eXAiOiJKV1QiLCJhbGci...",
      "token_type": "bearer",
      "expires_in": 3600
    }
  }
}

Error Response (401):

{
  "success": false,
  "status": "error",
  "message": "Invalid credentials",
  "data": {
    "error_code": "INVALID_CREDENTIALS"
  }
}
POST /api/auth/register

Request:

{
  "email": "newuser@example.com",
  "name": "Jane",
  "last_name": "Smith",
  "phone": "+1234567890",
  "password": "SecurePass123!",
  "password_confirmation": "SecurePass123!"
}

Success Response (201):

{
  "success": true,
  "status": "success",
  "message": "User registered successfully",
  "data": {
    "user": {
      "id": 2,
      "name": "Jane",
      "email": "newuser@example.com"
    }
  }
}
POST /api/auth/forgot-password

Request:

{
  "email": "user@example.com"
}

Success Response (200):

{
  "success": true,
  "status": "success",
  "message": "Password reset code has been sent to your email"
}

Note: For security, the response is the same whether the email exists or not.

POST /api/auth/reset-password

Request:

{
  "email": "user@example.com",
  "code": "ABCD1234",
  "password": "NewSecurePass123!",
  "password_confirmation": "NewSecurePass123!"
}

Success Response (200):

{
  "success": true,
  "status": "success",
  "message": "Password has been reset successfully"
}

Error Response (400):

{
  "success": false,
  "status": "error",
  "message": "Invalid or expired reset code",
  "data": {
    "error_code": "PASSWORD_RESET_CODE_INVALID"
  }
}

⚙️ Configuration

After publishing, edit config/ra-jwt-auth.php to customize the package behavior.

Route Configuration

'route' => [
    'prefix' => 'api/auth',        // API route prefix
    'middleware' => ['api'],        // Middleware groups
],

Refresh Token Cookie

'refresh_cookie' => [
    'name' => env('RA_JWT_AUTH_REFRESH_COOKIE_NAME', 'refresh_token'),
    'minutes' => env('RA_JWT_AUTH_REFRESH_COOKIE_MINUTES', 60 * 24), // 1 day
    'secure' => env('RA_JWT_AUTH_REFRESH_COOKIE_SECURE', null),     // null = auto-detect
    'http_only' => env('RA_JWT_AUTH_REFRESH_COOKIE_HTTP_ONLY', true),
    'same_site' => env('RA_JWT_AUTH_REFRESH_COOKIE_SAME_SITE', null), // 'lax'|'strict'|'none'
    'path' => env('RA_JWT_AUTH_REFRESH_COOKIE_PATH', '/'),
    'domain' => env('RA_JWT_AUTH_REFRESH_COOKIE_DOMAIN', null),
],

Custom Classes

Override default implementations:

'classes' => [
    'user_model' => App\Models\User::class,
    'user_resource' => App\Http\Resources\UserResource::class,
    'auth_repository_interface' => RaDevs\JwtAuth\Repositories\Contracts\IAuthRepository::class,
    'auth_repository' => App\Repositories\CustomAuthRepository::class,
    'user_repository_interface' => RaDevs\JwtAuth\Repositories\Contracts\IUserRepository::class,
    'user_repository' => App\Repositories\CustomUserRepository::class,
    'password_reset_service' => RaDevs\JwtAuth\Services\PasswordResetCodeService::class,
    'notification' => App\Notifications\CustomResetPasswordNotification::class,
],

Registration Fields

Customize registration validation rules:

'registration' => [
    'fields' => [
        'email' => 'required|email:rfc,dns|unique:users,email',
        'name' => 'required|string|max:255',
        'last_name' => 'required|string|max:255',
        'phone' => 'required|string|regex:/^\+\d{10,15}$/',
        'password' => 'required|confirmed|min:8',
        'password_confirmation' => 'required_with:password',
    ],
    'exclude_from_create' => [
        'password_confirmation',
    ],
],

Password Reset Settings

'password_reset' => [
    'code_length' => env('RA_JWT_AUTH_PASSWORD_RESET_CODE_LENGTH', 8),
    'code_alphabet' => env('RA_JWT_AUTH_PASSWORD_RESET_CODE_ALPHABET', 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789'),
    'max_attempts' => env('RA_JWT_AUTH_PASSWORD_RESET_MAX_ATTEMPTS', 5),
    'rate_limit_seconds' => env('RA_JWT_AUTH_PASSWORD_RESET_RATE_LIMIT_SECONDS', 60),
],

Rate Limits

Configure rate limiting per endpoint:

'rate_limits' => [
    'login' => env('RA_JWT_AUTH_RATE_LIMIT_LOGIN', 5),
    'register' => env('RA_JWT_AUTH_RATE_LIMIT_REGISTER', 3),
    'forgot_password' => env('RA_JWT_AUTH_RATE_LIMIT_FORGOT_PASSWORD', 3),
    'reset_password' => env('RA_JWT_AUTH_RATE_LIMIT_RESET_PASSWORD', 3),
    'refresh' => env('RA_JWT_AUTH_RATE_LIMIT_REFRESH', 10),
],

💡 Usage Examples

Custom User Resource

Create a custom resource to control API responses:

<?php
// app/Http/Resources/UserResource.php

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\JsonResource;

class UserResource extends JsonResource
{
    public function toArray($request): array
    {
        return [
            'id' => $this->id,
            'name' => $this->name,
            'email' => $this->email,
            'avatar' => $this->avatar_url,
            'created_at' => $this->created_at->toIso8601String(),
        ];
    }
}

Then update config/ra-jwt-auth.php:

'classes' => [
    'user_resource' => App\Http\Resources\UserResource::class,
],

Custom Repository

Override authentication logic:

<?php
// app/Repositories/CustomAuthRepository.php

namespace App\Repositories;

use RaDevs\JwtAuth\Repositories\AuthRepository;
use RaDevs\JwtAuth\Repositories\Contracts\IAuthRepository;

class CustomAuthRepository extends AuthRepository implements IAuthRepository
{
    public function login(array $credentials): array
    {
        // Add custom logic before login
        // e.g., check user status, log attempts, etc.
        
        $result = parent::login($credentials);
        
        // Add custom logic after login
        // e.g., update last login, send notification, etc.
        
        return $result;
    }
}

Custom Password Reset Notification

Create a custom email template:

<?php
// app/Notifications/CustomResetPasswordNotification.php

namespace App\Notifications;

use RaDevs\JwtAuth\Notifications\ApiResetPasswordCodeNotification;

class CustomResetPasswordNotification extends ApiResetPasswordCodeNotification
{
    public function toMail($notifiable)
    {
        return (new \Illuminate\Notifications\Messages\MailMessage)
            ->subject('Reset Your Password')
            ->view('emails.password-reset', [
                'code' => $this->code,
                'user' => $notifiable,
            ]);
    }
}

🛡️ Security Features

Rate Limiting

All endpoints are protected with configurable rate limits to prevent brute force attacks:

  • Login: 5 attempts per minute
  • Register: 3 attempts per minute
  • Password Reset: 3 attempts per minute
  • Token Refresh: 10 attempts per minute

When rate limit is exceeded, the API returns:

{
  "success": false,
  "status": "error",
  "message": "Too many attempts. Please try again later.",
  "data": {
    "error_code": "RATE_LIMIT_EXCEEDED",
    "retry_after": 60
  }
}

Security Event Logging

All authentication events are automatically logged with IP address and user agent:

  • ✅ User login (success/failure)
  • ✅ User registration
  • ✅ User logout
  • ✅ Password reset requests
  • ✅ Password reset completion

Listen to events in your EventServiceProvider:

<?php
// app/Providers/EventServiceProvider.php

use RaDevs\JwtAuth\Events\UserLoggedIn;
use RaDevs\JwtAuth\Events\UserLoginFailed;

protected $listen = [
    UserLoggedIn::class => [
        SendLoginNotification::class,
        UpdateLastLoginTimestamp::class,
    ],
    UserLoginFailed::class => [
        LogFailedAttempt::class,
    ],
];

Error Codes

Structured error responses with error codes for programmatic handling:

Error Code Description
INVALID_CREDENTIALS Wrong email/password combination
USER_NOT_FOUND User does not exist
INVALID_TOKEN Token is invalid or expired
PASSWORD_RESET_CODE_EXPIRED Reset code has expired
PASSWORD_RESET_CODE_INVALID Invalid reset code
PASSWORD_RESET_TOO_MANY_ATTEMPTS Too many code verification attempts
RATE_LIMIT_EXCEEDED Too many requests

Password Reset Security

  • 8-character codes using alphabet without confusing characters (no I, O, 0, 1)
  • Time-limited codes (configurable expiration)
  • Attempt limiting (max 5 attempts by default)
  • Rate limiting on code requests (1 request per minute)

🌐 Frontend Integration

Vue.js / React

See detailed integration examples in docs/EXAMPLES.md for:

  • Vue.js with Pinia
  • React with Context API
  • Axios interceptors
  • Token refresh strategies
  • Error handling

Quick Example (Axios)

import axios from 'axios';

const api = axios.create({
  baseURL: 'https://api.example.com/api',
  withCredentials: true, // Important for refresh token cookies
});

// Add access token to requests
api.interceptors.request.use((config) => {
  const token = localStorage.getItem('access_token');
  if (token) {
    config.headers.Authorization = `Bearer ${token}`;
  }
  return config;
});

// Handle token refresh on 401
api.interceptors.response.use(
  (response) => response,
  async (error) => {
    if (error.response?.status === 401 && !error.config._retry) {
      error.config._retry = true;
      
      try {
        const { data } = await axios.post('/api/auth/refresh', {}, { withCredentials: true });
        localStorage.setItem('access_token', data.data.token.access_token);
        error.config.headers.Authorization = `Bearer ${data.data.token.access_token}`;
        return api(error.config);
      } catch {
        localStorage.removeItem('access_token');
        window.location.href = '/login';
      }
    }
    return Promise.reject(error);
  }
);

🧪 Testing

Run Tests

# Run all tests
composer test

# Run without coverage
vendor/bin/phpunit --no-coverage

# Run specific test file
vendor/bin/phpunit tests/Feature/AuthControllerTest.php

# Run with coverage report
composer test-coverage

Test Coverage

The package includes a comprehensive test suite:

  • Unit tests for services (7/7 passing)
  • Feature tests for API endpoints (14/14 passing)
  • Rate limiting tests (2/2 passing)
  • Password reset service tests (7/7 passing)

Current Status: 21/21 passing (100%)

✅ All tests are passing successfully! See Testing Guide for details.

📚 Documentation

🔧 Customization

Override User Model

Ensure your User model implements JWTSubject:

<?php
// app/Models/User.php

use Tymon\JWTAuth\Contracts\JWTSubject;

class User extends Authenticatable implements JWTSubject
{
    public function getJWTIdentifier()
    {
        return $this->getKey();
    }

    public function getJWTCustomClaims()
    {
        return [];
    }
}

Custom Validation Rules

Extend the request classes to add custom validation:

<?php
// app/Http/Requests/CustomRegisterRequest.php

namespace App\Http\Requests;

use RaDevs\JwtAuth\Http\Requests\Auth\RegisterRequest;

class CustomRegisterRequest extends RegisterRequest
{
    public function rules(): array
    {
        $rules = parent::rules();
        
        // Add custom rules
        $rules['email'] .= '|unique:users,email,deleted_at,NULL';
        $rules['terms'] = 'required|accepted';
        
        return $rules;
    }
}

Custom Routes

Override routes by publishing and editing routes/api.php, or add middleware:

// In your RouteServiceProvider or routes file
Route::prefix('api/auth')
    ->middleware(['api', 'throttle:60,1'])
    ->group(function () {
        // Your custom routes
    });

🚧 Development

Local Development Setup

For local development, add the package as a path repository in composer.json:

{
  "repositories": [
    {
      "type": "path",
      "url": "../ra-devs-jwt-auth",
      "options": {
        "symlink": true
      }
    }
  ]
}

Then require it:

composer require ra-devs/jwt-auth:"*@dev"

Project Structure

src/
├── Events/              # Event classes
├── Exceptions/          # Custom exceptions
├── Http/
│   ├── Controllers/     # Controllers
│   ├── Requests/        # Form requests
│   └── Resources/       # API resources
├── Listeners/           # Event listeners
├── Models/              # Eloquent models
├── Providers/           # Service providers
├── Repositories/        # Repository classes
│   └── Contracts/       # Repository interfaces
└── Services/            # Business logic services

🤝 Contributing

Contributions are welcome! Please read our Contributing Guidelines before submitting a pull request.

Quick Contribution Steps

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Make your changes
  4. Add/update tests
  5. Update documentation
  6. Commit your changes (git commit -m 'Add amazing feature')
  7. Push to the branch (git push origin feature/amazing-feature)
  8. Open a Pull Request

📄 License

MIT © RA Devs

Made with ❤️ by RA Devs

Report Bug · Request Feature · Documentation

统计信息

  • 总下载量: 424
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 1
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2025-09-10

承接程序开发

PHP开发

VUE

Vue开发

前端开发

小程序开发

公众号开发

系统定制

数据库设计

云部署

网站建设

安全加固