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

如何在.NET项目中实现Postman式Keycloak授权流程?

.NET 对接 Keycloak 实现授权流程解决方案

一、控制台应用:交互式获取 Access Token

用Microsoft.Identity.Client(MSAL)实现和Postman一致的交互式授权流程,自动弹出浏览器引导登录:

  1. 安装NuGet包:Microsoft.Identity.Client
  2. 代码示例:
using Microsoft.Identity.Client;

var clientId = "你的Keycloak客户端ID";
var realmName = "你的Keycloak Realm名";
var authority = $"https://你的Keycloak地址/realms/{realmName}";
var redirectUri = "http://localhost:5000/callback"; // 需提前在Keycloak客户端配置中添加此地址

var app = PublicClientApplicationBuilder
    .Create(clientId)
    .WithAuthority(authority)
    .WithRedirectUri(redirectUri)
    .Build();

var scopes = new[] { "openid", "profile", "email" }; // 根据业务需求添加对应Scope

try
{
    var result = await app.AcquireTokenInteractive(scopes)
        .WithPrompt(Prompt.SelectAccount)
        .ExecuteAsync();

    Console.WriteLine($"Access Token: {result.AccessToken}");
}
catch (MsalException ex)
{
    Console.WriteLine($"获取Token失败: {ex.Message}");
}

二、.NET API:两种授权场景

场景1:保护API,仅允许携带合法Keycloak Token的请求访问

  1. 安装NuGet包:Microsoft.AspNetCore.Authentication.JwtBearer
  2. Program.cs配置:
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        options.Authority = $"https://你的Keycloak地址/realms/{realmName}";
        options.Audience = "你的API客户端ID"; // Keycloak中配置的API客户端ID
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true
        };
    });

builder.Services.AddAuthorization();

var app = builder.Build();

app.UseAuthentication();
app.UseAuthorization();

app.MapGet("/api/protected", () => "这是受Keycloak保护的API内容")
    .RequireAuthorization();

app.Run();

场景2:API自身调用其他受Keycloak保护的服务(获取Token)

用服务账户模式获取Token,无需用户交互:

using Microsoft.Identity.Client;

var clientId = "API客户端ID";
var clientSecret = "API客户端密钥"; // Keycloak客户端开启"服务账户"后生成
var authority = $"https://你的Keycloak地址/realms/{realmName}";
var targetScope = "目标服务的Scope";

var app = ConfidentialClientApplicationBuilder
    .Create(clientId)
    .WithClientSecret(clientSecret)
    .WithAuthority(authority)
    .Build();

var result = await app.AcquireTokenForClient(new[] { targetScope })
    .ExecuteAsync();

var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", result.AccessToken);

var response = await httpClient.GetAsync("https://目标服务地址/api/xxx");
var content = await response.Content.ReadAsStringAsync();

三、Razor WebApp:完整登录流程(修复未完成功能)

用ASP.NET Core内置的OpenID Connect中间件自动处理登录跳转、回调、Token存储,替代手动处理HTML的方式:

  1. 安装NuGet包:Microsoft.AspNetCore.Authentication.OpenIdConnect、Microsoft.AspNetCore.Authentication.Cookies
  2. Program.cs配置:
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.AddAuthentication(options =>
{
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect(options =>
{
    options.Authority = $"https://你的Keycloak地址/realms/{realmName}";
    options.ClientId = "WebApp客户端ID";
    options.ClientSecret = "WebApp客户端密钥"; // 保密客户端需配置,公开客户端可省略
    options.ResponseType = "code"; // 采用授权码流程,和Postman一致
    options.SaveTokens = true; // 将Token保存到Cookie
    options.Scope.Add("openid");
    options.Scope.Add("profile");
    options.Scope.Add("email");
    options.GetClaimsFromUserInfoEndpoint = true;
    options.CallbackPath = "/signin-oidc"; // 需在Keycloak客户端配置中添加此回调地址
});

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthentication();
app.UseAuthorization();

app.MapRazorPages();

app.Run();
  1. 登录/退出页面实现:
  • 在Index.cshtml添加登录入口:
@page
@using Microsoft.AspNetCore.Authentication

<div>
    @if (User.Identity.IsAuthenticated)
    {
        <p>欢迎, @User.Identity.Name!</p>
        <form method="post" asp-page="/Account/Logout">
            <button type="submit">退出登录</button>
        </form>
    }
    else
    {
        <a asp-page="/Account/Login">登录</a>
    }
</div>
  • 创建Account/Login.cshtml.cs:
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace WebApp.Pages.Account;

public class LoginModel : PageModel
{
    public async Task<IActionResult> OnGetAsync(string returnUrl = null)
    {
        await HttpContext.ChallengeAsync(OpenIdConnectDefaults.AuthenticationScheme, new AuthenticationProperties
        {
            RedirectUri = returnUrl ?? Url.Content("~/")
        });
        return new EmptyResult();
    }
}
  • 创建Account/Logout.cshtml.cs:
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace WebApp.Pages.Account;

public class LogoutModel : PageModel
{
    public async Task<IActionResult> OnPostAsync(string returnUrl = null)
    {
        await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
        await HttpContext.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme);
        return LocalRedirect(returnUrl ?? Url.Content("~/"));
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 22:43:16