物联网设备认证服务

# 物联网设备认证服务

# 概述

设备认证服务是物联网安全体系的核心组件,负责验证设备身份、管理访问权限、防范安全威胁。本文档详细介绍设备认证服务的设计原理、实现方案和安全机制。

# 认证架构

设备认证服务
├── 身份认证
│   ├── 设备证书认证
│   ├── 密钥签名认证
│   └── 动态令牌认证
├── 权限管理
│   ├── 访问控制列表
│   ├── 角色权限管理
│   └── 资源授权
├── 安全防护
│   ├── 防重放攻击
│   ├── 防暴力破解
│   └── 异常检测
└── 会话管理
    ├── 令牌生成
    ├── 会话维持
    └── 令牌刷新

# 认证方式

# 1. 基于签名的认证

@Service
public class SignatureAuthenticationService {
    
    @Autowired
    private DeviceManagementService deviceManagementService;
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    /**
     * 签名认证
     */
    public AuthenticationResult authenticateBySignature(SignatureAuthRequest request) {
        String deviceId = request.getDeviceId();
        String signature = request.getSignature();
        String timestamp = request.getTimestamp();
        String nonce = request.getNonce();
        
        try {
            // 1. 基础参数验证
            validateBasicParams(deviceId, signature, timestamp, nonce);
            
            // 2. 时间戳验证(防重放攻击)
            validateTimestamp(timestamp);
            
            // 3. 随机数验证(防重放攻击)
            validateNonce(deviceId, nonce);
            
            // 4. 获取设备信息
            IoTDevice device = getAndValidateDevice(deviceId);
            
            // 5. 签名验证
            validateSignature(device, signature, timestamp, nonce);
            
            // 6. 生成访问令牌
            String accessToken = generateAccessToken(deviceId);
            
            // 7. 缓存认证信息
            cacheAuthenticationInfo(deviceId, accessToken);
            
            // 8. 记录认证日志
            recordAuthenticationLog(deviceId, true, "签名认证成功");
            
            return AuthenticationResult.success(accessToken, "认证成功");
            
        } catch (AuthenticationException e) {
            recordAuthenticationLog(deviceId, false, e.getMessage());
            return AuthenticationResult.failure(e.getMessage());
        }
    }
    
    /**
     * 验证基础参数
     */
    private void validateBasicParams(String deviceId, String signature, String timestamp, String nonce) {
        if (StringUtils.isAnyBlank(deviceId, signature, timestamp, nonce)) {
            throw new AuthenticationException("认证参数不完整");
        }
        
        if (deviceId.length() > 100 || signature.length() > 256) {
            throw new AuthenticationException("参数长度超限");
        }
    }
    
    /**
     * 验证时间戳
     */
    private void validateTimestamp(String timestamp) {
        try {
            long ts = Long.parseLong(timestamp);
            long currentTime = System.currentTimeMillis();
            long diff = Math.abs(currentTime - ts);
            
            // 允许5分钟的时间偏差
            if (diff > 5 * 60 * 1000) {
                throw new AuthenticationException("时间戳无效");
            }
        } catch (NumberFormatException e) {
            throw new AuthenticationException("时间戳格式错误");
        }
    }
    
    /**
     * 验证随机数(防重放攻击)
     */
    private void validateNonce(String deviceId, String nonce) {
        String nonceKey = "auth:nonce:" + deviceId + ":" + nonce;
        
        // 检查随机数是否已使用
        if (redisTemplate.hasKey(nonceKey)) {
            throw new AuthenticationException("随机数已使用");
        }
        
        // 缓存随机数,防止重复使用
        redisTemplate.opsForValue().set(nonceKey, "used", Duration.ofMinutes(10));
    }
    
    /**
     * 获取并验证设备
     */
    private IoTDevice getAndValidateDevice(String deviceId) {
        IoTDevice device = deviceManagementService.getDeviceById(deviceId);
        if (device == null) {
            throw new AuthenticationException("设备不存在");
        }
        
        if (device.getStatus() == DeviceStatus.DISABLED) {
            throw new AuthenticationException("设备已被禁用");
        }
        
        if (device.getStatus() == DeviceStatus.INACTIVE) {
            throw new AuthenticationException("设备未激活");
        }
        
        return device;
    }
    
