前面hawkfly提到的在多层编程中,服务器端安全性验证的问题
, i C: d6 v# B' r4 ]在以socket方式实现MIDAS时尤为明显,DCOM/CORBA都有现成的
5 G& b& p) q1 g& J3 c安全管理功能,而socket方式在这方面比较薄弱,没有现成的解决方案
6 |8 H) @) J1 s" s% `2 N" A现就我以前对MIDAS编程的理解,做一个简要的介绍,
; ~- {: f" p! m, n以后有时间精力再详细举例说明
win2k中dcom的安全级别有7种,其中
最低的“无”安全检查暂且不论
默认的“身份验证”服务方式几句话也说不清,
/ L+ _, Q4 P3 ~: ^- D* P先放到一边,看看剩下的5种
1.连接,仅对初始连接进行安全检查
因为tcp/ip是稳固的连接,因此每个连接,也就是每个RemoteDataModule
/ \7 m! Z3 f |- t实例检测一次即可,实现方法很多,这里简要介绍一种最简单的
可以在服务器端的TypeLibrary里面为你的服务器接口增加若干个方法,如
% D' C' m3 h& t% C( p0 q; winterface ILoginServer: IAppServer
{
[
id(0x00000001)
]
HRESULT _stdcall Login( void );
/ x& j/ s) G0 h* Q) {2 L[
& J1 y2 H: `% H' [6 A1 C4 X9 {id(0x00000002)
2 `( {3 H9 N& K, S# }]
HRESULT _stdcall Logout( void );
4 v2 \4 a& q( M9 F};
- J! i# Z4 p* [) N/ Z8 o& o在方法中实现你的客户身份校验,而在校验之前,通过把RDM上所有的TDataSetProvider
5 G* ?- \. f; \9 W& b- [的Exported属性关掉即可让客户端无法看到服务器端的provider
/ Z7 F5 [9 t2 x8 @因为客户端实际上是在连接服务器成功后通过服务器之IAppServer接口访问
2 \0 R$ w4 p, J3 n% j所有的Provider,如IAppServer::AS_GetProviderNames可以取得
服务器端所有exported的IProvider接口名称,而所有数据的取得、修改
. W X4 Z& ]0 i7 J6 m6 G都是通过相应的ProviderName来指定的,如
* x' E$ ~; t/ A" T" a; Pvirtual HRESULT __safecall AS_GetRecords(const WideString: ProviderName, in
t Count, int &RecsOut, int Options, const WideString: CommandText, OleVarian
! }" e( i W. l8 R( Z$ kt &
arams, OleVariant: &OwnerData, OleVariant &GetRecords_result) = 0 ;
取得数据方法的第一个参数就是你需要操作的数据集名称……
如果你把服务器RDM上所有的TDataSetProvider::Exported关掉,
* \8 S+ B3 r* X% v7 h则客户端看不到任何Provider,也无法通过其ProviderName取得数据
5 k$ Z9 a' a$ H& k* L' O' k; K例如我在服务器端的RDM类中加入
1 b& W6 w+ F% Z% yclass TLoginServer : public TCRemoteDataModule
l. D4 C2 ]5 }( V1 I% q{
...
private: // User declarations
: n( |8 Q! g; I) ]* @1 xbool FLogin;
: e+ s0 Y4 K3 s, h1 Vvoid __fastcall SetLogin(bool value);
, K' I0 w5 p0 P# Z; v' @/ [" }bool __fastcall IsLogin(OleVariant &OwnerData);
3 M$ M! I; Z9 p. Q3 K9 I1 p4 Z...
__published:
__property bool Login = { read = FLogin, write = SetLogin };
. J( S2 }4 y- ~8 g};
在RDM实现类中
. o9 l: a" |( R& |3 ]6 m ]( g. aclass ATL_NO_VTABLE TLoginServerImpl: 。。。
; q% H! E) q* U{
// ILoginServer
protected:
) Q! @6 P, n8 P0 ]- n, D4 B- GSTDMETHOD(Login());
% |5 t5 U) P# ^1 PSTDMETHOD(Logout());
- V# I5 S2 g5 B};
然后简单实现之
7 e' t2 D8 C9 C+ D__fastcall TLoginServer::TLoginServer(TComponent* Owner)
9 @% |$ ^3 N1 }" g4 p: TCRemoteDataModule(Owner), FLogin(false)
2 S7 D7 e% ^! ^0 ]( d, G{
: P3 ?- l# g$ [( m% g c7 N}
6 B/ Z0 ?4 a; S6 ~//---------------------------------------------------------------------------
void __fastcall TLoginServer::SetLogin(bool value)
{
if(FLogin != value)
{
' p1 {! H6 Z' X; ^) u7 Z9 yFLogin = value;
dspAnimals->Exported = FLogin;
}
7 D7 Z# @. ~ y+ c( k$ x) [}
//---------------------------------------------------------------------------
# ^' c' y' {3 p6 l( e/ KSTDMETHODIMP TLoginServerImpl:
ogin()
{
+ v# L# Y4 c+ Zm_DataModule->Login = true;
# E2 B$ p' n; e# Yreturn S_OK;
}
//---------------------------------------------------------------------------
+ K% L( s0 k: J2 E8 X9 |9 i7 e# GSTDMETHODIMP TLoginServerImpl:
ogout()
{
m_DataModule->Login = false;
- w9 g: j! w4 p9 K+ a! |return S_FALSE;
. @+ `: G* s) v4 n3 f$ v9 C}
; k5 \# C& M9 \, O//---------------------------------------------------------------------------
bool __fastcall TLoginServer::IsLogin(OleVariant &OwnerData)
{
$ a* r4 U* J$ T; i" U! N5 ureturn FLogin;
0 s9 O4 k3 o I" m. `5 o+ p3 _: f}
& l) f* ?0 o; [) b0 }1 T1 xeasy
这样除非你的客户端成功调用Login方法,否则他是无法使用
dspAnimals这个数据集Provider的,成功调用后手工打开的数据集使用完全相同
( B* O& c( H- Z0 P$ P
比如客户端可以用如下代码
IDispatch *dispAppServer = (IDispatch*)(DM->Connection->AppServer);
- |+ Y1 q$ E! ]( s8 r* o/ cILoginServerDisp dispLoginServer = (ILoginServer *)dispAppServer;
# e f/ y9 i/ h6 z# t8 `dispLoginServer.Login();
! z3 c) `( C' C0 a. iDM->cdsAnimals->Open();
, C6 S) Y5 M I! P. Z实现注册,并且打开相应数据集……
$ C9 X2 _( c: F/ u
因为大多数的三层程序对安全性要求并不高,因此这样的安全检测对
绝大多数程序应该足以……
| 欢迎光临 数学建模社区-数学中国 (http://www.madio.net/) | Powered by Discuz! X2.5 |