Laravel 中实现设备认证的几种方法
在物联网系统中,设备认证是确保安全通信的关键环节。以下是几种在 Laravel 中实现设备认证的方法:
1. API Token 认证 (简单方案)
创建设备时生成 Token
// 在 Device 模型中
use Illuminate\Support\Str;
public static function boot()
{
parent::boot();
static::creating(function ($device) {
$device->api_token = Str::random(60);
});
}
验证中间件
php artisan make:middleware AuthenticateDevice
namespace App\Http\Middleware;
use Closure;
use App\Models\Device;
class AuthenticateDevice
{
public function handle($request, Closure $next)
{
$token = $request->bearerToken() ?? $request->input('api_token');
if (!$token || !Device::where('api_token', $token)->exists()) {
return response()->json(['error' => 'Unauthorized'], 401);
}
return $next($request);
}
}
注册中间件
在 app/Http/Kernel.php
中:
protected $routeMiddleware = [
// ...
'device.auth' => \App\Http\Middleware\AuthenticateDevice::class,
];
使用中间件保护路由
Route::middleware('device.auth')->group(function () {
Route::post('/update', [DeviceController::class, 'update']);
// 其他需要认证的路由
});
2. Laravel Sanctum (推荐方案)
安装 Sanctum
composer require laravel/sanctum
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
php artisan migrate
配置设备模型
use Laravel\Sanctum\HasApiTokens;
class Device extends Model
{
use HasApiTokens;
// ...
}
创建设备并生成 Token
public function register(Request $request)
{
$device = Device::create($request->validated());
$token = $device->createToken('device-token')->plainTextToken;
return response()->json([
'device' => $device,
'token' => $token
]);
}
认证请求
设备需要在请求头中添加:
Authorization: Bearer {token}
3. JWT 认证 (适合分布式系统)
安装 jwt-auth
composer require tymon/jwt-auth
php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"
php artisan jwt:secret
配置设备模型
use Tymon\JWTAuth\Contracts\JWTSubject;
class Device extends Model implements JWTSubject
{
public function getJWTIdentifier()
{
return $this->getKey();
}
public function getJWTCustomClaims()
{
return [];
}
}
创建认证控制器
use Tymon\JWTAuth\Facades\JWTAuth;
class DeviceAuthController extends Controller
{
public function login(Request $request)
{
$credentials = $request->only('device_id', 'password');
if (!$token = JWTAuth::attempt($credentials)) {
return response()->json(['error' => 'Unauthorized'], 401);
}
return response()->json([
'access_token' => $token,
'token_type' => 'bearer',
'expires_in' => auth()->factory()->getTTL() * 60
]);
}
}
保护路由
Route::middleware('auth:api')->group(function () {
// 需要认证的路由
});
4. 双向SSL认证 (高安全性要求)
生成证书
# 生成CA证书
openssl genrsa -out ca.key 2048
openssl req -new -x509 -days 365 -key ca.key -out ca.crt
# 生成设备证书
openssl genrsa -out device.key 2048
openssl req -new -key device.key -out device.csr
openssl x509 -req -days 365 -in device.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out device.crt
Laravel 配置
在 config/nginx/ssl.conf
中添加:
ssl_client_certificate /path/to/ca.crt;
ssl_verify_client on;
中间件验证
public function handle($request, Closure $next)
{
if (!$request->hasValidSignature()) {
abort(401, 'Invalid client certificate');
}
$certificate = $request->server('SSL_CLIENT_CERT');
$deviceId = $this->extractDeviceIdFromCert($certificate);
if (!Device::where('id', $deviceId)->exists()) {
abort(403, 'Device not registered');
}
return $next($request);
}
最佳实践建议
- 短期令牌:对于高安全要求的系统,使用短期有效的JWT或OAuth令牌
- 设备指纹:结合设备唯一标识(如MAC地址)进行双重验证
- 速率限制:防止暴力破解
Route::middleware(['throttle:10,1'])->group(...);
- 令牌刷新:实现令牌刷新机制,避免长期使用同一令牌
- 日志记录:记录所有设备认证尝试,便于安全审计
选择哪种方案取决于你的具体需求:
- 简单项目:API Token 或 Sanctum
- 分布式系统:JWT
- 高安全性要求:双向SSL + 令牌认证