当前位置:首页 > 技术 > 正文内容

ASP.NET Core Web API 集成 IdentityServer4 与 Swagger OAuth2 授权流程

访客 技术 2026年10月22日 1

在现代微服务架构中,API 安全性至关重要。本文将演示如何在 ASP.NET Core Web API 中集成 IdentityServer4 实现基于 OpenID Connect 的令牌认证,并通过 Swagger UI 提供交互式授权体验。整个方案采用内存存储配置,适用于开发与测试阶段。

一、搭建 IdentityServer4 认证中心

新建一个空的 ASP.NET Core Web 项目(目标框架 .NET Core 3.1 或更高版本),然后通过 NuGet 安装 IdentityServer4 和 IdentityServer4.Quickstart.UI:

dotnet add package IdentityServer4
dotnet add package IdentityServer4.Quickstart.UI

接着,在项目根目录执行以下命令以自动引入基础 UI 页面(登录页、授权页等):

dotnet is4ui

若该命令不可用,可手动克隆官方 Quickstart UI 并复制 Quickstart 文件夹至项目中,确保其包含 Controllers、Views 等子目录。

二、定义认证资源与客户端

创建 Configuration/IdentityConfig.cs 文件,封装资源配置逻辑:

using IdentityServer4.Models;
using System.Collections.Generic;

namespace AuthCenter.Configuration
{
    public static class IdentityConfig
    {
        public static IEnumerable<IdentityResource> IdentityScopes => new IdentityResource[]
        {
            new IdentityResources.OpenId(),
            new IdentityResources.Profile()
        };

        public static IEnumerable<ApiResource> ApiResources => new[]
        {
            new ApiResource("protected_api", "Protected Backend Service")
            {
                Scopes = { "api.read", "api.write" }
            }
        };

        public static IEnumerable<Client> Clients => new[]
        {
            new Client
            {
                ClientId = "swagger_client",
                ClientName = "Swagger Interactive Docs",
                AllowedGrantTypes = GrantTypes.Implicit,
                AllowAccessTokensViaBrowser = true,
                RedirectUris = { "http://localhost:5002/swagger/oauth2-redirect.html" },
                PostLogoutRedirectUris = { "http://localhost:5002/" },
                AllowedScopes = { "openid", "profile", "protected_api" },
                RequireConsent = false
            }
        };
    }
}

注意:此处将 API 资源拆分为更细粒度的作用域(api.read / api.write),便于后续权限控制扩展。

三、注册并启用 IdentityServer4

在 Startup.ConfigureServices 中注册服务:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();

    services.AddIdentityServer()
        .AddDeveloperSigningCredential()
        .AddInMemoryIdentityResources(IdentityConfig.IdentityScopes)
        .AddInMemoryApiResources(IdentityConfig.ApiResources)
        .AddInMemoryClients(IdentityConfig.Clients)
        .AddTestUsers(TestUsers.Users); // 内置测试用户:alice/bob
}

在 Configure 方法中启用中间件:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    app.UseStaticFiles();
    app.UseRouting();
    app.UseIdentityServer(); // 必须在 UseAuthentication 之前
    app.UseEndpoints(endpoints => endpoints.MapDefaultControllerRoute());
}

修改 launchSettings.json 将应用端口设为 5000,启动后访问 http://localhost:5000/.well-known/openid-configuration 可验证配置是否生效。

四、构建受保护的 API 服务

新建另一个 ASP.NET Core Web API 项目,安装以下 NuGet 包:

  • IdentityServer4.AccessTokenValidation
  • Swashbuckle.AspNetCore

在 Startup.ConfigureServices 中添加 JWT Bearer 认证支持:

services.AddAuthentication("Bearer")
    .AddJwtBearer("Bearer", options =>
    {
        options.Authority = "http://localhost:5000";
        options.Audience = "protected_api";
        options.RequireHttpsMetadata = false;
    });

