Я не знаю о Facebook, но обычно (у меня есть опыт работы с Google OAuth2 и Azure AD, а также Azure AD B2 C), поставщик аутентификации позволяет вам использовать custom Схема URI для обратного вызова аутентификации, что-то вроде badcompany://auth
Чтобы получить токен аутентификации, я реализовал следующую схему (Весь код представлен без гарантии и не копируется бездумно.)
1. Регистрация URI-обработчика при запуске приложения
Вы можете зарегистрировать URI-обработчик, создав ключ в HKEY_CURRENT_USER/Software/Classes
(следовательно, права администратора не требуются) в Windows реестре
- Имя ключа равно префиксу URI,
badcompany
в нашем случае - Ключ содержит пустое строковое значение с именем
URL Protocol
- Ключ содержит подключ
DefaultIcon
для иконки (на самом деле я не знаю, нужно ли это), я использовал путь к текущему исполняемому файлу - . Здесь есть подраздел
shell/open/command
, значение которого по умолчанию определяет путь к команде, которую нужно выполнить. ** при попытке открытия URI ** обратите внимание *, что "%1"
необходимо для передачи URI исполняемому файлу
this.EnsureKeyExists(Registry.CurrentUser, "Software/Classes/badcompany", "URL:BadCo Applications");
this.SetValue(Registry.CurrentUser, "Software/Classes/badcompany", "URL Protocol", string.Empty);
this.EnsureKeyExists(Registry.CurrentUser, "Software/Classes/badcompany/DefaultIcon", $"{location},1");
this.EnsureKeyExists(Registry.CurrentUser, "Software/Classes/badcompany/shell/open/command", $"\"{location}\" \"%1\"");
// ...
private void SetValue(RegistryKey rootKey, string keys, string valueName, string value)
{
var key = this.EnsureKeyExists(rootKey, keys);
key.SetValue(valueName, value);
}
private RegistryKey EnsureKeyExists(RegistryKey rootKey, string keys, string defaultValue = null)
{
if (rootKey == null)
{
throw new Exception("Root key is (null)");
}
var currentKey = rootKey;
foreach (var key in keys.Split('/'))
{
currentKey = currentKey.OpenSubKey(key, RegistryKeyPermissionCheck.ReadWriteSubTree)
?? currentKey.CreateSubKey(key, RegistryKeyPermissionCheck.ReadWriteSubTree);
if (currentKey == null)
{
throw new Exception("Could not get or create key");
}
}
if (defaultValue != null)
{
currentKey.SetValue(string.Empty, defaultValue);
}
return currentKey;
}
2. Откройте канал для IP C
Поскольку вам придется передавать сообщения из одного экземпляра вашей программы в другой, вам придется открыть именованный канал, который можно использовать для этой цели.
Я назвал этот код в al oop на фоне Task
private async Task<string> ReceiveTextFromPipe(CancellationToken cancellationToken)
{
string receivedText;
PipeSecurity ps = new PipeSecurity();
System.Security.Principal.SecurityIdentifier sid = new System.Security.Principal.SecurityIdentifier(System.Security.Principal.WellKnownSidType.WorldSid, null);
PipeAccessRule par = new PipeAccessRule(sid, PipeAccessRights.ReadWrite, System.Security.AccessControl.AccessControlType.Allow);
ps.AddAccessRule(par);
using (var pipeStream = new NamedPipeServerStream(this._pipeName, PipeDirection.InOut, 1, PipeTransmissionMode.Message, PipeOptions.Asynchronous, 4096, 4096, ps))
{
await pipeStream.WaitForConnectionAsync(cancellationToken);
using (var streamReader = new StreamReader(pipeStream))
{
receivedText = await streamReader.ReadToEndAsync();
}
}
return receivedText;
}
3. Убедитесь, что приложение запускается только один раз
. Это можно получить с помощью Mutex
.
internal class SingleInstanceChecker
{
private static Mutex Mutex { get; set; }
public static async Task EnsureIsSingleInstance(string id, Action onIsSingleInstance, Func<Task> onIsSecondaryInstance)
{
SingleInstanceChecker.Mutex = new Mutex(true, id, out var isOnlyInstance);
if (!isOnlyInstance)
{
await onIsSecondaryInstance();
Application.Current.Shutdown(0);
}
else
{
onIsSingleInstance();
}
}
}
Когда мьютекс был получен другим экземпляром, приложение запускается не полностью, , но
4. Обработчик вызова с URI перенаправления аутентификации
- Если это единственный (первый) экземпляр, он может обрабатывать сам URI перенаправления аутентификации
- Извлечь токен из URI
- Сохранить токен (если необходимо и / или необходимо)
- Использовать токен для запросов
- Если это дополнительный экземпляр
- Передать перенаправление URI для первого экземпляра с использованием каналов
- Первый экземпляр теперь выполняет шаги в 1.
- Закройте второй экземпляр
URI отправляется первому экземпляру с
using (var client = new NamedPipeClientStream(this._pipeName))
{
try
{
var millisecondsTimeout = 2000;
await client.ConnectAsync(millisecondsTimeout);
}
catch (Exception)
{
onSendFailed();
return;
}
if (!client.IsConnected)
{
onSendFailed();
}
using (StreamWriter writer = new StreamWriter(client))
{
writer.Write(stringToSend);
writer.Flush();
}
}