    /**
     * 验证签名
     */
    private void validateSignature(IoTDevice device, String signature, String timestamp, String nonce) {
        String expectedSignature = calculateSignature(
            device.getDeviceId(),
            device.getDeviceSecret(),
            timestamp,
            nonce
        );
        
        if (!signature.equals(expectedSignature)) {
            throw new AuthenticationException("签名验证失败");
        }
    }
    
    /**
     * 计算签名
     */
    private String calculateSignature(String deviceId, String deviceSecret, String timestamp, String nonce) {
        // 签名算法: SHA256(deviceId + deviceSecret + timestamp + nonce)
        String data = deviceId + deviceSecret + timestamp + nonce;
        return DigestUtils.sha256Hex(data);
    }
}

# 2. 基于证书的认证

@Service
public class CertificateAuthenticationService {
    
    @Autowired
    private DeviceCertificateRepository certificateRepository;
    
    @Autowired
    private CertificateValidator certificateValidator;
    
    /**
     * 证书认证
     */
    public AuthenticationResult authenticateByCertificate(CertificateAuthRequest request) {
        String deviceId = request.getDeviceId();
        String certificateContent = request.getCertificate();
        
        try {
            // 1. 解析证书
            X509Certificate certificate = parseCertificate(certificateContent);
            
            // 2. 验证证书有效性
            validateCertificate(certificate);
            
            // 3. 验证证书与设备的绑定关系
            validateDeviceCertificateBinding(deviceId, certificate);
            
            // 4. 验证证书链
            validateCertificateChain(certificate);
            
            // 5. 生成访问令牌
            String accessToken = generateAccessToken(deviceId);
            
            // 6. 缓存认证信息
            cacheAuthenticationInfo(deviceId, accessToken);
            
            return AuthenticationResult.success(accessToken, "证书认证成功");
            
        } catch (Exception e) {
            log.error("证书认证失败, deviceId: {}", deviceId, e);
            return AuthenticationResult.failure("证书认证失败: " + e.getMessage());
        }
    }
    
    /**
     * 解析证书
     */
    private X509Certificate parseCertificate(String certificateContent) throws CertificateException {
        byte[] certBytes = Base64.getDecoder().decode(certificateContent);
        CertificateFactory factory = CertificateFactory.getInstance("X.509");
        return (X509Certificate) factory.generateCertificate(new ByteArrayInputStream(certBytes));
    }
    
    /**
     * 验证证书有效性
     */
    private void validateCertificate(X509Certificate certificate) throws CertificateException {
        // 检查证书是否过期
        certificate.checkValidity();
        
        // 验证证书签名
        certificateValidator.validateSignature(certificate);
        
        // 检查证书是否被吊销
        if (certificateValidator.isRevoked(certificate)) {
            throw new CertificateException("证书已被吊销");
        }
    }
    
    /**
     * 验证设备证书绑定关系
     */
    private void validateDeviceCertificateBinding(String deviceId, X509Certificate certificate) {
        DeviceCertificate deviceCert = certificateRepository.findByDeviceId(deviceId)
            .orElseThrow(() -> new AuthenticationException("设备证书不存在"));
        
        String certFingerprint = calculateCertificateFingerprint(certificate);
        if (!certFingerprint.equals(deviceCert.getCertificateFingerprint())) {
            throw new AuthenticationException("证书与设备不匹配");
        }
    }
    
    /**
     * 计算证书指纹
     */
    private String calculateCertificateFingerprint(X509Certificate certificate) {
        try {
            byte[] encoded = certificate.getEncoded();
            return DigestUtils.sha256Hex(encoded);
        } catch (CertificateEncodingException e) {
            throw new RuntimeException("计算证书指纹失败", e);
        }
    }
}

# 3. 动态令牌认证

@Service
public class TokenAuthenticationService {
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    @Autowired
    private JwtTokenProvider jwtTokenProvider;
    
