liujie
2026-09-21 20051550f01227ecebbe0bf064e188dd242f58f2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package com.ruoyi.web.integration.dahua;
 
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.system.utils.DoorDeviceCredentialCrypto;
 
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Date;
 
/**
 * 仅用于实体门禁联调:临时下发测试人员和人脸,并在 finally 中立即撤权。
 */
public final class DahuaGrantProbe {
 
    private static final String TEST_USER_ID = "CODEX_TEST_20260810";
    private static final String TEST_USER_NAME = "门禁联调测试";
    private static final long ONE_MINUTE_MILLIS = 60_000L;
    private static final int DEVICE_FACE_IMAGE_LIMIT = 200 * 1024;
 
    private DahuaGrantProbe() {
    }
 
    public static void main(String[] args) throws Exception {
        if (args.length != 5) {
            throw new IllegalArgumentException("参数:原生库目录、设备地址、用户名、profile目录、人脸图片地址");
        }
 
        String passwordCipher = System.getenv("DAHUA_DEVICE_PASSWORD_CIPHER");
        if (passwordCipher == null || passwordCipher.trim().isEmpty()) {
            throw new IllegalArgumentException("缺少 DAHUA_DEVICE_PASSWORD_CIPHER");
        }
        String password = DoorDeviceCredentialCrypto.decrypt(passwordCipher);
 
        new RuoYiConfig().setProfile(args[3]);
        byte[] faceImage = new DahuaFaceImageLoader().load(args[4]);
        DahuaAccessProperties properties = createProperties(args[0], args[2], password);
        DahuaAccessControlClient client = new DahuaAccessControlClient(properties);
        DahuaDeviceCredential device = new DahuaDeviceCredential(
                args[1], 37777, args[2], password, 0, 255, "GBK");
 
        long now = System.currentTimeMillis();
        DahuaAccessControlClient.VisitorCredential visitor =
                new DahuaAccessControlClient.VisitorCredential(
                        TEST_USER_ID,
                        TEST_USER_NAME,
                        null,
                        new Date(now - ONE_MINUTE_MILLIS),
                        new Date(now + 5 * ONE_MINUTE_MILLIS),
                        faceImage);
 
        RuntimeException grantFailure = null;
        try {
            client.grant(device, visitor);
            System.out.println("grantSuccess=true");
        } catch (RuntimeException e) {
            grantFailure = e;
            throw e;
        } finally {
            try {
                client.revoke(device, TEST_USER_ID);
                System.out.println("revokeSuccess=true");
            } catch (RuntimeException revokeFailure) {
                if (grantFailure != null) {
                    grantFailure.addSuppressed(revokeFailure);
                } else {
                    throw revokeFailure;
                }
            } finally {
                client.cleanup();
            }
        }
    }
 
    private static DahuaAccessProperties createProperties(String nativeLibraryPath,
                                                          String username,
                                                          String password) {
        DahuaAccessProperties properties = new DahuaAccessProperties();
        properties.setNativeLibraryPath(nativeLibraryPath);
        properties.setConnectTimeout(5000);
        properties.setTimeout(10000);
        return properties;
    }
 
    private static byte[] loadFaceImage(Path path) throws Exception {
        byte[] image = Files.readAllBytes(path);
        if (image.length == 0 || image.length > DahuaSdkLayout.MAX_FACE_IMAGE_BYTES) {
            throw new IllegalArgumentException("人脸图片必须大于0且不超过200KB");
        }
        if (!isJpeg(image) && !isPng(image)) {
            throw new IllegalArgumentException("人脸图片必须是有效的JPEG或PNG文件");
        }
        if (image.length <= DEVICE_FACE_IMAGE_LIMIT && isJpeg(image)) {
            return image;
        }
 
        BufferedImage source = ImageIO.read(new ByteArrayInputStream(image));
        if (source == null) {
            throw new IllegalArgumentException("无法解码人脸图片");
        }
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        if (!ImageIO.write(source, "jpg", output)) {
            throw new IllegalArgumentException("无法将人脸图片转换为JPEG");
        }
        byte[] normalized = output.toByteArray();
        if (normalized.length > DEVICE_FACE_IMAGE_LIMIT) {
            throw new IllegalArgumentException("人脸图片转换后仍超过120KB");
        }
        System.out.println("normalizedFaceBytes=" + normalized.length);
        return normalized;
    }
 
    private static boolean isJpeg(byte[] image) {
        return image.length >= 3
                && (image[0] & 0xFF) == 0xFF
                && (image[1] & 0xFF) == 0xD8
                && (image[2] & 0xFF) == 0xFF;
    }
 
    private static boolean isPng(byte[] image) {
        return image.length >= 8
                && (image[0] & 0xFF) == 0x89
                && image[1] == 0x50
                && image[2] == 0x4E
                && image[3] == 0x47
                && image[4] == 0x0D
                && image[5] == 0x0A
                && image[6] == 0x1A
                && image[7] == 0x0A;
    }
}