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

如何解决从Azure Function调用需Cookie认证的Blazor应用的认证问题?

Azure Function通过SignalR向Cookie认证的Blazor Server发送通知的最优方案

方案1:让Azure Function获取Blazor Server的认证Cookie

  • 核心思路:通过MSAL获取针对Blazor Server应用的id_token,调用Blazor Server自定义端点兑换出认证Cookie,再携带Cookie连接SignalR Hub发送通知。
  • 具体实现:
    1. 在Blazor Server的Program.cs中新增Cookie兑换端点(基于现有认证配置扩展):
      // 保留原有认证配置
      services.AddMicrosoftIdentityWebAppAuthentication(Configuration)
              .EnableTokenAcquisitionToCallDownstreamApi()
              .AddInMemoryTokenCaches();
      
      // 添加Cookie兑换API端点
      app.MapGet("/api/exchangecookie", async (HttpContext context, IConfiguration config) =>
      {
          var idToken = context.Request.Query["id_token"].ToString();
          if (string.IsNullOrEmpty(idToken)) return Results.BadRequest("缺少id_token");
      
          // 验证id_token有效性
          var validator = context.RequestServices.GetRequiredService<ISecurityTokenValidator>();
          try
          {
              ClaimsPrincipal principal = validator.ValidateToken(idToken,
                  new TokenValidationParameters
                  {
                      ValidAudience = config["AzureAd:ClientId"],
                      ValidIssuer = $"https://login.microsoftonline.com/{config["AzureAd:TenantId"]}/v2.0",
                      ValidateLifetime = true,
                      ValidateIssuerSigningKey = true
                  }, out _);
      
              // 生成并返回认证Cookie
              await context.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal);
              var authCookie = context.Response.Cookies.FirstOrDefault(c => c.Key.StartsWith(CookieAuthenticationDefaults.CookiePrefix));
              return Results.Ok(new { Name = authCookie.Key, Value = authCookie.Value });
          }
          catch
          {
              return Results.Unauthorized();
          }
      }).RequireAuthorization(policy => 
          policy.RequireClaim("azp", "<Azure Function的ClientId>")); // 限制仅Function服务主体访问
      
    2. Azure Function中获取id_token、兑换Cookie并连接SignalR:
      var client = new ConfidentialClientApplicationBuilder("<Function ClientId>", "<Function ClientSecret>")
          .WithAuthority($"https://login.microsoftonline.com/<TenantId>/v2.0")
          .Build();
      var tokenResult = await client.AcquireTokenForClient(new[] { "<Blazor Server ClientId>/.default" })
          .ExecuteAsync();
      
      // 调用兑换Cookie端点
      var httpClient = new HttpClient();
      var cookieResponse = await httpClient.GetFromJsonAsync<CookieDto>(
          $"<Blazor Server域名>/api/exchangecookie?id_token={tokenResult.IdToken}");
      
      // 携带Cookie连接SignalR Hub
      var hubConnection = new HubConnectionBuilder()
          .WithUrl("<Blazor Server域名>/notificationHub", options =>
          {
              options.Cookies.Add(new Cookie(cookieResponse.Name, cookieResponse.Value));
          })
          .Build();
      await hubConnection.StartAsync();
      await hubConnection.SendAsync("SendNotification", "来自Azure Function的通知");
      

