You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity开发OPC UA客户端遇证书缺失问题及相关疑问

Unity中OPC UA Client证书找不到问题的解决及分发说明

一、解决证书找不到的错误

你遇到的ServiceResultException: ApplicationCertificate cannot be found,核心原因是代码仅配置了证书路径,但未触发OPC UA库的证书自动生成逻辑,同时Unity环境下系统环境变量不会自动解析,需要手动处理。

关键修复步骤:

  1. 解析系统环境变量:Unity无法自动识别%CommonApplicationData%这类变量,需用Environment.ExpandEnvironmentVariables方法手动展开路径。
  2. 触发证书自动生成:OPC UA库不会主动创建证书,必须显式调用配置验证和证书初始化方法,确保证书不存在时自动生成。

二、修正后的代码示例

using System.Security.Cryptography.X509Certificates;
using Opc.Ua;
using Opc.Ua.Client;
using System.Threading.Tasks;
using UnityEngine;
using System;

public class OPCUAReader : MonoBehaviour
{
    private Session session;

    async void Start()
    {
        var endpointUrl = "opc.tcp://opcuaserver.com:48010";
        var endpoint = new ConfiguredEndpoint(null, new EndpointDescription
        {
            EndpointUrl = endpointUrl
        });

        // 手动解析系统环境变量路径
        string storePath = Environment.ExpandEnvironmentVariables(@"%%CommonApplicationData%%\OPC Foundation\CertificateStores\MachineDefault");

        var config = new ApplicationConfiguration
        {
            ApplicationUri = "urn:UnityOPCClient:OPC UA Client Test", // 必须设置唯一的客户端URI
            ApplicationName = "OPC UA Client Test",
            ApplicationType = ApplicationType.Client,
            SecurityConfiguration = new SecurityConfiguration
            {
                ApplicationCertificate = new CertificateIdentifier
                {
                    StoreType = CertificateStoreType.Directory,
                    StorePath = storePath,
                    SubjectName = "OPC UA Client Test",
                },
                AutoAcceptUntrustedCertificates = true, // 允许自动信任服务器证书(测试环境可用)
                RejectSHA1SignedCertificates = false,
                MinimumCertificateKeySize = 2048
            },
            TransportConfigurations = new TransportConfigurationCollection(),
            TransportQuotas = new TransportQuotas { OperationTimeout = 60000 },
            ClientConfiguration = new ClientConfiguration { DefaultSessionTimeout = 60000 }
        };

        try
        {
            // 验证配置并触发证书生成逻辑
            await config.Validate(ApplicationType.Client);

            // 检查证书是否存在,不存在则自动创建
            var cert = config.SecurityConfiguration.ApplicationCertificate.Find(true);
            if (cert == null)
            {
                cert = CertificateFactory.CreateCertificate(
                    config.SecurityConfiguration.ApplicationCertificate.StoreType,
                    config.SecurityConfiguration.ApplicationCertificate.StorePath,
                    null,
                    config.ApplicationUri,
                    config.ApplicationName,
                    config.SecurityConfiguration.ApplicationCertificate.SubjectName,
                    null,
                    CertificateFactory.DefaultKeySize,
                    DateTime.UtcNow - TimeSpan.FromDays(1),
                    CertificateFactory.DefaultLifeTime);

                // 将生成的证书保存到指定路径
                config.SecurityConfiguration.ApplicationCertificate.Certificate = cert;
                config.SecurityConfiguration.ApplicationCertificate.Save();
            }

            // 创建OPC UA会话
            session = await Session.Create(
                config,
                endpoint,
                true,
                "",
                60000,
                null,
                null);

            await ReadVariableValue();
        }
        catch (Exception ex)
        {
            Debug.LogError("初始化或连接失败: " + ex.Message);
        }
    }

    async Task ReadVariableValue()
    {
        if (session == null || !session.Connected)
        {
            Debug.LogError("会话未连接");
            return;
        }

        try
        {
            var readValue = await session.ReadValueAsync(new NodeId("ns=2;s=Demo.Static.Scalar.Double"));
            Debug.Log("读取到的值: " + readValue.Value);
        }
        catch (Exception ex)
        {
            Debug.LogError("读取变量失败: " + ex.Message);
        }
    }

    private void OnDestroy()
    {
        // 销毁时关闭会话
        session?.Close();
        session?.Dispose();
    }
}

代码要点说明:

  • 必须设置ApplicationUri:OPC UA协议要求每个客户端有唯一标识URI,否则证书生成会失败。
  • 环境变量手动解析:确保路径在Unity环境下能正确指向证书存储目录。
  • 显式证书生成逻辑:通过检查证书是否存在,触发自动创建并保存的流程。

三、分发到其他电脑的证书处理

分发后有两种可行方案:

  1. 预先打包证书:

    • 在开发机上运行程序生成证书,找到%CommonApplicationData%\OPC Foundation\CertificateStores\MachineDefault下的客户端证书文件(通常为.der和.pfx格式)。
    • 将证书与程序打包,在目标电脑部署到相同路径,或者修改代码中的证书路径为程序本地目录(比如Application.persistentDataPath),避免系统路径权限问题。
  2. 目标电脑自动生成:

    • 保留代码中的证书生成逻辑,首次运行时程序会自动创建证书,但需要注意:
      • 目标电脑需具备对应路径的写入权限(若使用系统公共目录,可能需要以管理员身份运行程序)。
      • 可将证书路径改为用户目录(比如Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)下的自定义文件夹),规避权限限制。

内容的提问来源于stack exchange,提问作者Ege

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 23:12:12