You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过WinUI3+C#桌面应用实现Google OAuth登录?

WinUI3 + C# 实现Google登录并获取用户信息

桌面应用实现Google登录的核心是使用OAuth 2.0授权码流程+PKCE(桌面应用属于公共客户端,无法安全存储密钥,PKCE是Google官方推荐的方案),下面是具体实现步骤:

1. Google Cloud控制台配置

  • 创建项目并启用「Google Identity API」
  • 在「凭据」页面创建「OAuth客户端ID」,应用类型选择「桌面应用」
  • 记录生成的客户端ID,无需客户端密钥;同时配置允许的重定向URI(推荐两种方案:http://localhost:自定义端口 或 自定义URI方案如com.googleusercontent.apps.你的客户端ID:/oauth2redirect)

2. 构造授权请求(带PKCE)

生成PKCE参数

// 生成code_verifier:43-128位的随机字符串
var codeVerifier = Convert.ToBase64String(RandomNumberGenerator.GetBytes(32))
    .Replace('+', '-')
    .Replace('/', '_')
    .TrimEnd('=');

// 生成code_challenge:对code_verifier做SHA256哈希后Base64URL编码
using var sha256 = SHA256.Create();
var challengeBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(codeVerifier));
var codeChallenge = Convert.ToBase64String(challengeBytes)
    .Replace('+', '-')
    .Replace('/', '_')
    .TrimEnd('=');

构造并打开授权URL

var clientId = "你的Google客户端ID";
var redirectUri = "http://localhost:5000"; // 和控制台配置一致
var scope = "openid email profile"; // 需要获取的用户权限

var authUri = new UriBuilder("https://accounts.google.com/o/oauth2/v2/auth")
{
    Query = string.Join("&", new[]
    {
        $"client_id={Uri.EscapeDataString(clientId)}",
        "response_type=code",
        $"scope={Uri.EscapeDataString(scope)}",
        $"redirect_uri={Uri.EscapeDataString(redirectUri)}",
        $"code_challenge={Uri.EscapeDataString(codeChallenge)}",
        "code_challenge_method=S256",
        "access_type=offline" // 可选,用于获取刷新令牌
    })
}.Uri;

// 打开默认浏览器
await Launcher.LaunchUriAsync(authUri);

3. 接收授权码并交换令牌

方案1:本地HTTP服务器监听回调

在应用中启动一个轻量的HttpListener,监听指定端口的请求:

var listener = new HttpListener();
listener.Prefixes.Add("http://localhost:5000/");
listener.Start();

// 等待Google重定向回调
var context = await listener.GetContextAsync();
var code = context.Request.QueryString["code"];

// 返回浏览器提示页面,让用户关闭窗口
var responseString = "<html><body>登录完成,请关闭此窗口</body></html>";
var buffer = Encoding.UTF8.GetBytes(responseString);
context.Response.ContentLength64 = buffer.Length;
var output = context.Response.OutputStream;
await output.WriteAsync(buffer);
output.Close();
listener.Stop();

交换授权码获取令牌

拿到code后,向令牌端点发送POST请求:

var tokenRequest = new FormUrlEncodedContent(new Dictionary<string, string>
{
    {"client_id", clientId},
    {"code", code},
    {"redirect_uri", redirectUri},
    {"grant_type", "authorization_code"},
    {"code_verifier", codeVerifier}
});

using var httpClient = new HttpClient();
var tokenResponse = await httpClient.PostAsync("https://oauth2.googleapis.com/token", tokenRequest);
var tokenData = await tokenResponse.Content.ReadFromJsonAsync<TokenResponse>();

// TokenResponse是自定义类,包含access_token、id_token等字段
public class TokenResponse
{
    public string access_token { get; set; }
    public string id_token { get; set; }
    public int expires_in { get; set; }
    public string refresh_token { get; set; } // 如果请求了access_type=offline则返回
}

4. 获取用户身份信息

使用access_token调用Google用户信息API:

using var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", tokenData.access_token);
var userInfo = await httpClient.GetFromJsonAsync<UserInfo>("https://www.googleapis.com/oauth2/v3/userinfo");

// UserInfo自定义类,包含用户基本信息
public class UserInfo
{
    public string sub { get; set; } // 用户唯一ID
    public string name { get; set; }
    public string given_name { get; set; }
    public string family_name { get; set; }
    public string picture { get; set; }
    public string email { get; set; }
    public bool email_verified { get; set; }
}

注意事项

  • 自定义URI方案需要在Windows注册表中注册,确保系统能将URI关联到你的应用(可以在安装包中配置,或首次启动时写入注册表)
  • 处理令牌过期:如果请求了refresh_token,可以用它刷新access_token,无需用户重新登录
  • 权限范围按需申请,避免请求不必要的权限,提高用户信任度

内容的提问来源于stack exchange,提问作者G_Man

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 22:36:33