超级难题,关于logonuser或其他办法连接中间层服务器 (300分)

  • 主题发起人 主题发起人 KenLee
  • 开始时间 开始时间
K

KenLee

Unregistered / Unconfirmed
GUEST, unregistred user!
我的三层结构的程序结构是这样的,数据库服务器、中间层应用程序服务器都用2000server,
客户端用98。中间层程序和客户端程序都放在中间层(一个2000server)一个共享目录里,
客户端(98)机器只使用该共享目录中的客户端程序的快捷方式。
由于客户端程序需要读写其他很多配置文件,这些文件也都放在该共享目录下,并且所有客户
端(98)机器都有读写该共享目录的权限。问题是,这些配置文件我希望只能由程序去读写它,
但不允许其他人为的修改。
解决的办法我想是把这些配置文件放在另一个目录下,并不给98客户端机器有访问权限,然后
在程序中动态建立网络连接,用完释放。
尝试过的函数有:WNetCancelConnection2、net use 和LogonUser,都失败了。
WNetCancelConnection2(98下)“can not open file ……”
LogonUser在98下提示该功能仅在win32模式下有效;在2000professional中又提示用户没有
需要的特权(但是已经受权'SeTcbPrivilege',见所附程序)
附:测试程序。
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ExtCtrls, StdCtrls;

type
TForm1 = class(TForm)
Button1: TButton;
Image1: TImage;
Label1: TLabel;
Memo1: TMemo;
Button2: TButton;
Edit1: TEdit;
Button3: TButton;
Button4: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure Button4Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);
var
NRW: TNetResource;
d : dword;
begin
with NRW do
begin
dwType:= RESOURCETYPE_ANY;
lpLocalName:='T:';//PChar(LocalDriver); //映射的网络驱动器,取自己最高盘符后面一个就可以了。
lpRemoteName:='//APPSERVER/photo';
//PChar(ShareName); //共享文件夹名
lpProvider:='';
end;
try
d := WNetAddConnection2(NRW, PChar('fwzh'), PChar('fwzh'), CONNECT_UPDATE_PROFILE);
if d=NO_ERROR then
Image1.Picture.LoadFromFile(NRW.lpRemoteName + '/FaSongBtn_Hot.bmp')
else begin
showMessage( IntToStr(d));
case d of
ERROR_ACCESS_DENIED :showMessage(' Access to the network resource was denied. ');
ERROR_ALREADY_ASSIGNED :showMessage(' The local device specified by lpLocalName is already connected to a network resource.');
ERROR_BAD_DEV_TYPE :showMessage(' The type of local device and the type of network resource do not match.');
ERROR_BAD_DEVICE :showMessage(' The value specified by lpLocalName is invalid.');
ERROR_BAD_NET_NAME :showMessage(' The value specified by lpRemoteName is not acceptable to any network resource provider. The resource name is invalid, or the named resource cannot be located.');
ERROR_BAD_PROFILE :showMessage(' The user profile is in an incorrect format.');
ERROR_BAD_PROVIDER :showMessage(' The value specified by lpProvider does not match any provider.');
ERROR_BUSY :showMessage('The router or provider is busy, possibly initializing. The caller should retry.');
ERROR_CANCELLED :showMessage('The attempt to make the connection was cancelled by the user through a dialog box from one of the network resource providers, or by a called resource.');
ERROR_CANNOT_OPEN_PROFILE : showMessage('The system is unable to open the user profile to process persistent connections.');
ERROR_DEVICE_ALREADY_REMEMBERED: showMessage('An entry for the device specified in lpLocalName is already in the user profile.');
ERROR_EXTENDED_ERROR : showMessage('A network-specific error occured. Call the WNetGetLastError function to get a description of the error.');
ERROR_INVALID_PASSWORD : showMessage('The specified password is invalid.');
ERROR_NO_NET_OR_BAD_PATH : showMessage('A network component has not started, or the specified name could not be handled.');
ERROR_NO_NETWORK : showMessage('There is no network present.');
end;
end;
finally
d := WNetCancelConnection2(PChar('T:'),CONNECT_UPDATE_PROFILE, FALSE);
end;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
Edit1.Text := ExtractFilePath(ParamStr(0));
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
WinExec(Pchar('net use //appserver/photo/ fwzh/fwzh'),sw_Hide);
Image1.Picture.LoadFromFile('//appserver/photo/FaSongBtn_Hot.bmp');
WinExec(Pchar('net use //appserver/photo /delete'),sw_Hide);
end;

