Как получить текущего вошедшего в систему пользователя, включая домен в Delphi 2009?

Мне нужно получить текущее имя пользователя? Мне нужно, чтобы это работало правильно, когда я вызываю код из ASP.NET, который работает в режиме проверки подлинности Windows. то есть я не хочу получить пользователя ASPNET в этом случае, а олицетворенного пользователя. Это связано с моим более ранним вопросом. Все, что я пытаюсь сделать, возвращает ASPNET.


person Steve    schedule 26.11.2009    source источник


Ответы (3)


В другом вопросе вы написали, что настроили ASP.NET для использования проверки подлинности Windows с олицетворением:

 <system.web>
    ...
    <authentication mode="Windows"/>
    <identity impersonate="true"/>
    ...
 </system.web>

Отображает ли приложение ASP.NET правильные учетные данные (пользователя и домена)?

Вы вызываете функцию Delphi, используя правильный контекст Identity, например

WindowsIdentity winId = (WindowsIdentity)HttpContext.Current.User.Identity;
try
{
    ctx = winId.Impersonate();
    // call Delphi function, passing the identity context
}
catch
{
}
finally
{
    if (ctx != null)
        ctx.Undo();
}

Обновлять:

Если объект COM вызывается из кода для страницы веб-формы, вы можете попытаться установить для свойства ASPCOMPAT страницы веб-формы значение true.

Видеть:

Тег «identity» гарантирует, что поток, выполняющий запрос (поток MTA), будет олицетворять свой контекст безопасности для пользователя, указанного в теге, но наш STA COM-объект в конечном итоге был создан в потоке STA по умолчанию, который не был олицетворенным, что привело к чтобы получить контекст безопасности процесса (это был IUSR_XXX — наименее влиятельный пользователь из всех).

person mjn    schedule 26.11.2009
comment
Приложение asp.net возвращает олицетворенные учетные данные. Так что я знаю, что настроено правильно. - person Steve; 26.11.2009
comment
Я не уверен, что мое приложение Delphi может или будет делать с контекстом идентификации, как только оно его получит. Помните, что Delphi — это Win32. - person Steve; 26.11.2009
comment
Как вы вызываете приложение Delphi из ASP.NET? Можете ли вы показать код? - person mjn; 26.11.2009
comment
Приложение Delphi представляет собой простой COM-объект. Я создаю ссылку на него, затем создаю экземпляр объекта и вызываю метод. Но я могу передавать только стандартные типы COM в качестве параметров, если только я не перехожу к пользовательскому маршалингу. - person Steve; 26.11.2009
comment
Если объект COM вызывается из кода для страницы веб-формы, вы можете попытаться установить для свойства ASPCOMPAT страницы веб-формы значение true. Смотрите новые ссылки в моем ответе. - person mjn; 26.11.2009
comment
Это сработало, хотя наш com-объект является COM-объектом MTA, а не STA com-объектом, но, очевидно, должно происходить что-то еще. Посмотрим, как это пойдет. Спасибо - person Steve; 26.11.2009
comment
На самом деле это был объект STA COM. Так что все имеет смысл, и ответ идеален. Спасибо - person Steve; 27.11.2009

Возможно, ваш подход IADsWinNTSystemInfo (из связанного предыдущего вопроса) возвращает информацию об учетной записи текущего процесса, но ASP.NET выдает себя за уровень потока?

Попробуй это:

type
  PTokenUser = ^TTokenUser;
  TTokenUser = packed record
    User: SID_AND_ATTRIBUTES;
  end;

function GetCurrentUserName(out DomainName, UserName: string): Boolean;
var
  Token: THandle;
  InfoSize, UserNameSize, DomainNameSize: Cardinal;
  User: PTokenUser;
  Use: SID_NAME_USE;
  _DomainName, _UserName: array[0..255] of Char;