    /**
     * 令牌认证
     */
    public AuthenticationResult authenticateByToken(TokenAuthRequest request) {
        String deviceId = request.getDeviceId();
        String token = request.getToken();
        
        try {
            // 1. 验证令牌格式
            validateTokenFormat(token);
            
            // 2. 验证令牌有效性
            Claims claims = jwtTokenProvider.validateToken(token);
            
            // 3. 验证设备ID匹配
            String tokenDeviceId = claims.getSubject();
            if (!deviceId.equals(tokenDeviceId)) {
                throw new AuthenticationException("设备ID不匹配");
            }
            
            // 4. 检查令牌是否在黑名单中
            if (isTokenBlacklisted(token)) {
                throw new AuthenticationException("令牌已失效");
            }
            
            // 5. 刷新令牌(如果需要)
            String newToken = refreshTokenIfNeeded(token, claims);
            
            return AuthenticationResult.success(newToken != null ? newToken : token, "令牌认证成功");
            
        } catch (Exception e) {
            log.error("令牌认证失败, deviceId: {}", deviceId, e);
            return AuthenticationResult.failure("令牌认证失败: " + e.getMessage());
        }
    }
    
    /**
     * 验证令牌格式
     */
    private void validateTokenFormat(String token) {
        if (StringUtils.isBlank(token)) {
            throw new AuthenticationException("令牌不能为空");
        }
        
        if (!token.startsWith("Bearer ")) {
            throw new AuthenticationException("令牌格式错误");
        }
    }
    
    /**
     * 检查令牌黑名单
     */
    private boolean isTokenBlacklisted(String token) {
        String blacklistKey = "auth:blacklist:" + DigestUtils.sha256Hex(token);
        return redisTemplate.hasKey(blacklistKey);
    }
    
    /**
     * 刷新令牌(如果需要)
     */
    private String refreshTokenIfNeeded(String token, Claims claims) {
        Date expiration = claims.getExpiration();
        Date now = new Date();
        
        // 如果令牌在30分钟内过期,则刷新
        long timeToExpire = expiration.getTime() - now.getTime();
        if (timeToExpire < 30 * 60 * 1000) {
            String deviceId = claims.getSubject();
            return generateAccessToken(deviceId);
        }
        
        return null;
    }
}

# 权限管理

# 访问控制服务

@Service
public class AccessControlService {
    
    @Autowired
    private DevicePermissionRepository permissionRepository;
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    /**
     * 检查设备权限
     */
    public boolean checkPermission(String deviceId, String resource, String action) {
        // 1. 从缓存获取权限信息
        Set<String> permissions = getCachedPermissions(deviceId);
        
        if (permissions == null) {
            // 2. 从数据库加载权限
            permissions = loadDevicePermissions(deviceId);
            
            // 3. 缓存权限信息
            cachePermissions(deviceId, permissions);
        }
        
        // 4. 检查具体权限
        String permission = resource + ":" + action;
        return permissions.contains(permission) || permissions.contains(resource + ":*");
    }
    
    /**
     * 获取缓存的权限信息
     */
    @SuppressWarnings("unchecked")
    private Set<String> getCachedPermissions(String deviceId) {
        String cacheKey = "auth:permissions:" + deviceId;
        return (Set<String>) redisTemplate.opsForValue().get(cacheKey);
    }
    
    /**
     * 加载设备权限
     */
    private Set<String> loadDevicePermissions(String deviceId) {
        List<DevicePermission> permissions = permissionRepository.findByDeviceId(deviceId);
        return permissions.stream()
            .map(p -> p.getResource() + ":" + p.getAction())
            .collect(Collectors.toSet());
    }
    
    /**
     * 缓存权限信息
     */
    private void cachePermissions(String deviceId, Set<String> permissions) {
        String cacheKey = "auth:permissions:" + deviceId;
        redisTemplate.opsForValue().set(cacheKey, permissions, Duration.ofHours(1));
    }
    
    /**
     * 批量权限检查
     */
    public Map<String, Boolean> batchCheckPermissions(String deviceId, List<PermissionRequest> requests) {
        Set<String> permissions = getCachedPermissions(deviceId);
        if (permissions == null) {
            permissions = loadDevicePermissions(deviceId);
            cachePermissions(deviceId, permissions);
        }
        
        Map<String, Boolean> results = new HashMap<>();
        for (PermissionRequest request : requests) {
            String permission = request.getResource() + ":" + request.getAction();
            boolean hasPermission = permissions.contains(permission) || 
                                  permissions.contains(request.getResource() + ":*");
            results.put(permission, hasPermission);
        }
        
        return results;
    }
}

