.NET调用FCM V1 API发通知遇APNS/Web Push认证错误求助
问题描述
我正在尝试使用Firebase Cloud Messaging API (V1)发送通知,React应用中使用相同项目配置能正常生成设备令牌,但在.NET API项目发送消息时,抛出APNS或Web推送服务认证错误。已确认账号具备全部权限,仍未找到问题根源,请求帮忙排查。
相关代码
发送通知的Action方法
[HttpPost("notification")] public async Task<IActionResult> SendMessage(SingleMessageRequest request) { var messaging = FirebaseMessaging.DefaultInstance; if (messaging == null) { notificationService.GetFirebaseApp(); messaging = FirebaseMessaging.DefaultInstance; } var message = new Message() { Data = new Dictionary<string, string>() { ["Name"] = request.data.Name, ["Email"] = request.data.Email }, Notification = new FirebaseAdmin.Messaging.Notification { Title = request.notification.title, Body = request.notification.body }, Token = request.token, //Topic = request.topic }; var result = await messaging.SendAsync(message); return new OkObjectResult(result); }
Firebase配置服务
public interface INotificationService { public FirebaseApp GetFirebaseApp(); } public class NotificationService : INotificationService { public FirebaseApp GetFirebaseApp() { var credentials = FirebaseApp.Create(new AppOptions() { Credential = GoogleCredential.FromFile(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "key.json")), }); return credentials; } }
错误详情
FirebaseAdmin.Messaging.FirebaseMessagingException: Auth error from APNS or Web Push Service at FirebaseAdmin.Util.ErrorHandlingHttpClient`1.SendAndReadAsync(HttpRequestMessage request, CancellationToken cancellationToken) at FirebaseAdmin.Util.ErrorHandlingHttpClient`1.SendAndDeserializeAsync[TResult](HttpRequestMessage request, CancellationToken cancellationToken) at FirebaseAdmin.Messaging.FirebaseMessagingClient.SendAsync(Message message, Boolean dryRun, CancellationToken cancellationToken) at FirebaseAdmin.Messaging.FirebaseMessaging.SendAsync(Message message, Boolean dryRun, CancellationToken cancellationToken) at FirebaseAdmin.Messaging.FirebaseMessaging.SendAsync(Message message, Boolean dryRun) at FirebaseAdmin.Messaging.FirebaseMessaging.SendAsync(Message message) at FirebaseCloudMessagingPOC.Controllers.NotificationController.SendMessage(SingleMessageRequest request) in C:\Users\Vijay.Parmar\source\repos\FirebaseCloudMessagingPOC\FirebaseCloudMessagingPOC\Controllers\NotificationController.cs:line 73 at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|20_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope) at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger) at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context) at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext) at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider) at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
排查方案
修复Firebase App初始化逻辑
现有代码每次调用GetFirebaseApp都会创建新实例,会导致凭证冲突。修改为优先复用已有实例:public FirebaseApp GetFirebaseApp() { try { return FirebaseApp.DefaultInstance; } catch { var credentials = FirebaseApp.Create(new AppOptions() { Credential = GoogleCredential.FromFile(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "key.json")), }); return credentials; } }验证key.json有效性
确认文件路径正确,private_key和client_email字段未被篡改;检查该服务账号在Firebase控制台项目设置>服务账号中存在,且已启用Cloud Messaging API权限。APNS配置检查(iOS设备)
若推送iOS设备,确认Firebase控制台项目设置>云消息传递中APNs认证配置正确:上传有效证书或配置APNs密钥,且密钥包含推送权限;同时验证设备令牌环境(开发/生产)与API使用的key.json环境一致。Web Push配置检查(Web设备)
若推送Web应用,确认Firebase控制台项目设置>云消息传递中Web推送证书配置正确,且React端使用的vapidKey与控制台一致;检查服务账号在Google Cloud控制台IAM>权限中拥有firebase.messaging相关权限。测试dry-run模式
开启dry-run模式模拟发送流程,定位是认证还是消息格式问题:var result = await messaging.SendAsync(message, dryRun: true);检查网络连通性
确认.NET API服务器能正常访问https://fcm.googleapis.com,未被防火墙或代理拦截。
内容的提问来源于stack exchange,提问作者Vijay Parmar

