前面hawkfly提到的在多层编程中,服务器端安全性验证的问题
在以socket方式实现MIDAS时尤为明显,DCOM/CORBA都有现成的
# B1 z5 C* V8 I安全管理功能,而socket方式在这方面比较薄弱,没有现成的解决方案
8 k6 ~1 w( y! Y1 X' }: O- J现就我以前对MIDAS编程的理解,做一个简要的介绍,
以后有时间精力再详细举例说明
( X+ t9 Z0 M# z3 P) s
win2k中dcom的安全级别有7种,其中
最低的“无”安全检查暂且不论
默认的“身份验证”服务方式几句话也说不清,
先放到一边,看看剩下的5种
; G+ u2 C1 ^8 P" c6 V& @, ~
1.连接,仅对初始连接进行安全检查
3 C: v0 \$ o- T& |4 V. f6 c
因为tcp/ip是稳固的连接,因此每个连接,也就是每个RemoteDataModule
实例检测一次即可,实现方法很多,这里简要介绍一种最简单的
/ J+ n( b* _$ @0 O/ z9 N6 F) j/ k可以在服务器端的TypeLibrary里面为你的服务器接口增加若干个方法,如
interface ILoginServer: IAppServer
{
; ^& G0 V0 J$ w( Y6 V" @& b2 I[
& w) r$ _1 d3 R% e- j/ j& uid(0x00000001)
/ z: \) z3 |; {% j- R) \) m! c7 ^]
HRESULT _stdcall Login( void );
J) f' |" p, i- I! I! k[
id(0x00000002)
. o/ \3 |5 w: T7 K* A0 p]
0 `; o d9 C; Q* n' {1 d" q1 \HRESULT _stdcall Logout( void );
9 _3 C$ y% m; T6 P2 Y. O/ Z};
在方法中实现你的客户身份校验,而在校验之前,通过把RDM上所有的TDataSetProvider
6 J" K- P6 S- _# A4 E. s. d的Exported属性关掉即可让客户端无法看到服务器端的provider
因为客户端实际上是在连接服务器成功后通过服务器之IAppServer接口访问
所有的Provider,如IAppServer::AS_GetProviderNames可以取得
服务器端所有exported的IProvider接口名称,而所有数据的取得、修改
都是通过相应的ProviderName来指定的,如
- [+ B7 T9 H1 t1 rvirtual HRESULT __safecall AS_GetRecords(const WideString: ProviderName, in
t Count, int &RecsOut, int Options, const WideString: CommandText, OleVarian
/ ?) d0 `. D# V1 s/ H( S7 nt &
arams, OleVariant: &OwnerData, OleVariant &GetRecords_result) = 0 ;
取得数据方法的第一个参数就是你需要操作的数据集名称……
2 N) B7 ]* m/ {' ^; i- t" L5 [如果你把服务器RDM上所有的TDataSetProvider::Exported关掉,
则客户端看不到任何Provider,也无法通过其ProviderName取得数据
$ K3 H9 l: _; D) ^7 P例如我在服务器端的RDM类中加入
class TLoginServer : public TCRemoteDataModule
{
...
private: // User declarations
+ }% h0 @( a6 D8 P7 M! R3 rbool FLogin;
void __fastcall SetLogin(bool value);
bool __fastcall IsLogin(OleVariant &OwnerData);
...
__published:
__property bool Login = { read = FLogin, write = SetLogin };
};
在RDM实现类中
class ATL_NO_VTABLE TLoginServerImpl: 。。。
{
% ~& V2 ~ B& D1 q% Q9 k// ILoginServer
3 q k( z: |* R; Fprotected:
: J% _$ F& t- R' a/ X; zSTDMETHOD(Login());
STDMETHOD(Logout());
3 X) p0 r/ {9 N& H0 y};
然后简单实现之
__fastcall TLoginServer::TLoginServer(TComponent* Owner)
: TCRemoteDataModule(Owner), FLogin(false)
( X% f/ n) L9 k% D. }{
}
//---------------------------------------------------------------------------
; x D' V2 F+ z, N$ Jvoid __fastcall TLoginServer::SetLogin(bool value)
s; U9 ~/ G9 a{
/ o' Y; s- t) q0 D: ]: nif(FLogin != value)
9 |8 M" P5 ?9 |0 Y( Z. {! b- M{
FLogin = value;
dspAnimals->Exported = FLogin;
}
) H0 W1 _3 P4 [1 p}
M0 m7 `6 Z; s# k+ M//---------------------------------------------------------------------------
, U9 u: R% c4 k! YSTDMETHODIMP TLoginServerImpl:
ogin()
{
m_DataModule->Login = true;
return S_OK;
6 A* {) k$ N8 }3 e: p, N% [}
//---------------------------------------------------------------------------
STDMETHODIMP TLoginServerImpl:
ogout()
{
; M- I4 W9 _7 L4 D; dm_DataModule->Login = false;
return S_FALSE;
}
$ `$ R" T/ \2 n, m7 c//---------------------------------------------------------------------------
bool __fastcall TLoginServer::IsLogin(OleVariant &OwnerData)
{
% \/ T: E& G$ Y- X( lreturn FLogin;
}
easy
这样除非你的客户端成功调用Login方法,否则他是无法使用
dspAnimals这个数据集Provider的,成功调用后手工打开的数据集使用完全相同
比如客户端可以用如下代码
IDispatch *dispAppServer = (IDispatch*)(DM->Connection->AppServer);
4 S5 e% ]$ j" r+ T8 F$ E$ JILoginServerDisp dispLoginServer = (ILoginServer *)dispAppServer;
dispLoginServer.Login();
DM->cdsAnimals->Open();
7 _! H# h' u- ~- ]实现注册,并且打开相应数据集……
' j( F1 s C% Z% G( v" |
因为大多数的三层程序对安全性要求并不高,因此这样的安全检测对
8 b8 _1 E/ H' X, y6 d% _. A绝大多数程序应该足以……
| 欢迎光临 数学建模社区-数学中国 (http://www.madio.net/) | Powered by Discuz! X2.5 |