news 2026/9/9 9:20:12

.NET 8 + Azure 登录 + Ant Design Blazor 企业身份认证实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
.NET 8 + Azure 登录 + Ant Design Blazor 企业身份认证实战

简介:这是一套面向.NET开发者的后台管理框架案例,基于.NET 8与Azure登录集成,采用Ant Design Blazor构建主界面,并考虑了常见后台管理场景。框架运行在Blazor Server模式下,实现了菜单导航、路由跳转,以及本地JSON文件的读取与修改,适合需要快速搭建企业级后台系统、或希望系统学习Blazor与Azure认证集成的初中级.NET开发人员参考。资源包共含147个文件,压缩包大小3.57MB,其中62个dll程序集支撑运行依赖、26个json用于配置、9个cs与9个razor展示核心逻辑和页面结构,另有css样式、svg图标、props工程文件等,整体目录结构清晰。这些文件方便直接还原项目环境开展二次开发。目前已有280人学习下载,通过该框架,开发者可理清Azure登录流程与Blazor Server导航路由的配置方法,掌握Ant Design Blazor组件的使用技巧,并可直接复用JSON配置读写功能,作为新项目的基础脚手架或技术验证样例。 最近接了个活,要给一套企业内部工具加上统一的身份认证,前端用 Blazor,后端打算跑在 .NET 8 上。选型的时候没怎么犹豫:认证直接走 Azure 登录(Microsoft Entra ID),UI 组件用了 Ant Design Blazor。这套组合跑通之后,整体体验相当顺,这里把完整的落地过程、踩坑记录和关键代码都整理出来,给正在做类似选型的朋友一个参考。

1. 项目背景与整体方案拆解

1.1 为什么是 .NET 8 + Azure 登录 + Ant Design Blazor

先说结论:这三个东西组合在一起,解决的是“从零搭一套带企业身份认证的现代化 Web 应用”这个刚需问题。

.NET 8 是微软当前的主力 LTS 版本,支持 Blazor WebAssembly 和 Blazor Server 两种托管模型。我这次用的是 Blazor WebAssembly(Wasm),因为前端需要较强的交互性,而且部署环境允许纯静态托管,可以跟后端 API 分开走。如果你对内网延迟敏感,也可以考虑 Blazor Server,但后文代码里大部分认证逻辑是通用的。

Azure 登录,也就是 Microsoft Entra ID(老的 Azure AD),企业场景里几乎绕不开。用户已经在 Microsoft 365 / Office 365 里有账号,直接用它当身份源,省掉了自建用户体系的麻烦。OAuth 2.0 / OpenID Connect 协议是标准流程,.NET 官方库支持得很好。

Ant Design Blazor 则是把 Ant Design 的设计语言搬到 Blazor 生态里。Ant Design 在 React 圈子里早就验证过了,组件审美在线、交互齐全。Blazor 版本虽然没 React 那么成熟,但常用的 Table、Form、Layout、Menu 等质量完全够用,而且组件是 C# 写的,跟前端逻辑不用来回切语言。

这三个组合在一起,最大的价值是“全栈 C#”:前端 C#、后端 C#、认证走标准协议,团队成员只要会 C# 就能完整把控整个链路,不用引入第二门语言。

1.2 这套方案适合什么样的项目

如果你的项目符合下面几条,那这套组合会很舒服:

  • 用户身份已经存在于 Microsoft 365 / Entra ID 中,希望实现单点登录(SSO)。
  • 团队以 .NET 技术栈为主,不希望前端引入繁重的 JS 框架。
  • 需要一个开箱即用的中后台 UI 组件库,Table、Form、布局都要好看且功能完整。
  • 需要对接 Azure 上的其他资源(如 Azure OpenAI、Storage、Graph API),登录凭证可以复用。

反过来说,如果你的用户是外部 C 端消费者,没有微软账号体系,那 Azure 登录就不是最优解,建议直接走 ASP.NET Core Identity + 外部登录提供商。

2. Azure 登录的前置准备

2.1 在 Azure 门户创建应用注册

这个步骤是整套流程的“钥匙”,注册错了后面全白搭。登录 Azure 门户,打开“Microsoft Entra ID”,进入“应用注册”,点击“新注册”。

这里有几个关键字段:

  • 名称:填个应用名,比如MyBlazorApp,对用户可见。
  • 受支持的帐户类型:如果你只在企业内部用,选“仅此组织目录中的帐户”;如果还要支持微软个人账号或其他组织的账号,选“任何组织目录中的帐户”。我这次是在企业内部,选的第一项。
  • 重定向 URI:这一步必须现在就填,否则登录成功后会报AADSTS50011错误。平台选“单页应用程序 (SPA)”或“Web”,URI 填写你的应用实际地址。Blazor WebAssembly 通常用 SPA 类型;Blazor Server 用 Web 类型。