services.AddAuthorization(options =>
{
    options.AddPolicy("ReadScope", policy =>
        policy.RequireClaim("scope", "api.read"));
    options.AddPolicy("WriteScope", policy =>
        policy.RequireClaim("scope", "api.write"));
});

五、集成 Swagger 并启用 OAuth2 登录

配置 Swagger 以支持隐式授权流:

services.AddSwaggerGen(c =>
{
    c.SwaggerDoc("v1", new OpenApiInfo { Title = "Secure API", Version = "v1" });

    c.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
    {
        Type = SecuritySchemeType.OAuth2,
        Flows = new OpenApiOAuthFlows
        {
            Implicit = new OpenApiOAuthFlow
            {
                AuthorizationUrl = new Uri("http://localhost:5000/connect/authorize"),
                Scopes = new Dictionary<string, string>
                {
                    { "api.read", "Read protected data" },
                    { "api.write", "Modify protected data" }
                }
            }
        }
    });

    c.OperationFilter<SecurityRequirementsOperationFilter>();
});

// 自定义过滤器:为标记 [Authorize] 的操作注入安全要求
public class SecurityRequirementsOperationFilter : IOperationFilter
{
    public void Apply(OpenApiOperation operation, OperationFilterContext context)
    {
        var authAttributes = context.MethodInfo.GetCustomAttributes(true)
            .Union(context.MethodInfo.DeclaringType.GetCustomAttributes(true))
            .OfType<AuthorizeAttribute>();

        if (authAttributes.Any())
        {
            operation.Security = new List<OpenApiSecurityRequirement>
            {
                new OpenApiSecurityRequirement
                {
                    {
                        new OpenApiSecurityScheme
                        {
                            Reference = new OpenApiReference
                            {
                                Type = ReferenceType.SecurityScheme,
                                Id = "oauth2"
                            }
                        },
                        new[] { "api.read" } // 默认作用域
                    }
                }
            };
        }
    }
}

在 Configure 方法中启用中间件:

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

app.UseSwagger();
app.UseSwaggerUI(c =>
{
    c.SwaggerEndpoint("/swagger/v1/swagger.json", "Secure API v1");
    c.OAuthClientId("swagger_client");
    c.OAuthAppName("Secure API - Interactive Docs");
    c.OAuthUseBasicAuthenticationWithAccessCodeGrant();
});

将 API 项目端口设为 5002(需与 IdentityServer 中 RedirectUris 一致),启动后访问 http://localhost:5002/swagger 即可见 "Authorize" 按钮。

六、控制器示例与权限控制

在 API 控制器中使用策略或作用域进行细粒度控制:

[ApiController]
[Route("api/[controller]")]
public class DataController : ControllerBase
{
    [HttpGet("public")]
    public IActionResult GetPublic() => Ok("This endpoint requires no auth.");

    [HttpGet("restricted")]
    [Authorize(Policy = "ReadScope")]
    public IActionResult GetRestricted() => Ok("You have 'api.read' scope.");

    [HttpPost("update")]
    [Authorize(Policy = "WriteScope")]
    public IActionResult UpdateData() => Ok("Write access granted.");
}

当调用带 [Authorize] 特性的接口时,Swagger 会显示锁形图标;点击 Authorize 后跳转至 IdentityServer 登录页,成功后自动携带 Access Token 发起请求,响应头中将包含 Authorization: Bearer <token>。

相关文章

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

linux screen 用法详情 (nohup 的替代方案)

一、screen 是什么?能干嘛?screen 是一个终端复用器,可以:在一个 SSH 会话中开多个“虚拟终端”SSH 断线后,程序仍然在后台运行随时重新连接到原来的会话特别适合:nohup 的替代方案跑脚本 / 爬虫 / 训练模型运维、远程开发二、安装 screen# CentOS / Rocky / Almayum install -y screen# Debian / Ubuntuapt i...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。