Blazor中Google身份认证实现:兼容Asp.net Core托管与MAUI环境
统一兼容Blazor WASM(Asp.net Core托管)与MAUI Android的Google身份认证方案
核心思路
所有认证流程完全通过后端代理,应用端(Blazor WASM/MAUI)仅负责触发认证请求、接收后端返回的认证结果,全程不接触Google Client ID和Secret,确保密钥安全。
步骤1:后端(Asp.net Core)配置Google认证
- 安装NuGet包:
Microsoft.AspNetCore.Authentication.Google - 在
Program.cs中配置Google认证与JWT(跨场景兼容):
builder.Services.AddAuthentication(options => { options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = GoogleDefaults.AuthenticationScheme; }) .AddGoogle(googleOptions => { // 从配置文件读取密钥,避免硬编码 googleOptions.ClientId = builder.Configuration["Authentication:Google:ClientId"]; googleOptions.ClientSecret = builder.Configuration["Authentication:Google:ClientSecret"]; googleOptions.CallbackPath = "/signin-google"; // 映射Google返回的用户头像字段 googleOptions.ClaimActions.MapJsonKey("urn:google:picture", "picture", "url"); }) .AddJwtBearer(jwtOptions => { jwtOptions.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey = true, ValidIssuer = builder.Configuration["Jwt:Issuer"], ValidAudience = builder.Configuration["Jwt:Audience"], IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"])) }; }); // 启用认证、授权中间件 app.UseAuthentication(); app.UseAuthorization();
- 新增认证接口,处理前端触发的认证请求与Token生成:
[ApiController] [Route("api/auth")] public class AuthController : ControllerBase { private readonly IConfiguration _config; public AuthController(IConfiguration config) { _config = config; } // 触发Google认证跳转 [HttpGet("google-login")] public IActionResult GoogleLogin() { var redirectUrl = Url.Action(nameof(GoogleResponse), "Auth"); var properties = new AuthenticationProperties { RedirectUri = redirectUrl }; return Challenge(properties, GoogleDefaults.AuthenticationScheme); } // 处理Google回调,生成JWT返回给前端 [HttpGet("google-response")] public async Task<IActionResult> GoogleResponse() { var result = await HttpContext.AuthenticateAsync(GoogleDefaults.AuthenticationScheme); if (!result.Succeeded) return BadRequest("Google认证失败"); // 提取用户Claims var claims = result.Principal.Claims.ToList(); // 生成JWT Token var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Jwt:Key"])); var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256); var token = new JwtSecurityToken( issuer: _config["Jwt:Issuer"], audience: _config["Jwt:Audience"], claims: claims, expires: DateTime.Now.AddMinutes(30), signingCredentials: credentials); return Ok(new { Token = new JwtSecurityTokenHandler().WriteToken(token) }); } }
步骤2:前端通用认证逻辑(兼容Blazor WASM和MAUI)
通用认证服务
创建IAuthService接口与实现类,封装核心认证逻辑,两个前端项目共用:
public interface IAuthService { Task<string> LoginWithGoogle(); Task Logout(); } public class AuthService : IAuthService { private readonly HttpClient _httpClient; private readonly object _navigationService; // 平台特定导航服务,Blazor用NavigationManager,MAUI用INavigation public AuthService(HttpClient httpClient, object navigationService) { _httpClient = httpClient; _navigationService = navigationService; } public async Task<string> LoginWithGoogle() { // 触发后端认证跳转 var response = await _httpClient.GetAsync("api/auth/google-login"); if (response.IsRedirect) { var redirectUrl = response.Headers.Location.ToString(); // 平台特定跳转逻辑:Blazor用NavigationManager,MAUI用WebView加载 if (_navigationService is NavigationManager blazorNav) { blazorNav.NavigateTo(redirectUrl, true); } } // 获取认证后的Token var tokenResponse = await _httpClient.GetFromJsonAsync<TokenResponse>("api/auth/google-response"); return tokenResponse?.Token; } public Task Logout() { // 清除前端存储的Token,可选调用后端注销接口 return Task.CompletedTask; } } // 辅助模型 public class TokenResponse { public string Token { get; set; } }
平台适配处理
Blazor WASM:
在Program.cs注册服务:builder.Services.AddScoped<IAuthService>(sp => new AuthService(sp.GetRequiredService<HttpClient>(), sp.GetRequiredService<NavigationManager>())); builder.Services.AddHttpClient("BackendApi", client => client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress));页面中触发认证:
<button @onclick="HandleGoogleLogin">Google登录</button> @code { [Inject] private IAuthService AuthService { get; set; } [Inject] private Blazored.LocalStorage.ILocalStorageService LocalStorage { get; set; } private async Task HandleGoogleLogin() { var token = await AuthService.LoginWithGoogle(); if (!string.IsNullOrEmpty(token)) { await LocalStorage.SetItemAsync("authToken", token); // 导航到主页面 NavigationManager.NavigateTo("/"); } } }MAUI Android:
使用WebView加载认证地址,监听回调获取Token:private readonly HttpClient _httpClient; private readonly INavigation _navigation; public LoginPage(HttpClient httpClient, INavigation navigation) { InitializeComponent(); _httpClient = httpClient; _navigation = navigation; } private void GoogleLoginBtn_Clicked(object sender, EventArgs e) { var authUrl = $"{App.BackendBaseUrl}/api/auth/google-login"; AuthWebView.Source = authUrl; AuthWebView.Navigating += AuthWebView_Navigating; } private async void AuthWebView_Navigating(object sender, WebNavigatingEventArgs e) { if (e.Url.Contains("/api/auth/google-response")) { e.Cancel = true; var tokenResponse = await _httpClient.GetFromJsonAsync<TokenResponse>(e.Url); if (!string.IsNullOrEmpty(tokenResponse.Token)) { await SecureStorage.SetAsync("authToken", tokenResponse.Token); await _navigation.PushAsync(new MainPage()); } AuthWebView.Navigating -= AuthWebView_Navigating; } }
关键注意事项
- 密钥安全:Google Client ID/Secret仅存储在后端
appsettings.json,前端全程不接触。 - 跨域配置:若Blazor WASM独立部署,后端需配置CORS允许前端域名访问。
- MAUI权限:Android端需在
AndroidManifest.xml添加<uses-permission android:name="android.permission.INTERNET" />权限。 - Token存储:前端使用安全存储,Blazor用
Blazored.LocalStorage,MAUI用SecureStorage,避免明文存储。
内容的提问来源于stack exchange,提问作者Bobil
相关产品推荐
相关产品推荐