我用的地址是https://localhost:7001/authentication/login-callback,这是 Blazor 默认的回调路径,端口需要跟你实际跑起来的一致。

2.2 配置 API 权限与客户端凭据

注册完成后,进入“公开 API”或“API 权限”菜单,给应用添加权限。如果你是纯前端登录,不加受保护 API,那只需要默认的User.Read(读取用户基本信息)就够了。但企业内部工具往往还要调用自己的 Web API,此时需要在应用中暴露一个作用域(Scope),例如api://my-blazor-app/access_as_user

具体操作:在“公开 API”中点击“添加范围”,范围名称填access_as_user,然后选择谁可以同意。接着在“API 权限”中“添加权限”,切换到“我的 API”页签,选中刚刚暴露的 Scope,这样就完成了前后端的权限关联。

还要注意“客户端凭据”:如果前端是纯 SPA,用授权码 + PKCE 流程,不需要客户端密码。微软推荐 SPA 不走 Authorization Code + PKCE,所以不需要创建 client secret。这一点很多资料会误导你去生成密钥,其实没必要,反而有泄露风险。

3. Blazor 与 Ant Design 的整合细节

3.1 建立 .NET 8 Blazor WebAssembly 项目

我用的是 .NET 8 SDK,直接用 dotnet CLI 创建项目:

dotnet new blazorwasm-empty -n BlazorAzureAntd -o . dotnet add package Microsoft.Authentication.WebAssembly.MSAL dotnet add package AntDesign dotnet add package Microsoft.AspNetCore.Components.WebAssembly.Authentication

blazorwasm-empty模板比带 UI 的模板干净,不会有一堆示例代码干扰。加了包之后,需要在Program.cs里注册服务:

using Microsoft.AspNetCore.Components.Web; using Microsoft.AspNetCore.Components.WebAssembly.Hosting; using BlazorAzureAntd; using Microsoft.AspNetCore.Components.WebAssembly.Authentication; using AntDesign; var builder = WebAssemblyHostBuilder.CreateDefault(args); builder.RootComponents.Add<App>("#app"); builder.RootComponents.Add<HeadOutlet>("head::after"); builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) }); builder.Services.AddMsalAuthentication(options => { builder.Configuration.Bind("AzureAd", options.ProviderOptions.Authentication); options.ProviderOptions.LoginMode = "redirect"; options.ProviderOptions.DefaultAccessTokenScopes.Add("api://my-blazor-app/access_as_user"); }); builder.Services.AddAntDesign(); await builder.Build().RunAsync();

注意AddMsalAuthentication是微软提供的 MSAL 集成,它自动处理了授权码流程和 token 的存储刷新。LoginMode我用的是 redirect 而不是 popup,因为有些浏览器对弹窗拦截比较严格,redirect 模式更稳。

3.2 引入 AntDesign 样式与交互

index.html里加入 AntDesign 的静态资源:

<link href="_content/AntDesign/css/ant-design-blazor.css" rel="stylesheet" /> <script src="_content/AntDesign/js/ant-design-blazor.js"></script>

然后在根组件App.razor里包一层ConfigProvider,可以设置全局语言和其他主题配置:

<ConfigProvider> <CascadingAuthenticationState> <Router AppAssembly="@typeof(App).Assembly"> <Found Context="routeData"> <AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" /> <FocusOnNavigate RouteData="@routeData" Selector="h1" /> </Found> <NotFound> <LayoutView Layout="@typeof(MainLayout)"> <Result Status="404" Title="404" SubTitle="页面不存在" /> </LayoutView> </NotFound> </Router> </CascadingAuthenticationState> </ConfigProvider>

这里最核心的是CascadingAuthenticationStateAuthorizeRouteView,它们负责把登录状态传下去,并在未授权时触发跳转登录。

4. 实现 Azure 登录:后端与前端的关键代码

4.1 配置 appsettings.json 里的 AzureAd 节点

wwwroot/appsettings.json中配置:

{ "AzureAd": { "Authority": "https://login.microsoftonline.com/你的租户ID", "ClientId": "你的应用客户端ID", "ValidateAuthority": true } }

一个坑点:上面我是在Program.cs里用builder.Configuration.Bind("AzureAd", options.ProviderOptions.Authentication)绑定的。因为 Blazor WebAssembly 运行在浏览器里,配置文件必须放在wwwroot下,而不是项目根目录。很多人直接把appsettings.json放根目录,结果运行时报找不到配置。另外,你的“租户ID”可以在 Azure 门户的应用注册概览页找到,是一串 GUID。

4.2 登录组件与用户状态显示

