155 lines
3.6 KiB
PHP
155 lines
3.6 KiB
PHP
<?php
|
|
|
|
namespace App\Models;
|
|
|
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|
use Illuminate\Database\Eloquent\Model;
|
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
|
|
|
class UserDevice extends Model
|
|
{
|
|
use HasFactory;
|
|
|
|
protected $fillable = [
|
|
'user_id',
|
|
'device_hash',
|
|
'device_name',
|
|
'device_type',
|
|
'os',
|
|
'browser',
|
|
'ip',
|
|
'location',
|
|
'first_login_at',
|
|
'last_login_at',
|
|
'is_trusted',
|
|
'trusted_at',
|
|
];
|
|
|
|
protected $casts = [
|
|
'is_trusted' => 'boolean',
|
|
'first_login_at' => 'datetime',
|
|
'last_login_at' => 'datetime',
|
|
'trusted_at' => 'datetime',
|
|
];
|
|
|
|
/**
|
|
* 用户关联
|
|
*/
|
|
public function user(): BelongsTo
|
|
{
|
|
return $this->belongsTo(User::class);
|
|
}
|
|
|
|
/**
|
|
* 判断是否授信
|
|
*/
|
|
public function isTrusted(): bool
|
|
{
|
|
return $this->is_trusted;
|
|
}
|
|
|
|
/**
|
|
* 授信
|
|
*/
|
|
public function trust(): void
|
|
{
|
|
$this->update([
|
|
'is_trusted' => true,
|
|
'trusted_at' => now(),
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* 取消授信
|
|
*/
|
|
public function revoke(): void
|
|
{
|
|
$this->update([
|
|
'is_trusted' => false,
|
|
'trusted_at' => null,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* 更新登录信息
|
|
*/
|
|
public function recordLogin(): void
|
|
{
|
|
if (!$this->first_login_at) {
|
|
$this->update(['first_login_at' => now()]);
|
|
}
|
|
$this->update(['last_login_at' => now()]);
|
|
}
|
|
|
|
/**
|
|
* 通过设备哈希查找
|
|
*/
|
|
public static function findByHash(int $userId, string $hash): ?self
|
|
{
|
|
return static::where('user_id', $userId)
|
|
->where('device_hash', $hash)
|
|
->first();
|
|
}
|
|
|
|
/**
|
|
* 生成设备哈希
|
|
*/
|
|
public static function generateHash(string $userAgent, string $ip): string
|
|
{
|
|
return hash('sha256', $userAgent . $ip . config('app.key'));
|
|
}
|
|
|
|
/**
|
|
* 解析设备信息
|
|
*/
|
|
public static function parseDeviceInfo(string $userAgent): array
|
|
{
|
|
$deviceType = 'desktop';
|
|
$os = 'Unknown';
|
|
$browser = 'Unknown';
|
|
|
|
// 检测设备类型
|
|
if (preg_match('/mobile|android|iphone|ipad|ipod/i', $userAgent)) {
|
|
if (preg_match('/ipad/i', $userAgent)) {
|
|
$deviceType = 'tablet';
|
|
} else {
|
|
$deviceType = 'mobile';
|
|
}
|
|
}
|
|
|
|
// 检测操作系统
|
|
if (preg_match('/windows nt 10/i', $userAgent)) {
|
|
$os = 'Windows 10';
|
|
} elseif (preg_match('/windows nt 6.3/i', $userAgent)) {
|
|
$os = 'Windows 8.1';
|
|
} elseif (preg_match('/mac os x/i', $userAgent)) {
|
|
$os = 'macOS';
|
|
} elseif (preg_match('/linux/i', $userAgent)) {
|
|
$os = 'Linux';
|
|
} elseif (preg_match('/android/i', $userAgent)) {
|
|
$os = 'Android';
|
|
} elseif (preg_match('/iphone|ipad|ipod/i', $userAgent)) {
|
|
$os = 'iOS';
|
|
}
|
|
|
|
// 检测浏览器
|
|
if (preg_match('/edg/i', $userAgent)) {
|
|
$browser = 'Edge';
|
|
} elseif (preg_match('/chrome/i', $userAgent)) {
|
|
$browser = 'Chrome';
|
|
} elseif (preg_match('/firefox/i', $userAgent)) {
|
|
$browser = 'Firefox';
|
|
} elseif (preg_match('/safari/i', $userAgent)) {
|
|
$browser = 'Safari';
|
|
} elseif (preg_match('/ie|trident/i', $userAgent)) {
|
|
$browser = 'IE';
|
|
}
|
|
|
|
return [
|
|
'device_type' => $deviceType,
|
|
'os' => $os,
|
|
'browser' => $browser,
|
|
];
|
|
}
|
|
}
|