# 安全防护

# 防暴力破解

@Component
public class BruteForceProtectionService {
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    private static final int MAX_ATTEMPTS = 5;
    private static final int LOCKOUT_DURATION_MINUTES = 30;
    
    /**
     * 检查是否被锁定
     */
    public boolean isLocked(String deviceId) {
        String lockKey = "auth:lock:" + deviceId;
        return redisTemplate.hasKey(lockKey);
    }
    
    /**
     * 记录认证失败
     */
    public void recordFailedAttempt(String deviceId) {
        String attemptKey = "auth:attempts:" + deviceId;
        
        // 增加失败次数
        Long attempts = redisTemplate.opsForValue().increment(attemptKey);
        
        if (attempts == 1) {
            // 设置过期时间
            redisTemplate.expire(attemptKey, Duration.ofMinutes(LOCKOUT_DURATION_MINUTES));
        }
        
        // 如果失败次数达到阈值,锁定设备
        if (attempts >= MAX_ATTEMPTS) {
            lockDevice(deviceId);
        }
    }
    
    /**
     * 锁定设备
     */
    private void lockDevice(String deviceId) {
        String lockKey = "auth:lock:" + deviceId;
        redisTemplate.opsForValue().set(lockKey, "locked", Duration.ofMinutes(LOCKOUT_DURATION_MINUTES));
        
        log.warn("设备因多次认证失败被锁定, deviceId: {}", deviceId);
        
        // 发送告警
        sendBruteForceAlert(deviceId);
    }
    
    /**
     * 清除失败记录
     */
    public void clearFailedAttempts(String deviceId) {
        String attemptKey = "auth:attempts:" + deviceId;
        redisTemplate.delete(attemptKey);
    }
    
    /**
     * 发送暴力破解告警
     */
    private void sendBruteForceAlert(String deviceId) {
        BruteForceAlert alert = new BruteForceAlert();
        alert.setDeviceId(deviceId);
        alert.setAttempts(MAX_ATTEMPTS);
        alert.setLockoutTime(LocalDateTime.now());
        alert.setAlertLevel(AlertLevel.HIGH);
        
        // 发送到告警队列
        rabbitTemplate.convertAndSend("iot.alert.exchange", "auth.bruteforce", alert);
    }
}

# 异常检测

@Component
public class AuthenticationAnomalyDetector {
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    /**
     * 检测认证异常
     */
    public void detectAnomalies(String deviceId, String clientIp, String userAgent) {
        // 1. 检测异常IP
        detectAbnormalIP(deviceId, clientIp);
        
        // 2. 检测异常用户代理
        detectAbnormalUserAgent(deviceId, userAgent);
        
        // 3. 检测异常时间
        detectAbnormalTime(deviceId);
        
        // 4. 检测频繁认证
        detectFrequentAuthentication(deviceId);
    }
    
    /**
     * 检测异常IP
     */
    private void detectAbnormalIP(String deviceId, String clientIp) {
        String ipHistoryKey = "auth:ip_history:" + deviceId;
        Set<String> historicalIPs = redisTemplate.opsForSet().members(ipHistoryKey);
        
        if (historicalIPs != null && !historicalIPs.isEmpty() && !historicalIPs.contains(clientIp)) {
            // 新IP认证,发送告警
            sendAnomalyAlert(deviceId, "异常IP认证", "设备从新IP地址认证: " + clientIp);
        }
        
        // 记录IP
        redisTemplate.opsForSet().add(ipHistoryKey, clientIp);
        redisTemplate.expire(ipHistoryKey, Duration.ofDays(30));
    }
    
    /**
     * 检测频繁认证
     */
    private void detectFrequentAuthentication(String deviceId) {
        String frequencyKey = "auth:frequency:" + deviceId;
        Long count = redisTemplate.opsForValue().increment(frequencyKey);
        
        if (count == 1) {
            redisTemplate.expire(frequencyKey, Duration.ofMinutes(5));
        }
        
        // 5分钟内认证超过10次视为异常
        if (count > 10) {
            sendAnomalyAlert(deviceId, "频繁认证", "5分钟内认证次数: " + count);
        }
    }
    
