有时我们需要临时以其它用户的权限来执行某项操作。典型的像从一个共享文件夹中复制数据到本地,如果这个共享文件夹处于一个安全的服务器上,且设置了只有指定的用户才能读取,这时这种技术就非常有用;通常的处理方法是临时映射一个本地盘符,用完后取消映射,但如果要处理的时间稍长,有经验的用户会察觉到它,并在你的程序执行操作的同时也同样可以访问到其中的敏感内容,所以我们需要秘密的访问它。Windows 有几个 API 可以帮我们完成此功能,它们是: LogonUser, ImpersonateLoggedOnUser, RevertToSelf,类似于 RunAs 的功能。
下面的代码实现了这个功能:
*!* LogonUser API test #define LOGNAME 'test' #define LOGDOMAIN NULL #define LOGPSWD '123' #define SRCFILE '//dkfdtf/ttt/test.txt' #define TAGFILE 'MyCopiedFile.txt' #define LOGON32_PROVIDER_DEFAULT 0 #define LOGON32_LOGON_INTERACTIVE 2 #define LOGON32_LOGON_NETWORK 3 #define LOGON32_LOGON_BATCH 4 #define LOGON32_LOGON_SERVICE 5 #define LOGON32_LOGON_UNLOCK 7 DECLARE Long LogonUser IN WIN32API ; String szUsername, String lpszDomain, String lpszPassword, ; Long dwLogonType, Long dwLogonProvider, Long @ phToken DECLARE Long ImpersonateLoggedOnUser IN WIN32API ; Long hToken DECLARE Long RevertToSelf IN WIN32API LOCAL iToken, lSuccess MESSAGEBOX( '首先以当前用户权限测试.', 64, '按任意键继续' ) CopyTest( SUBSTR( ID(), AT('#', ID())+1 )) MESSAGEBOX( '现在以 test 用户权限测试.', 64, '按任意键继续' ) m.iToken = 0 IF ( 0 == LogonUser( LOGNAME, LOGDOMAIN, LOGPSWD, ; LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, @ m.iToken )) ; OR ; ( 0 = ImpersonateLoggedOnUser( m.iToken )) MESSAGEBOX( '登录验证失败. 无法继续', 16, '错误' ) ELSE *!* 现在应该有访问权限了 m.lSuccess = CopyTest( 'test' ) RevertToSelf() && 操作完成, 移除访问授权 IF ( m.lSuccess ) MODIFY FILE ( TAGFILE ) ENDIF ENDIF FUNCTION CopyTest( tcUser AS String ) LOCAL oError, cMsg TRY COPY FILE ( SRCFILE ) TO ( TAGFILE ) m.oError = NULL CATCH TO m.oError ENDTRY m.cMsg = '以 ' + m.tcUser + ' 用户权限操作' IF ISNULL( m.oError ) MESSAGEBOX( m.cMsg + '成功.', 64, '信息' ) ELSE TEXT TO m.cMsg NOSHOW TEXTMERGE <<m.cmsg>>失败 错误消息:<<m.oerror.message>> ENDTEXT MESSAGEBOX( m.cMsg, 16, '错误' ) ENDIF RETURN ISNULL( m.oError ) ENDFUNC
可以这样来测试:
1. 先在管理工具->本地用户和组中创建一个名为 test 的测试用户,口令改为 123
2. 创建一个共享文件夹,将共享权限中的 EveryOne 等其它用户全部删除,加入刚创建的 test 用户。(如果你找不到更改共享权限的地方,应该是使用了“简单共享”模式,可以到“工具->文件夹选项”中关闭它后再来设置)
3. 在这个共享文件夹中创建一个名为 test.txt 的文本文件,其中随便写点什么。
将上面代码中的第 4 行( '//dkfdtf/ttt/test.txt' ) 改为: //你的计算机名/共享文件夹名/test.txt 然后复制并运行上面的代码,应该可以看到以当前用户是无法读取到 test.txt 文件的,而 test 用户则可以成功。
由于最终用户并不知道这个 test 用户的名称和口令,所以只有你的程序可以访问这个共享文件夹中的数据,其它用户无法访问它们;这里只是用本地机器来做的测试,所以你可以在管理工具中看到这个用户的账号,当这个共享文件夹处于一个安全的服务器上时,账号和共享文件夹下的数据便可以得到一定程度上的保护。