【发布时间】:2017-02-27 10:38:27
【问题描述】:
我正在尝试创建一个基本上充当本地 Web 服务器的服务。理论上,用户将通过浏览器中的 localhost 访问 URI 来使用 REST API,即http://localhost:2017/path/to/function/call 将连接到服务并执行功能。
我的问题是如何获取调用该服务的帐户的 SID 和用户名?
我已经实现了几个解决方案,但它们返回的是服务的 SID 和用户名,而不是使用它的用户。
OJSon* UnifiedStreamingService::getUserDetails()
{
OJSon* result = OJSon::create();
if(result)
{
/*
HANDLE hToken = NULL;
ULONG id = WTSGetActiveConsoleSessionId();
BOOL bRet = WTSQueryUserToken(id, &hToken);
if (bRet == false)
{
DWORD error = GetLastError();
printf("ERROR: %d", error);
}
*/
HANDLE hToken = NULL;
if ( ! OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &hToken ) )
{
//_tprintf( _T("OpenProcessToken failed. GetLastError returned: %d\n"), GetLastError());
return NULL;
}
// Get the size of the memory buffer needed for the SID
DWORD dwBufferSize = 0;
if ( ! GetTokenInformation( hToken, TokenUser, NULL, 0, &dwBufferSize ) && ( GetLastError() != ERROR_INSUFFICIENT_BUFFER ) )
{
//_tprintf( _T("GetTokenInformation failed. GetLastError returned: %d\n"), GetLastError());
// Cleanup
CloseHandle( hToken );
hToken = NULL;
return NULL;
}
// Allocate buffer for user token data
std::vector<BYTE> buffer;
buffer.resize( dwBufferSize );
PTOKEN_USER pTokenUser = reinterpret_cast<PTOKEN_USER>( &buffer[0] );
// Retrieve the token information in a TOKEN_USER structure
if ( ! GetTokenInformation(
hToken,
TokenUser,
pTokenUser,
dwBufferSize,
&dwBufferSize))
{
//_tprintf( _T("2 GetTokenInformation failed. GetLastError returned: %d\n"), GetLastError());
// Cleanup
CloseHandle( hToken );
hToken = NULL;
return NULL;
}
// Check if SID is valid
if ( ! IsValidSid( pTokenUser->User.Sid ) )
{
//_tprintf( _T("The owner SID is invalid.\n") );
// Cleanup
CloseHandle(hToken);
hToken = NULL;
return NULL;
}
// add the name
OString* name = lookupAccountSid(pTokenUser->User.Sid);
if(name)
{
result->setKey(&OString("name"), name);
SAFEDELETE(name);
}
// add the SID
OString* sid = convertSidToString(pTokenUser->User.Sid);
if(sid)
{
result->setKey(&OString("SID"), sid);
SAFEDELETE(sid);
}
// Cleanup
CloseHandle(hToken);
hToken = NULL;
}
return result;
}
OString* UnifiedStreamingService::convertSidToString(PSID pSID)
{
OString* result = NULL;
if(pSID)
{
// Get string corresponding to SID
LPTSTR pszSID = NULL;
if ( ! ConvertSidToStringSid( pSID, &pszSID ) )
{
return NULL;
}
result = new OString(pszSID);
// Release buffer allocated by ConvertSidToStringSid API
LocalFree( pszSID );
pszSID = NULL;
}
return result;
}
OString* UnifiedStreamingService::lookupAccountSid(PSID pSID)
{
DWORD dwSize = 256;
DWORD dwResult = 0;
SID_NAME_USE SidType;
LPTSTR lpName = new TCHAR[dwSize];
LPWSTR lpDomain = new TCHAR[dwSize];
OString* result = NULL;
if( !LookupAccountSid( NULL, pSID, lpName, &dwSize, lpDomain, &dwSize, &SidType ) )
{
dwResult = GetLastError();
return NULL;
}
OString* pDomain = new OString(lpDomain);
OString* pName = new OString(lpName);
if(pDomain && pName)
{
result = OString::createByFormat(&OString("%s\\%s"), pDomain, pName);
SAFEDELETE(pDomain);
SAFEDELETE(pName);
}
delete[] lpDomain;
delete[] lpName;
return result;
}
【问题讨论】:
-
TCP/IP 是匿名的,您需要在您的服务器中实现身份验证,即提示输入用户名和密码。
-
不确定确切的条件,但如果您需要唯一登录用户的 SID,您可以使用 WTSGetActiveConsoleSessionId 和 WTSQueryUserToken 获取用户令牌,然后使用 GetTokenInformation 获取 SID。但您需要适当的访问权限才能执行此操作。
-
@KonstantinL 我确实尝试过这种技术,但它导致了服务的 SID 和用户名。您知道需要什么访问权限才能使其返回用户的 SID 和/或用户名吗?
-
嗯.. 出了点问题。如果权限不足,您应该获得零句柄,而不是服务句柄。你能展示你的代码吗?
-
@KonstantinL 您好,我已附上我当前的代码。