    /**
     * 发送异常告警
     */
    private void sendAnomalyAlert(String deviceId, String anomalyType, String description) {
        AuthenticationAnomalyAlert alert = new AuthenticationAnomalyAlert();
        alert.setDeviceId(deviceId);
        alert.setAnomalyType(anomalyType);
        alert.setDescription(description);
        alert.setDetectTime(LocalDateTime.now());
        alert.setAlertLevel(AlertLevel.MEDIUM);
        
        rabbitTemplate.convertAndSend("iot.alert.exchange", "auth.anomaly", alert);
    }
}

# 会话管理

# JWT令牌提供者

@Component
public class JwtTokenProvider {
    
    @Value("${iot.auth.jwt.secret}")
    private String jwtSecret;
    
    @Value("${iot.auth.jwt.expiration:3600000}") // 默认1小时
    private long jwtExpiration;
    
    /**
     * 生成访问令牌
     */
    public String generateAccessToken(String deviceId) {
        Date now = new Date();
        Date expiryDate = new Date(now.getTime() + jwtExpiration);
        
        return Jwts.builder()
            .setSubject(deviceId)
            .setIssuedAt(now)
            .setExpiration(expiryDate)
            .signWith(SignatureAlgorithm.HS512, jwtSecret)
            .compact();
    }
    
    /**
     * 生成刷新令牌
     */
    public String generateRefreshToken(String deviceId) {
        Date now = new Date();
        Date expiryDate = new Date(now.getTime() + jwtExpiration * 24); // 24小时
        
        return Jwts.builder()
            .setSubject(deviceId)
            .setIssuedAt(now)
            .setExpiration(expiryDate)
            .claim("type", "refresh")
            .signWith(SignatureAlgorithm.HS512, jwtSecret)
            .compact();
    }
    
    /**
     * 验证令牌
     */
    public Claims validateToken(String token) {
        try {
            return Jwts.parser()
                .setSigningKey(jwtSecret)
                .parseClaimsJws(token)
                .getBody();
        } catch (JwtException | IllegalArgumentException e) {
            throw new AuthenticationException("无效的令牌", e);
        }
    }
    
    /**
     * 从令牌获取设备ID
     */
    public String getDeviceIdFromToken(String token) {
        Claims claims = validateToken(token);
        return claims.getSubject();
    }
    
    /**
     * 检查令牌是否即将过期
     */
    public boolean isTokenExpiringSoon(String token) {
        try {
            Claims claims = validateToken(token);
            Date expiration = claims.getExpiration();
            Date now = new Date();
            
            // 如果在30分钟内过期,返回true
            return (expiration.getTime() - now.getTime()) < 30 * 60 * 1000;
        } catch (Exception e) {
            return true;
        }
    }
}

# 数据库设计

# 设备权限表