function GetErrorMessage(Code:Integer):String;
var
hErrLib:THandle;
msg:PChar;
flags:Integer;

function MAKELANGID(p,s:word):Integer;
begin
result:=(s shl 10) or p
end;

begin
hErrLib:=LoadLibraryEx ('netmsg.dll', 0, LOAD_LIBRARY_AS_DATAFILE);
try
flags:=FORMAT_MESSAGE_ALLOCATE_BUFFER or FORMAT_MESSAGE_IGNORE_INSERTS or FORMAT_MESSAGE_FROM_SYSTEM;
if hErrLib<>0 then flags := flags or FORMAT_MESSAGE_FROM_HMODULE;
if FormatMessage(flags,pointer(hErrLib),code,MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),PChar(@msg),0,Nil)<>0 Then
try
result:=msg;
finally
LocalFree(Integer(msg));
end
finally
if hErrLib <> 0 then FreeLibrary (hErrLib)
end
end;

procedure TForm1.Button4Click(Sender: TObject);
var
hdlProcessHandle : Thandle;
hdlTokenHandle : Thandle;
tmpLuid : Int64;
tkp : TOKEN_PRIVILEGES;
tkpNewButIgnored : TTokenPrivileges;// TOKEN_PRIVILEGES;
lBufferNeeded : Cardinal;
tkn : Thandle;
FError:DWORD;
begin
hdlProcessHandle := GetCurrentProcess;
OpenProcessToken(hdlProcessHandle, (TOKEN_ADJUST_PRIVILEGES or
TOKEN_QUERY), hdlTokenHandle);

// Get the LUID for shutdown privilege.
if not LookupPrivilegeValue('', 'SeTcbPrivilege', tmpLuid) then
begin
showmessage('LookupPrivilegeValue');
FError:=GetLastError;
Application.MessageBox(PChar(GetErrorMessage(FError)),'',mb_OK + mb_ICONINFORMATION);//显示出错原因
end;

tkp.PrivilegeCount := 1; // ' One privilege to set
tkp.Privileges[0].Luid := tmpLuid;
tkp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
// Enable the shutdown privilege in the access token of this process.

//AdjustTokenPrivileges( hToken, False, tkp, SizeOf( TTokenPrivileges ), tkpo, zero );
if not AdjustTokenPrivileges(hdlTokenHandle, False, tkp,
SizeOf({tkpNewButIgnored}TTokenPrivileges), tkpNewButIgnored, lBufferNeeded) then
begin
showmessage('AdjustToken');
FError:=GetLastError;
Application.MessageBox(PChar(GetErrorMessage(FError)),'',mb_OK + mb_ICONINFORMATION);//显示出错原因
end;
if not LogonUser(PChar('fwzh'),
pchar('appdomain'),
PChar('fwzh'),
LOGON32_LOGON_NETWORK,
LOGON32_PROVIDER_DEFAULT,
hdlTokenHandle) then
begin
FError:=GetLastError;
Application.MessageBox(PChar(GetErrorMessage(FError)),'',mb_OK + mb_ICONINFORMATION);//显示出错原因
Exit;
end
end;


end.

 
http://www.delphibbs.com/keylife/iblog_show.asp?xid=605
我最后就贴了一段登录网络的代码。
试验过的。
 
