解决客户端计算机上的 Web 安全限制






4.71/5 (5投票s)
PHP 和 C# 通过 thrift 框架协同工作
引言
这个示例允许你在内网 Web 环境中,在客户端机器上执行命令、打开文件等。
背景
一些时间以前,我正在开发一个用于控制建筑项目开发的应用程序,我的客户要求它必须是一个 Web 应用程序。其中一个挑战是,在这个 Web 应用程序中应该能够通过点击网页上的链接来打开图纸和文档。正如我们所知,出于安全原因,这是不可能的,所以我决定使用桌面支持软件来在客户端机器上执行这些任务。而内网 Web 应用程序和桌面软件之间的桥梁是由 THRIFT (一种接口定义语言和二进制通信协议) 实现的。
使用应用程序
注意:你必须运行 composer 来获取 symfony 中的 vendors ....
我创建了两个示例项目:一个是充当 thrift 客户端的 Symfony 2.8 Web 应用程序,另一个是在客户端机器上运行的 C# 应用程序,作为服务器。一切都从编写一个 .thrift 文件开始,该文件是由 thrift 类型和服务组成的接口定义,如下所示
namespace csharp ThriftServer
namespace php ThriftSampleBundle.Util
struct FileInf
{
1: string FileName,
2: string extension,
3: bool isDir
}
service OpenFileService{
bool openFile (1:FileInf info,2:string parameters),
list <FileInf> listFolder(1:string path),
}
这里有两个方法的定义,一个用于列出指定路径中的文件夹和文件,另一个用于运行或打开特定文件,所有这些都在客户端机器上进行。然后运行 thrift 命令来生成客户端和服务器代码。
通用语法是
thrift --gen <language> <Thrift filename
对于 PHP
thrift --gen php OpenFileService.thrift
对于 C#
thrift --gen csharp OpenFileService.thrift
因此,你必须在服务器上实现这两个方法,并通过 RPC 从客户端调用它们。
一些来自 PHP 的代码,充当客户端,请注意我使用 "$this->request->getClientIp()
" 来获取内网客户端 IP 并知道连接到哪里。因此,如果 Web 浏览器有代理配置,你必须指定不为该站点使用代理,否则它会获取错误的 IP 地址。
private function openConnection() {
// Create a thrift connection (Boiler plate)
$socket = new TSocket($this->request->getClientIp(), '9090');
$this->transport = new TBufferedTransport($socket);
$protocol = new TBinaryProtocol($this->transport);
// Create a calculator client
$this->client = new OpenFileServiceClient($protocol);
// Open up the connection
$this->transport->open();
}
要从 PHP 客户端调用 C# 服务器上的 listFolder($path)
方法
public function listFolder($path) {
try {
$this->openConnection();
// Perform operation on the server
$result=$this->client->listFolder($path);
// And finally, we close the thrift connection
$this->transport->close();
return $result;
}
catch (\Exception $tx) {
// a general thrift exception, like no such server
echo "ThriftException: ".$tx->getMessage()."\r\n";
}
}
要从 PHP 客户端调用 C# 服务器上的 openFile($path,$extension)
方法
public function openFile($path,$extension) {
try {
$this->openConnection();
$fileInfo=new FileInf();
$fileInfo->FileName=$path;
$fileInfo->extension=$extension;
// Perform operation on the server
$this->client->openFile($fileInfo,null);
// And finally, we close the thrift connection
$this->transport->close();
}
catch (\Exception $tx) {
// a general thrift exception, like no such server
echo "ThriftException: ".$tx->getMessage()."\r\n";
}
}
现在让我们看看如何在 C# 中启动服务器端
private void thrift(){
//Thrift stuff
var handler = new OpenFileHandler();
var processor = new OpenFileService.Processor(handler);
TServerTransport transport = new TServerSocket(9090);
TServer server = new TThreadPoolServer(processor, transport);
server.Serve();
//end thrift
}
以及服务处理程序实现
/*
* Created by SharpDevelop.
* User: lca85
* Date: 8/16/2016
* Time: 1:09 PM
*
* To change this template use Tools | Options | Coding | Edit Standard Headers.
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Windows.Forms;
namespace ThriftServer
{
/// <summary>
/// Description of OpenFileHandler.
/// </summary>
public class OpenFileHandler:OpenFileService.Iface
{
public FileInf fileToOpen;
public OpenFileHandler()
{
}
public bool openFile(FileInf info, string parameters)
{
System.Diagnostics.Process.Start(info.FileName);
return true;
}
public IAsyncResult Begin_openFile(AsyncCallback callback,
object state, FileInf info, string parameters)
{
throw new NotImplementedException();
}
public bool End_openFile(IAsyncResult asyncResult)
{
throw new NotImplementedException();
}
public List<FileInf> listFolder(string path)
{
DirectoryInfo di=new DirectoryInfo(path);
FileInfo[] files=di.GetFiles();
DirectoryInfo[] directories=di.GetDirectories();
List<FileInf>aux_list=new List<FileInf>();
foreach (DirectoryInfo element in directories) {
FileInf aux_file=new FileInf();
aux_file.FileName=element.FullName;
aux_file.Extension="";
aux_file.IsDir=true;
aux_list.Add(aux_file);
}
foreach (FileInfo element in files) {
FileInf aux_file=new FileInf();
aux_file.FileName=element.FullName;
aux_file.Extension=element.Extension.Replace(".","");
aux_file.IsDir=false;
aux_list.Add(aux_file);
}
return aux_list;
}
public IAsyncResult Begin_listFolder(AsyncCallback callback, object state, string path)
{
throw new NotImplementedException();
}
public List<FileInf> End_listFolder(IAsyncResult asyncResult)
{
throw new NotImplementedException();
}
}
}