CREATE TABLE `iot_device_permission` (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `device_id` varchar(100) NOT NULL COMMENT '设备ID',
  `resource` varchar(100) NOT NULL COMMENT '资源',
  `action` varchar(50) NOT NULL COMMENT '操作',
  `granted` tinyint(1) NOT NULL DEFAULT '1' COMMENT '是否授权',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_device_resource_action` (`device_id`, `resource`, `action`),
  KEY `idx_device_id` (`device_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='设备权限表';

# 设备证书表

CREATE TABLE `iot_device_certificate` (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `device_id` varchar(100) NOT NULL COMMENT '设备ID',
  `certificate_content` text NOT NULL COMMENT '证书内容',
  `certificate_fingerprint` varchar(64) NOT NULL COMMENT '证书指纹',
  `issuer` varchar(500) NOT NULL COMMENT '颁发者',
  `subject` varchar(500) NOT NULL COMMENT '主题',
  `valid_from` datetime NOT NULL COMMENT '有效期开始',
  `valid_to` datetime NOT NULL COMMENT '有效期结束',
  `status` varchar(20) NOT NULL DEFAULT 'ACTIVE' COMMENT '状态',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_device_id` (`device_id`),
  UNIQUE KEY `uk_certificate_fingerprint` (`certificate_fingerprint`),
  KEY `idx_valid_to` (`valid_to`),
  KEY `idx_status` (`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='设备证书表';

# 认证日志表

CREATE TABLE `iot_authentication_log` (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `device_id` varchar(100) NOT NULL COMMENT '设备ID',
  `auth_type` varchar(20) NOT NULL COMMENT '认证类型',
  `client_ip` varchar(50) DEFAULT NULL COMMENT '客户端IP',
  `user_agent` varchar(500) DEFAULT NULL COMMENT '用户代理',
  `success` tinyint(1) NOT NULL COMMENT '是否成功',
  `failure_reason` varchar(500) DEFAULT NULL COMMENT '失败原因',
  `auth_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '认证时间',
  PRIMARY KEY (`id`),
  KEY `idx_device_id_time` (`device_id`, `auth_time`),
  KEY `idx_success` (`success`),
  KEY `idx_auth_time` (`auth_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='认证日志表'
PARTITION BY RANGE (TO_DAYS(auth_time)) (
    PARTITION p202401 VALUES LESS THAN (TO_DAYS('2024-02-01')),
    PARTITION p202402 VALUES LESS THAN (TO_DAYS('2024-03-01')),
    PARTITION p202403 VALUES LESS THAN (TO_DAYS('2024-04-01')),
    PARTITION p_future VALUES LESS THAN MAXVALUE
);

# 性能优化

# 认证缓存策略

@Component
public class AuthenticationCacheManager {
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    /**
     * 缓存认证结果
     */
    public void cacheAuthenticationResult(String deviceId, String token, long expireSeconds) {
        String cacheKey = "auth:token:" + deviceId;
        redisTemplate.opsForValue().set(cacheKey, token, Duration.ofSeconds(expireSeconds));
    }
    
    /**
     * 获取缓存的认证结果
     */
    public String getCachedToken(String deviceId) {
        String cacheKey = "auth:token:" + deviceId;
        return (String) redisTemplate.opsForValue().get(cacheKey);
    }
    
    /**
     * 批量缓存设备权限
     */
    public void batchCachePermissions(Map<String, Set<String>> devicePermissions) {
        Map<String, Set<String>> cacheMap = devicePermissions.entrySet().stream()
            .collect(Collectors.toMap(
                entry -> "auth:permissions:" + entry.getKey(),
                Map.Entry::getValue
            ));
        
        // 使用Pipeline批量设置
        redisTemplate.executePipelined((RedisCallback<Object>) connection -> {
            cacheMap.forEach((key, permissions) -> {
                connection.set(key.getBytes(), SerializationUtils.serialize(permissions));
                connection.expire(key.getBytes(), 3600); // 1小时过期
            });
            return null;
        });
    }
}

# 监控指标

# 认证监控

@Component
public class AuthenticationMetrics {
    
    private final MeterRegistry meterRegistry;
    private final Counter authSuccessCounter;
    private final Counter authFailureCounter;
    private final Timer authDurationTimer;
    private final Gauge activeTokensGauge;
    
    public AuthenticationMetrics(MeterRegistry meterRegistry, RedisTemplate<String, Object> redisTemplate) {
        this.meterRegistry = meterRegistry;
        
        this.authSuccessCounter = Counter.builder("iot.auth.success")
            .description("认证成功次数")
            .register(meterRegistry);
        
        this.authFailureCounter = Counter.builder("iot.auth.failure")
            .description("认证失败次数")
            .register(meterRegistry);
        
        this.authDurationTimer = Timer.builder("iot.auth.duration")
            .description("认证耗时")
            .register(meterRegistry);
        
        this.activeTokensGauge = Gauge.builder("iot.auth.active_tokens")
            .description("活跃令牌数量")
            .register(meterRegistry, this, metrics -> {
                Set<String> keys = redisTemplate.keys("auth:token:*");
                return keys != null ? keys.size() : 0;
            });
    }
    
    public void incrementAuthSuccess() {
        authSuccessCounter.increment();
    }
    
    public void incrementAuthFailure() {
        authFailureCounter.increment();
    }
    
    public Timer.Sample startAuthTimer() {
        return Timer.start(meterRegistry);
    }
}

# 总结

设备认证服务是物联网安全的第一道防线,通过多种认证方式、完善的权限管理、强大的安全防护机制,确保只有合法的设备能够接入系统。合理的缓存策略和监控机制保证了认证服务的高性能和高可用性。