最终的项目是工作应用程序(运行时:net6.0,目标操作系统:Windows Server 2012R2),旨在用作 Windows 服务,使用 OPC UA 协议从 KEPServer(内部系统的代理)收集数据。
支持的安全策略:
服务器管理员向我保证不会使用带有私钥的证书。使用的扩展是
.der
类型。
出于安全考虑,敏感数据已被“端口”、“IP”等虚拟存根替代。
<?xml version="1.0" encoding="utf-8"?>
<ApplicationConfiguration
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ua="http://opcfoundation.org/UA/2008/02/Types.xsd"
xmlns="http://opcfoundation.org/UA/SDK/Configuration.xsd"
>
<ApplicationName>OPCFoundationConsoleClient</ApplicationName>
<ApplicationUri>urn:localhost:OPCFoundationConsoleClient</ApplicationUri>
<ApplicationType>Client_1</ApplicationType>
<SecurityConfiguration>
<ApplicationCertificate>
<StoreType>Directory</StoreType>
<StorePath>%LocalFolder%/CertificateStores/pki/own</StorePath>
<SubjectName>CN=MY_CLIENT, C=Country, S=City, O=organization, DC=opc.tcp://ip:port</SubjectName>
<!--<Thumbprint>Some hash</Thumbprint>-->
</ApplicationCertificate>
<TrustedIssuerCertificates>
<StoreType>Directory</StoreType>
<StorePath>%LocalFolder%/CertificateStores/pki/issuer</StorePath>
</TrustedIssuerCertificates>
<TrustedPeerCertificates>
<StoreType>Directory</StoreType>
<StorePath>%LocalFolder%/CertificateStores/pki/trusted</StorePath>
</TrustedPeerCertificates>
<RejectedCertificateStore>
<StoreType>Directory</StoreType>
<StorePath>%LocalFolder%/CertificateStores/pki/rejected</StorePath>
</RejectedCertificateStore>
<AutoAcceptUntrustedCertificates>false</AutoAcceptUntrustedCertificates>
</SecurityConfiguration>
<TransportConfigurations></TransportConfigurations>
<TransportQuotas>
<OperationTimeout>120000</OperationTimeout>
<MaxStringLength>4194304</MaxStringLength>
<MaxByteStringLength>4194304</MaxByteStringLength>
<MaxArrayLength>65535</MaxArrayLength>
<MaxMessageSize>4194304</MaxMessageSize>
<MaxBufferSize>65535</MaxBufferSize>
<ChannelLifetime>300000</ChannelLifetime>
<SecurityTokenLifetime>3600000</SecurityTokenLifetime>
</TransportQuotas>
<ClientConfiguration>
<DefaultSessionTimeout>60000</DefaultSessionTimeout>
<WellKnownDiscoveryUrls>
<ua:String>opc.tcp://{0}:port</ua:String>
</WellKnownDiscoveryUrls>
<DiscoveryServers></DiscoveryServers>
<MinSubscriptionLifetime>10000</MinSubscriptionLifetime>
<OperationLimits>
<MaxNodesPerRead>2500</MaxNodesPerRead>
<MaxNodesPerHistoryReadData>1000</MaxNodesPerHistoryReadData>
<MaxNodesPerHistoryReadEvents>1000</MaxNodesPerHistoryReadEvents>
<MaxNodesPerWrite>2500</MaxNodesPerWrite>
<MaxNodesPerHistoryUpdateData>1000</MaxNodesPerHistoryUpdateData>
<MaxNodesPerHistoryUpdateEvents>1000</MaxNodesPerHistoryUpdateEvents>
<MaxNodesPerMethodCall>2500</MaxNodesPerMethodCall>
<MaxNodesPerBrowse>2500</MaxNodesPerBrowse>
<MaxNodesPerRegisterNodes>2500</MaxNodesPerRegisterNodes>
<MaxNodesPerTranslateBrowsePathsToNodeIds>2500</MaxNodesPerTranslateBrowsePathsToNodeIds>
<MaxNodesPerNodeManagement>2500</MaxNodesPerNodeManagement>
<MaxMonitoredItemsPerCall>2500</MaxMonitoredItemsPerCall>
</OperationLimits>
</ClientConfiguration>
</ApplicationConfiguration>
到目前为止一切顺利。主题已定。设置存储文件夹的路径。我还将 KEPServer 的证书添加到 .CertificatesStores/pki/issuer/certs。应用程序证书已传递给服务器管理员以添加到受信任列表。他还表示 PHD 重新初始化期间没有出现错误。
在查看了 UA-.NETStandard-Samples 中的“ConsoleReferenceClient”(因为它对我来说最合适)存储库后,我删除了以下代码行:
using System.Text.Json;
using Opc.Ua;
using Opc.Ua.Client;
using Opc.Ua.Configuration;
using Microsoft.Extensions.Configuration;
using Models;
using System.Security.Cryptography.X509Certificates;
using System.Security.Cryptography;
const string tagsDataSettingsName = "tagsDataSettings.json"; // tags' ID list and other relevant settings
try {
/* configuration handling logic */
var configuration = await application.LoadApplicationConfiguration(silent: false);
var haveAppCertificate = await application.CheckApplicationInstanceCertificate(true, 2048);
if (!haveAppCertificate) {
throw new Exception("Application certificate isn't found.");
}
var endpointDescription = CoreClientUtils.SelectEndpoint(configuration, tds.Host.Address, true); // tds is a custom settings variable
endpointDescription.SecurityMode = (MessageSecurityMode)tds.Host.SecurityMode;
endpointDescription.SecurityPolicyUri = tds.Host.SecurityPolicyUri;
var endpointConfiguration = EndpointConfiguration.Create(configuration);
ConfiguredEndpoint endpoint = new(null, endpointDescription, endpointConfiguration);
var certificate = configuration.SecurityConfiguration.ApplicationCertificate.Certificate;
using (var session = await TraceableSessionFactory.Instance.CreateAsync(configuration: configuration, endpoint: endpoint, updateBeforeConnect: true, checkDomain: false, sessionName: "", sessionTimeout: 60000, identity: new UserIdentity(certificate), preferredLocales: null)) {
if (session!.Connected) {
var readValues = tds.TagGroups?.Aggregate(new ReadValueIdCollection(),
(final, current) => {
Array.ForEach(current.Tags!,
id => {
var tag = new ReadValueId()
{
NodeId = new NodeId(id),
AttributeId = Attributes.Value
};
final.Add(tag);
});
return final;
});
var response = await session.ReadAsync(null, 0, TimestampsToReturn.Both, readValues, CancellationToken.None);
var formattedData = response.Results.Aggregate("",
(final, current) => {
var tagData = $"[{current.SourceTimestamp}]: status code: {current.StatusCode}; value: {current.Value}";
final = (final == "") ? $"{tagData}" : $"{final}\n{tagData}";
return final;
});
Console.WriteLine(formattedData);
await session!.CloseAsync();
}
}
Console.ReadKey();
} catch (AggregateException agrErr) {
foreach (var ie in agrErr.InnerExceptions) {
Console.WriteLine($"AggregatedException.InnerExceptions error: {ie.Message}");
}
Console.ReadKey();
} catch (Exception err) {
Console.WriteLine($"Error: {err.Message}");
Console.ReadKey();
}
var i = 2;
while (i > 0) {
Console.WriteLine($"The application shuts down in {i} s");
await Task.Delay(1000);
i--;
}
tds
对象是记录类型,用于标签ID(ns=2;s=Namespace.Device.TagName)存储以及服务器地址。它还包含安全策略 URL 和安全模式类型。这是我的 .json
格式的自定义配置。
当我在生产服务器上部署并启动应用程序时,出现错误:
Endpoint doesn't support the user identity type provided
。创建应用程序证书: .der
在 own 子文件夹和 .pfx
- private。据我了解,该消息很简单:服务器不想允许连接。
我尝试测试与 UaExpert 程序的连接,但是当我设置 身份验证设置 => 证书时,出现错误,提示未找到 X509 证书私钥。该程序也不允许使用生成的
.pfx
证书。文件浏览器中仅允许使用 .pem
。所以它没有给我带来任何显着的结果。选择策略时,我只能在服务器设置块中使用上述内容。
certificate.PrivateKey
返回true
,但根据管理员的要求我不允许使用它。
certificate.GetHashString()
返回正确的哈希值。我想应用程序尝试使用 .pfx
证书,但我如何使用常规 .der
证书?
我该怎么办?将
.der
转换为 .pem
? .pfx
是密钥存储,所以我可以以某种方式从中提取密钥?我希望有更详细的规格。
所以,我可以总结以下几点:
附注我在这个网站上遇到过一些示例,但它们不使用证书(匿名身份),而是使用项目监控,而我需要按时间间隔(计时器)进行会话。
您似乎混淆了 OPC UA application 身份验证(始终使用证书完成)与 user 身份验证,这是一个不同的概念。研究 OPC UA 规范以了解这些规范。 用户身份验证可以是匿名、用户名/密码,也可以是(不太常见)证书。
您未正确地将 UserIdentity 中的 OPC UA application 证书传递到会话。这不仅是错误的证书,而且据我所知,KepServer 根本不支持用于 user 身份验证的 X509 证书。您需要使用匿名或用户名/密码。和, AFAIK,KepServer 默认情况下不允许匿名 user 连接。
因此,为了解决您的问题,您需要
使用正确的用户名和密码创建一个 UserIdentity,而不是证书,并将其传递给会话创建调用,或者