接下来做一个简单的登录/登出组件。我习惯在MainLayout的顶部导航栏放用户状态:

@using Microsoft.AspNetCore.Components.Authorization @using Microsoft.AspNetCore.Components.WebAssembly.Authentication @inject NavigationManager Navigation @inject AuthenticationStateProvider AuthProvider <AuthorizeView> <Authorized> <Space> <Avatar Style="background-color:#1890ff" Icon="user" /> <span>@context.User.Identity?.Name</span> <Button Type="primary" Danger OnClick="Logout">退出</Button> </Space> </Authorized> <NotAuthorized> <Button Type="primary" OnClick="Login">登录</Button> </NotAuthorized> </AuthorizeView> @code { private void Login() { Navigation.NavigateToLogin("authentication/login"); } private void Logout() { Navigation.NavigateToLogout("authentication/logout"); } }

这里用了 Blazor 内置的AuthorizeView组件,登录后context.User.Identity.Name是用户的主邮箱或 UPN,可以直接展示。NavigateToLoginNavigateToLogout是扩展方法,来自Microsoft.AspNetCore.Components.WebAssembly.Authentication命名空间,它们会自动拼接完整的 OAuth 登录/登出地址。

4.3 调用受保护 API 的 Token 处理

纯登录型应用太少见了,多数场景是要带上 token 去调用后端 API。Blazor WebAssembly 里可以用AccessTokenProvider拿到 token,然后手动塞进 HttpClient 的 Authorization 头:

using Microsoft.AspNetCore.Components.WebAssembly.Authentication; public class ApiService : IApiService { private readonly HttpClient _http; private readonly IAccessTokenProvider _tokenProvider; public ApiService(HttpClient http, IAccessTokenProvider tokenProvider) { _http = http; _tokenProvider = tokenProvider; } public async Task<string> GetDataAsync() { var tokenResult = await _tokenProvider.RequestAccessToken(); if (tokenResult.TryGetToken(out var token)) { var request = new HttpRequestMessage(HttpMethod.Get, "api/data"); request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token.Value); var response = await _http.SendAsync(request); response.EnsureSuccessStatusCode(); return await response.Content.ReadAsStringAsync(); } throw new InvalidOperationException("无法获取访问令牌"); } }

注意TryGetToken如果返回 false,说明 token 刷新失败或用户已退出,这时候应该引导用户重新登录,而不是默默返回空数据。

后端 API 这边,如果你是用 .NET 8 的 Minimal API 或 Controller,需要配置 JWT Bearer 认证,校验 token 的 issuer 和 audience。最简单的做法是加一个Microsoft.Identity.Web包,它跟 Azure 的集成度最高:

dotnet add package Microsoft.Identity.Web

然后在后端Program.cs里:

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd")); builder.Services.AddAuthorization();