你太牛了,大富翁N个用WNetAddConnection2函数的,怎么就没见过这样写的,唉!
可是xianjun大侠,现在变成另一个错误了“Access to the network resource was denied.”
是什么原因呢,我的用户名和密码都是有效的,随时可以登录那个叫做appserver的2kServer的。
该怎么解决呢?
procedure TForm1.Button1Click(Sender: TObject);
var
NRW: TNetResource;
d : dword;
begin
//登录到目标计算机
FillChar(NRW, SizeOf(NRW), 0);
NRW.dwScope := RESOURCE_GLOBALNET;
NRW.dwType := RESOURCETYPE_ANY;
NRW.dwDisplayType := RESOURCEDISPLAYTYPE_SERVER;
NRW.lpRemoteName := PChar('//appserver/Photo');
case WNetCancelConnection2(NRW.lpRemoteName, 0, False) of
NO_ERROR, ERROR_NOT_CONNECTED:
begin
d := WNetAddConnection2(NRW, PChar('fwzh'), PChar('fwzh'), 0);
if ((d=NO_ERROR)or(d=ERROR_ALREADY_ASSIGNED))then
Image1.Picture.LoadFromFile(NRW.lpRemoteName + '/FaSongBtn_Hot.bmp')
else begin
showMessage( IntToStr(d));
case d of
ERROR_ACCESS_DENIED :showMessage(' Access to the network resource was denied. ');
ERROR_ALREADY_ASSIGNED :showMessage(' The local device specified by lpLocalName is already connected to a network resource.');
ERROR_BAD_DEV_TYPE :showMessage(' The type of local device and the type of network resource do not match.');
ERROR_BAD_DEVICE :showMessage(' The value specified by lpLocalName is invalid.');
ERROR_BAD_NET_NAME :showMessage(' The value specified by lpRemoteName is not acceptable to any network resource provider. The resource name is invalid, or the named resource cannot be located.');
ERROR_BAD_PROFILE :showMessage(' The user profile is in an incorrect format.');
ERROR_BAD_PROVIDER :showMessage(' The value specified by lpProvider does not match any provider.');
ERROR_BUSY :showMessage('The router or provider is busy, possibly initializing. The caller should retry.');
ERROR_CANCELLED :showMessage('The attempt to make the connection was cancelled by the user through a dialog box from one of the network resource providers, or by a called resource.');
ERROR_CANNOT_OPEN_PROFILE : showMessage('The system is unable to open the user profile to process persistent connections.');
ERROR_DEVICE_ALREADY_REMEMBERED: showMessage('An entry for the device specified in lpLocalName is already in the user profile.');
ERROR_EXTENDED_ERROR : showMessage('A network-specific error occured. Call the WNetGetLastError function to get a description of the error.');
ERROR_INVALID_PASSWORD : showMessage('The specified password is invalid.');
ERROR_NO_NET_OR_BAD_PATH : showMessage('A network component has not started, or the specified name could not be handled.');
ERROR_NO_NETWORK : showMessage('There is no network present.');
end;
end;
end;
end;
end;
 
把配置文件放到数据库中不就行了
 
放到数据库表面上是行的,实际上严重加剧数据库负担,根本不可取。
 
既然Windows这么说,肯定是你的用户没有足够的权限了
你要看看那个用户是不是有权限访问//appserver/Photo
或者换一个用户试试, 那段代码是没有问题的,我一直在用。
 
xianjun,我想你也许误解我的意思了,我是要程序里用一个可以登录那服务器的用户,而98
本身登录时用的就是低权限的用户。现在是这样,如果我98中用‘fwzh’的用户名和密码登
录,就能打开那个图片,如果用别的用户登录,虽然程序中传了‘fwzh’的用户名和密码,
但还是打开不了。
不明白阿!我听说还是得用logonuser的,但是我好像也没写错什么吧!
 
根本用不着这么麻烦吧,你可以正在你的应用程序服务器上定义一个或一组方法
来读写配置文件不就行了,那些文件根本就不用share,就在本机访问.
 
没必要将中间层服务器共享啊!
把共享目录配置成只读的!

98上运行时读配置文件没问题吧?如果要写,就传给中间层让中间层去完成吧!
就象XEEN说的.可以考虑用TMemIniFile.
 