begin
  Result := False;
  DomainName := '';
  UserName := '';

  Token := 0;
  if not OpenThreadToken(GetCurrentThread, TOKEN_QUERY, True, Token) then
  begin
    if GetLastError = ERROR_NO_TOKEN then // current thread is not impersonating, try process token
    begin
      if not OpenProcessToken(GetCurrentProcess, TOKEN_QUERY, Token) then
        Exit;
    end
    else
      Exit;
  end;
  try
    GetTokenInformation(Token, TokenUser, nil, 0, InfoSize);
    User := AllocMem(InfoSize * 2);
    try
      if GetTokenInformation(Token, TokenUser, User, InfoSize * 2, InfoSize) then
      begin
        DomainNameSize := SizeOf(_DomainName);
        UserNameSize := SizeOf(_UserName);

        Result := LookupAccountSid(nil, User^.User.Sid, _UserName, UserNameSize, _DomainName, DomainNameSize, Use);

        if Result then
        begin
          SetString(DomainName, _DomainName, StrLen(_DomainName));
          SetString(UserName, _UserName, StrLen(_UserName));
        end;
      end;
    finally
      FreeMem(User);
    end;
  finally
    CloseHandle(Token);
  end;
end;

Пример использования:

var
  DomainName, UserName: string;
begin
  if not GetCurrentUserName(DomainName, UserName) then
    RaiseLastOSError;
  Writeln(Format('%s\%s', [DomainName, UserName]));
end;

Надеюсь это поможет.

person Ondrej Kelle    schedule 26.11.2009
comment
Да, потому что код не работает. ;-) Пытаюсь выяснить почему. - person Ondrej Kelle; 26.11.2009

Это часть кода моего LoadProfile, он хорошо работает в Delphi 2010:

const
  UNLEN = 256; // Maximum user name length

var
  TokenHandle: THandle; // Handle to the Processes' Acces Token
  cbTokenInfo: DWORD; // Size of TokenInfo in Bytes
  pTokenUser: PTOKEN_USER; // Pointer to a TOKEN_USER record

  cchName: DWORD; // Count of characters (length) of the Username array
  cchDomain: DWORD; // Count of characters (length) of the Domainname array
  peUse: DWORD; // Account type for LookupAccountSid

  UserName: array[0..UNLEN] of Char; // Holds the Username
  DomainName: array[0..UNLEN] of Char; // Holds the Domainname
  ComputerName: array[0..UNLEN] of Char; // Hold the Computername


    // Open the Current Process' Token
    OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY or
      TOKEN_IMPERSONATE or TOKEN_DUPLICATE, TokenHandle);

    // Check if we have a valid handle
    if TokenHandle = 0 then
      Exit; 

    { We will use GetTokenInformation to get the user's SID, the first call
      to GetTokenInformation is used to determine how much memory we need to
      allocate }
    GetTokenInformation(TokenHandle, TokenUser, nil, 0, cbTokenInfo);
    // as documented the call should fail with ERROR_INSUFFICIENT_BUFFER
    if (GetLastError() <> ERROR_INSUFFICIENT_BUFFER) then
      Exit;

    // Allocate Memory
    pTokenUser :=  HeapAlloc(GetProcessHeap(), 0, cbTokenInfo);
    if (pTokenUser = nil) then
       Exit;

    // Retrieve the user information from the token.
    if ( not GetTokenInformation(TokenHandle, TokenUser, pTokenUser,
      cbTokenInfo, cbTokenInfo)) then
       Exit;

    cchName := Length(UserName);
    cchDomain := Length(DomainName);
    peUse:= SidTypeUser;


    // Use the SID to find User and Domain Name
    Write('LookupAccountSid... ');
    if not LookupAccountSid(nil, pTokenUser^.User.Sid, UserName, cchName,
      DomainName, cchDomain, peUse) then
      Exit;

    // Cleanup
    if (pTokenUser <> nil) then
      HeapFree(GetProcessHeap(), 0, pTokenUser);

    WriteLn('CloseHandle... OK');
    CloseHandle(TokenHandle);
person Remko    schedule 26.11.2009
comment
Я добавил это в качестве замены кода TOndrej, так как он прав, что олицетворение предназначено только для текущего потока. - person Remko; 26.11.2009