后端配置的AzureAd节点里要有ClientIdTenantId,以及刚才在前端暴露的 Scope 对应的Audience(比如api://my-blazor-app)。这样前端拿到的 token 才能通过后端的鉴权验证。

5. 常见问题与排查技巧

我在这次开发中至少踩了下面这几个坑,有些问题查了挺久才定位到原因,整理成表格给大家参考。

异常信息原因分析解决办法
AADSTS50011: The reply URL specified in the request does not match重定向 URI 没注册或填错,常见于端口号变化登录 Azure 门户,在应用注册的“重定向 URI”中加入当前实际地址
LoginError: No account found with the requested ID缓存了旧的登录账号,或租户 ID 配置错误清除浏览器缓存 / 退出所有账号后重新登录;检查 appsettings 中租户 ID 是否属于该应用所在目录
Failed to load resource: ... 401后端 API 没有配置 JWT 认证,或 audience 不一致后端加.AddMicrosoftIdentityWebApi,确认 Scope 的api://前缀和前端 DefaultAccessTokenScopes 一致
Ant Design 组件无样式缺少 CSS 引用,或静态资源路径不对检查index.html中是否引入ant-design-blazor.css
JS 互操作报错AntDesign 的 JS 文件未加载,或加载顺序靠后确保<script src="_content/AntDesign/js/ant-design-blazor.js"></script>放在app.js之前
Unauthorised但 token 拿到了后端校验的 issuer/audience 不匹配用 jwt.ms 解码 token,对比前端和后端配置的 ClientId、TenantId 是否一致

5.1 一个典型的 AADSTS50011 排查过程

举个例子,我第一次配重定向 URI 时,没注意 IIS Express 会随机更换端口,导致每次重启端口都在变。后来干脆固定了启动端口:

Properties/launchSettings.json里设置:

"applicationUrl": "https://localhost:7001"

然后把7001端口提前注册到 Azure 门户。这样不管怎么重启,回调地址都是稳定的。如果你还是遇到 50011,优先检查回调 URL 的 protocol、host、port 是否与代码里导航到的完全一致,连末尾的斜杠都不能差。

5.2 交互卡在登录页循环跳转

还有一次登录流程陷入了“登录 → 回调 → 又跳转登录”的死循环。排查后发现是AuthorizationMessageHandler配置了自定义的 HttpClient,但这个 handler 默认会拼接defaultAccessTokenScopes,如果 API 的作用域和前端配置的 scope 不一致,token 请求失败,于是始终拿不到用户身份。

解决方法是给DefaultAccessTokenScopes指定明确的 scope 字符串,并保证后端注册的 API 作用域完全匹配。如果不确定,可以先在登录后把 token 打印出来,在 https://jwt.ms 上解码查看audscp字段,再对照后端配置。

6. 实操心得与补充建议

这套 .NET 8 + Azure 登录 + Ant Design Blazor 的组合,我跑下来整体是稳的,但也有几个地方想单独多说一句。

6.1 版本兼容性要小心

Ant Design Blazor 对 .NET 8 的支持是从 0.15+ 版本开始的,早期 0.14 以下版本可能只适配 .NET 6/7。建议直接用 NuGet 上的最新稳定版,我写这篇时 1.0 正式版已经发布,API 和旧版有一些差异,网上很多旧教程的代码可能跑不起来。如果你从旧项目升级,重点检查TableData参数、FormLabelCol/WrapperCol是否改成子组件写法。

6.2 托管方式影响很大

如果是 Blazor WebAssembly 模式,发布后是静态文件,可以放任意 CDN。但 Azure 登录要求回调地址必须是 HTTPS,所以本地调试要开 HTTPS,生产环境也别忘了绑定证书。如果是 Blazor Server 模式,登录流程会走服务端,很多配置和端上模式不同,不要硬套本文代码。

6.3 多租户场景提前规划

如果应用要被多个组织的 Microsoft 账号登录,Azure 应用注册里的“支持的帐户类型”要选择“任何组织目录”,代码里Authority要从租户 ID 改为commonorganizations。这样能省去后续改架构的麻烦。但多租户场景下 token 的验证逻辑更复杂,需要用tenantid字段做租户隔离,这块务必提前设计。

6.4 别忘了用户体验

登录体验上,Ant Design Blazor 的SpinResult组件很好用。在登录跳转的过程中,我会在根页面放一个全屏Spin遮罩,避免用户误以为页面卡住。另外,登录失败的页面用Result组件展示具体错误码,方便用户自行反馈,而不是白屏。

最后分享一个我自己的小习惯:Azure 应用注册里每个环境(开发、测试、生产)单独建一个应用注册,虽然多了几步操作,但环境间配置隔离明确,不会出现改了测试环境配置导致生产登录异常的问题。个人项目的认证配置看似简单,一旦环境多了,混乱是必然的,提前隔离能省很多心。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/9 9:20:08

K8s节点监控与告警体系实战:从指标采集到故障复盘

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/9 9:19:37

WorkMate部署与人机协同:供应链AI应用实战解析

兆企供应链管理AI应用白皮书&#xff08;二&#xff09;&#xff1a;WorkMate的部署与人机协同 身边不少做供应链的朋友这段时间都在聊同一个东西&#xff1a;AI Agent到底能不能在真实的采购、库存、物流协同场景里落地&#xff0c;而不是停留在“演示很惊艳&#xff0c;用起…

作者头像 李华
网站建设 2026/9/9 9:19:22

MC20E OPEN AT开发实战:从SDK搭建到低功耗定位追踪

简介&#xff1a;移远 MC20E OPEN AT SDK 是一套为该型号物联网通信模块打造的嵌入式开发工具包&#xff0c;适用于智能抄表、远程监控、车载追踪等不同行业的物联网应用开发者。它基于开放的 AT 指令体系&#xff0c;将底层硬件驱动、网络协议栈、数据收发等能力进行完整封装&…

作者头像 李华
网站建设 2026/9/9 9:18:43

CMSIS-5本质是嵌入式软硬件协同契约

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/9 9:18:40

Hadoop+Spark+Python租房大数据分析可视化系统实战

说个老实话&#xff0c;把 Hadoop、Spark、Python 这三样东西凑到一个项目里&#xff0c;最难的不是单个技术&#xff0c;而是怎么让它们各司其职又配合默契。今天要聊的这套租房大数据分析可视化系统&#xff0c;就是把“Python 采集数据、Hadoop 存数据、Spark 算数据、前端看…

作者头像 李华
网站建设 2026/9/9 9:18:13

多智能体框架怎么选?LangGraph、AutoGen与CrewAI选型指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华