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

.NET Core API+Angular+Keycloak的BFF架构CORS问题求解

问题分析与解决方案

核心问题原因

你遇到的CORS错误本质是AJAX请求无法跨域重定向到第三方登录页:Angular用HttpClient发起的AJAX请求收到API返回的302重定向后,浏览器会自动尝试跳转到Keycloak地址,但此时请求的源是Angular的http://localhost:4200,而Keycloak的登录页是HTML页面,不会返回符合要求的CORS响应头,浏览器因此拦截请求。

BFF模式下,登录流程应该是浏览器级别的页面跳转,而非AJAX请求,因为登录需要用户交互(输入账号密码),AJAX无法处理这类场景。


具体解决方案

1. 调整Angular的登录触发逻辑

放弃用HttpClient调用/api/auth/login,改为直接让浏览器导航到API的登录端点:

// Angular组件中的登录按钮点击事件
onLogin(): void {
  window.location.href = 'https://localhost:44315/api/auth/login';
}

这样浏览器会直接跳转到API的登录接口,后续重定向到Keycloak是浏览器原生跳转,不会触发CORS限制。

2. 修正.NET Core的中间件配置与认证流程

完善OpenID Connect认证配置

在Program.cs中配置Keycloak作为OpenID Connect身份提供者,同时启用Cookie认证(保存登录状态):

using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;

// ...

services.AddAuthentication(options =>
{
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie(options =>
{
    // 配置安全Cookie,防止XSS攻击
    options.Cookie.HttpOnly = true;
    options.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest; // 开发环境用SameAsRequest,生产改为Always
    options.Cookie.SameSite = SameSiteMode.Lax;
    options.ExpireTimeSpan = TimeSpan.FromHours(8);
})
.AddOpenIdConnect(options =>
{
    options.Authority = "http://localhost:8080/realms/xyz";
    options.ClientId = "你的Keycloak客户端ID";
    options.ClientSecret = "你的Keycloak客户端密钥"; // 若客户端类型为Confidential则必填,Public类型可省略
    options.ResponseType = "code";
    options.SaveTokens = true;
    options.CallbackPath = "/api/auth/callback"; // Keycloak登录成功后的回调路径
    options.SignedOutCallbackPath = "/api/auth/logout-callback";
    options.Scope.Add("openid");
    options.Scope.Add("profile");
});

// 保持原有CORS配置,但确保中间件顺序正确
services.AddCors(options =>
{
    options.AddPolicy("AllowAngularApp",
        builder => builder
            .WithOrigins("http://localhost:4200")
            .AllowAnyHeader()
            .AllowAnyMethod()
            .AllowCredentials());
});

// ...

// 中间件顺序必须严格遵循:Routing -> CORS -> Authentication -> Authorization -> Controllers
app.UseRouting();
app.UseCors("AllowAngularApp");
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();

新增回调端点

在Auth控制器中添加回调处理(无需额外代码,OpenID Connect中间件会自动处理授权码交换和Cookie设置):

[Route("api/auth")]
[ApiController]
public class AuthController : ControllerBase
{
    [HttpGet("login")]
    public IActionResult Login()
    {
        if (!User.Identity.IsAuthenticated)
        {
            return Challenge();
        }
        // 已登录则重定向回Angular首页
        return Redirect("http://localhost:4200");
    }

    [HttpGet("callback")]
    public async Task<IActionResult> Callback()
    {
        // OpenID Connect中间件自动处理授权码交换,此处可直接重定向回Angular
        return Redirect("http://localhost:4200");
    }

    [HttpGet("logout")]
    public async Task<IActionResult> Logout()
    {
        await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
        await HttpContext.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme);
        return Redirect("http://localhost:4200");
    }
}

3. 调整Keycloak配置

  • Valid Redirect URIs:新增https://localhost:44315/api/auth/callback,确保Keycloak能正确回调到API的认证端点
  • Web Origins:保留原有的https://localhost:44315和http://localhost:4200,允许Angular与API之间的跨域请求

BFF模式流程验证

  1. Angular页面点击登录按钮,浏览器跳转到https://localhost:44315/api/auth/login
  2. API检测到未认证,返回重定向到Keycloak登录页
  3. 用户完成登录后,Keycloak重定向到https://localhost:44315/api/auth/callback
  4. API处理授权码,交换令牌并设置HttpOnly认证Cookie,随后重定向回Angular首页
  5. Angular后续发起的所有业务请求都会自动携带Cookie,API验证Cookie后处理请求

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 14:07:18