方案2:修改Blazor Server的SignalR Hub支持双重认证(Cookie + Bearer)

  • 核心思路:让Blazor Server的SignalR Hub同时接受Cookie认证(适配Blazor客户端)和Bearer令牌认证(适配Azure Function),无需额外兑换Cookie。
  • 具体实现:
    1. 在Blazor Server的Program.cs中添加Bearer认证支持:
      // 保留原有Cookie认证配置
      services.AddMicrosoftIdentityWebAppAuthentication(Configuration)
              .EnableTokenAcquisitionToCallDownstreamApi()
              .AddInMemoryTokenCaches();
      
      // 添加Bearer认证
      services.AddAuthentication()
          .AddJwtBearer(options =>
          {
              options.Authority = $"https://login.microsoftonline.com/{Configuration["AzureAd:TenantId"]}/v2.0";
              options.Audience = Configuration["AzureAd:ClientId"];
              options.TokenValidationParameters = new TokenValidationParameters
              {
                  ValidateIssuer = true,
                  ValidateAudience = true,
                  ValidateLifetime = true
              };
              // 配置SignalR读取URL中的access_token
              options.Events = new JwtBearerEvents
              {
                  OnMessageReceived = context =>
                  {
                      var accessToken = context.Request.Query["access_token"];
                      var path = context.HttpContext.Request.Path;
                      if (!string.IsNullOrEmpty(accessToken) && path.StartsWithSegments("/notificationHub"))
                      {
                          context.Token = accessToken;
                      }
                      return Task.CompletedTask;
                  }
              };
          });
      
      // 配置SignalR Hub允许两种认证方式
      app.MapHub<NotificationHub>("/notificationHub")
          .RequireAuthorization(options =>
          {
              options.AddPolicy("SignalRPolicy", policy =>
              {
                  policy.AuthenticationSchemes.Add(CookieAuthenticationDefaults.AuthenticationScheme);
                  policy.AuthenticationSchemes.Add(JwtBearerDefaults.AuthenticationScheme);
                  policy.RequireAuthenticatedUser();
              });
          });
      
    2. Azure Function中获取Bearer令牌并连接SignalR:
      var client = new ConfidentialClientApplicationBuilder("<Function ClientId>", "<Function ClientSecret>")
          .WithAuthority($"https://login.microsoftonline.com/<TenantId>/v2.0")
          .Build();
      var tokenResult = await client.AcquireTokenForClient(new[] { "<Blazor Server ClientId>/.default" })
          .ExecuteAsync();
      
      var hubConnection = new HubConnectionBuilder()
          .WithUrl("<Blazor Server域名>/notificationHub", options =>
          {
              options.AccessTokenProvider = () => Task.FromResult(tokenResult.AccessToken);
          })
          .Build();
      await hubConnection.StartAsync();
      await hubConnection.SendAsync("SendNotification", "来自Azure Function的通知");
      

方案3:使用Azure SignalR Service作为中间层(推荐)

  • 核心思路:将SignalR的连接管理交给Azure SignalR Service,分别为Blazor Server(Cookie认证)和Azure Function(Bearer认证)配置适配的认证规则,由云服务处理兼容逻辑,无需自定义认证兼容代码。
  • 具体实现:
    1. 在Azure Portal创建Azure SignalR Service,记录连接字符串。
    2. Blazor Server配置接入Azure SignalR Service,保留原有Cookie认证:
      services.AddSignalR()
          .AddAzureSignalR(Configuration["AzureSignalR:ConnectionString"]);
      
      // 原有认证配置不变
      services.AddMicrosoftIdentityWebAppAuthentication(Configuration)
              .EnableTokenAcquisitionToCallDownstreamApi()
              .AddInMemoryTokenCaches();
      
    3. Azure Function配置SignalR输出绑定,发送通知:
      • 在local.settings.json中添加Azure SignalR连接字符串和Azure AD配置:
        {
            "Values": {
                "AzureSignalRConnectionString": "<Azure SignalR连接字符串>",
                "AzureAd:ClientId": "<Function ClientId>",
                "AzureAd:TenantId": "<TenantId>",
                "AzureAd:ClientSecret": "<Function ClientSecret>"
            }
        }
        
      • 创建发送通知的Function:
        [FunctionName("SendNotification")]
        public static async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)] HttpRequest req,
            [SignalR(HubName = "notificationHub")] IAsyncCollector<SignalRMessage> signalRMessages,
            ILogger log)
        {
            // 可选:验证Function的调用者身份
            var authHeader = req.Headers["Authorization"].FirstOrDefault();
            if (!string.IsNullOrEmpty(authHeader) && authHeader.StartsWith("Bearer "))
            {
                var token = authHeader.Substring(7);
                // 此处添加token验证逻辑
            }
        
            await signalRMessages.AddAsync(new SignalRMessage
            {
                Target = "ReceiveNotification",
                Arguments = new[] { "来自Azure Function的通知(通过SignalR Service)" }
            });
        
            return new OkResult();
        }
        
    4. Blazor Server的SignalR Hub无需修改,客户端将自动连接到Azure SignalR Service,保持原有Cookie认证流程。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 09:15:38