我已经听说过谷歌此处所述的OAuth互动现代化计划:https://developers.googleblog.com/2016/08/modernizing-oauth-interactions-in-native-apps.html
然后我在查看此处的Windows示例桌面应用程序:https://github.com/googlesamples/oauth-apps-for-windows/tree/master/OAuthDesktopApp。
它非常简单并且它正常工作,但是一旦我启动Visual Studio而没有提升权限(作为非管理员),我经历了HttpListener由于以下错误而无法启动:&# 34;访问被拒绝"。
事实证明,如果没有管理员权限,则无法在环回地址(127.0.0.1)处启动HttpListener。但是,尝试使用localhost而不是127.0.0.1会导致成功。
我发现有一个特定的命令允许HttpListener从给定的地址(和端口)开始:
netsh http add urlacl url=http://+:80/MyUri user=DOMAIN\user
但它也只能用管理员权限执行,所以它不是一个选项。
仍然localhost似乎是最好的镜头,但 OAuth 2.0 for Mobile&桌面应用对此部分说明如下:
有关环回IP地址的详细信息,请参阅redirect_uri参数定义。也可以使用localhost代替环回IP,但这可能会导致客户端防火墙出现问题。大多数(但不是全部)防火墙允许环回通信。
这就是我使用localhost有点怀疑的原因。所以我想知道在这种情况下谷歌推荐的方式是什么,因为我并不打算以管理员的身份运行我们的应用程序。
有什么想法吗?
答案 0 :(得分:0)
您可以使用TcpListener代替HttpListener。它不需要提升就可以了。
以下是此示例的修改摘录: https://github.com/googlesamples/oauth-apps-for-windows/tree/master/OAuthDesktopApp
// Generates state and PKCE values.
string state = randomDataBase64url(32);
string code_verifier = randomDataBase64url(32);
string code_challenge = base64urlencodeNoPadding(sha256(code_verifier));
const string code_challenge_method = "S256";
// Creates a redirect URI using an available port on the loopback address.
var listener = new TcpListener(IPAddress.Loopback, 0);
listener.Start();
string redirectURI = string.Format("http://{0}:{1}/", IPAddress.Loopback, ((IPEndPoint)listener.LocalEndpoint).Port);
output("redirect URI: " + redirectURI);
// Creates the OAuth 2.0 authorization request.
string authorizationRequest = string.Format("{0}?response_type=code&scope=openid%20profile&redirect_uri={1}&client_id={2}&state={3}&code_challenge={4}&code_challenge_method={5}",
authorizationEndpoint,
System.Uri.EscapeDataString(redirectURI),
clientID,
state,
code_challenge,
code_challenge_method);
// Opens request in the browser.
System.Diagnostics.Process.Start(authorizationRequest);
// Waits for the OAuth authorization response.
var client = await listener.AcceptTcpClientAsync();
// Read response.
var response = ReadString(client);
// Brings this app back to the foreground.
this.Activate();
// Sends an HTTP response to the browser.
WriteStringAsync(client, "<html><head><meta http-equiv='refresh' content='10;url=https://google.com'></head><body>Please close this window and return to the app.</body></html>").ContinueWith(t =>
{
client.Dispose();
listener.Stop();
Console.WriteLine("HTTP server stopped.");
});
// TODO: Check the response here to get the authorization code and verify the code challenge
读写方法是:
private string ReadString(TcpClient client)
{
var readBuffer = new byte[client.ReceiveBufferSize];
string fullServerReply = null;
using (var inStream = new MemoryStream())
{
var stream = client.GetStream();
while (stream.DataAvailable)
{
var numberOfBytesRead = stream.Read(readBuffer, 0, readBuffer.Length);
if (numberOfBytesRead <= 0)
break;
inStream.Write(readBuffer, 0, numberOfBytesRead);
}
fullServerReply = Encoding.UTF8.GetString(inStream.ToArray());
}
return fullServerReply;
}
private Task WriteStringAsync(TcpClient client, string str)
{
return Task.Run(() =>
{
using (var writer = new StreamWriter(client.GetStream(), Encoding.UTF8))
{
writer.Write("HTTP/1.0 200 OK");
writer.Write(Environment.NewLine);
writer.Write("Content-Type: text/html; charset=UTF-8");
writer.Write(Environment.NewLine);
writer.Write("Content-Length: " + str.Length);
writer.Write(Environment.NewLine);
writer.Write(Environment.NewLine);
writer.Write(str);
}
});
}