wolaixue,其实是这样的,所有客户机共享的配置文件不只是ini,还有很多东西,比如宏文件
定义等等,非常多。设置成只读只能是一种最后的办法,因为部分用户会具有修改部分配置文
件(以供所有人共用)的权限。
xeen,程序现有检测用户权限和打开修改配置文件的功能都又统一的框架,如果做成你说的那样,
还得对不同的共享文件写不同的方法并分别的进行权限检测。这样做不但损坏现有优越的架构,
还降低可扩充性,不爽。
300分阿,还有哪位高手能用logonuser或其他网络操作函数解决的吗?

 
LogonUser即使有ADMINISTRATOR权限也是不能用的,必须是系统权限,
用户界面下的程序最多只能拥有同登陆者同样的权限,
解决办法也是有的,用到了WIN2000的系统漏洞,能够提升权限,不过很麻烦,
而且不知道有没有打补丁,你要的话可以给你例子,用到了汇编
 
qsilence,需要汇编吗,我好象听说有关机权限的就行了。
不过你还是发给我试试看吧,mail:liganx@263.net
 
LogonUser 是NT4 SP3版本才新加的API,你98下怎么调用?
如果你一开始就用了一个低权限的用户登录,再想用另一个用户登录到网络,难
在9X/ME下,WNetAddConnection2中的用户名密码必须为空,也就是说不能手工指定用户密码

我看你还是另想办法吧。
 
你在中间层应用程序服务器上用一个本地数据库或自定义文件存取配置信息即可,
绝对不会加重服务器的负担
 
to KenLee
如果是在98下,最好别用这个函数了,返回恒为-1
如果在2000下,你只需要关机权限的话不需要汇编,只用调整一下ACL就行,
但如果用LOGONUSER的话,必须是系统权限(不是关机权限)
 
to wfzha,
"你在中间层应用程序服务器上用一个本地数据库或自定义文件存取配置信息即可,"
公用文件包含很多图片,甚至还包含为了提高登录速度的.dat(数据库定义)文件,把这些
东西存到中间层的本地数据库再由中间层读出,太滑稽了点,而且必然快不了。
to xeen,
“你可以正在你的应用程序服务器上定义一个或一组方法
来读写配置文件不就行了,那些文件根本就不用share,就在本机访问.”可以具体一点吗,
比如给个例子:我客户端要load一副图片,这副图片客户端访问不了,只能由中间层本地访
问,然后中间层发布该函数,让客户端可以调用。给个简单例子好不好。
 
那你就在再开一个SqlServer吧,理由如下:
1、安全问题易解决
2、如果传送的资料较大,传送瓶颈应该在网络上,即使数据库比文件系统略慢,也不会成为瓶颈
3、多层系统并不是只有三层,需要几层就可以由几层,由于是分布式编程,不会因为曾数的增加
而明显加重系统负担,效率照样很高。多层系统提高效率的办法主要在于减少通讯的次数,而不是
减少系统的层数
4、其实对大型应用来说,文件系统并不一定比数据库系统来得快,你没见M$想在将来的操作系统
中将在数据库系统的基础上建立文件系统吗
举个例子:例如如果100进程同时访问文件系统,文件系统即使不崩溃也要慢得像蜗牛爬,但对
数据库来说就是小菜一碟了。
5、其实Internet上大多数应用都是有单独的服务器的,如DNS服务器...例子实在是太多了,这是
分布式应用的根本特点。
我没做过跨地域的大型的分布式系统,但是直觉觉得这样的系统一定要有一台以上专门的服务器
来管理用户账户而且数据库应该是最好的选择,其实操作系统的目录服务不都是建立在数据库的
基础上吗,如果真的文件系统的效率高,为什么不单纯使用文件系统呢。
6、其实我说的和xeen是一回事,只不过系统小的时候用中间层代替了一台服务器而已,不管数
据库服务器在那里,多层程序的设计都是一样的,即使在本地也是!
 
后退
顶部