Blazor 下支持 Azure AD 的多套登录方案

比如上图配置了两套不同的登录方案,各有自己的 TenantId 和 ClientId ,要同时支持他们的登录(其实在同一套 TenantId 和 ClientId 里面配置多个登录账户不就好了,但是......那套登录的管理是在客户自己的Azure AD账户管理下的,而作为技术支持不想麻烦客户,更何况客户不一定同意呢,所以需要第二套专为技术支持提供的用户组......那么就自己再弄一套吧)

然后问题就来了,在Blazor 页面要触发验证需要调用 HttpContext.ChallengeAsync,你可以试试在.razor 组件内调用 HttpContextAccessor.HttpContext.ChallengeAsync 会发生什么......
当你执行的时候,由于Blazor 使用的是 WebSocket 所以这个 Http 的处理方式就报错了,说你的请求头有问题,是不是很无语?

那么怎么解决这个问题呢?在Asp.net Core 3.0 就加入了 EndPoints 终结点的概念,看一下 ChatGPT 是怎么说的

由此看来 EndPoints 可以自定义的控制路由访问,比Controller更加强大

所以这个时候搞明白一件事情,对于多个 oidc 的登录,需要自己用一特定路由地址来实现

这个工作都在 StartUp 里完成,只列出核心代码

1. 注册两套 OIDC 登录方案,注意他们的 CallbackPath  不能是一样的

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

            services.AddRazorPages();
            services.AddServerSideBlazor();

            // Configure authentication
            var authorityFormat = Configuration["AzureAd:Authority"];
            var callbackPath = Configuration["AzureAd:CallbackPath"];

            services.AddAuthentication(options =>
            {
                options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            })
            .AddCookie()
            .AddOpenIdConnect(_customerAuthType, options =>
            {
                options.Authority = string.Format(CultureInfo.InvariantCulture, authorityFormat, Configuration[$"AzureAd:{_customerAuthType}:TenantId"]);
                options.ClientId = Configuration[$"AzureAd:{_customerAuthType}:ClientId"];
                options.CallbackPath = Configuration[$"AzureAd:{_customerAuthType}:CallbackPath"];
                options.ResponseType = OpenIdConnectResponseType.IdToken; // Use implicit flow
                options.Scope.Add("openid");
                options.Scope.Add("profile");
                options.Events = new OpenIdConnectEvents
                {
                    OnTokenValidated = context =>
                    {
                        var identity = context.Principal.Identity as ClaimsIdentity;
                        identity.AddClaim(new Claim(_authScheme, _customerAuthType));
                        return Task.CompletedTask;
                    }
                };
            })
            .AddOpenIdConnect(_supportAgentAuthType, options =>
            {
                options.Authority = string.Format(CultureInfo.InvariantCulture, authorityFormat, Configuration[$"AzureAd:{_supportAgentAuthType}:TenantId"]);
                options.ClientId = Configuration[$"AzureAd:{_supportAgentAuthType}:ClientId"];                                
                options.CallbackPath = Configuration[$"AzureAd:{_supportAgentAuthType}:CallbackPath"];                
                options.ResponseType = OpenIdConnectResponseType.IdToken;
                options.Scope.Add("openid");
                options.Scope.Add("profile");
                options.Events = new OpenIdConnectEvents
                {
                    OnTokenValidated = context =>
                    {
                        var identity = context.Principal.Identity as ClaimsIdentity;
                        identity.AddClaim(new Claim(_authScheme, _supportAgentAuthType));
                        return Task.CompletedTask;
                    }
                };
            });

            services.AddAuthorization();
            ......
        }

2. 使用 Endpoints 响应自己定义的路由处理 (登录和登出)

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            ......

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

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
                endpoints.MapBlazorHub();
                endpoints.MapFallbackToPage("/_Host");

                // Add endpoints for login challenges
                endpoints.MapGet("/login-customer", async context =>
                {
                    await context.ChallengeAsync(_customerAuthType, new AuthenticationProperties
                    {
                        RedirectUri = "/"
                    });
                });

                endpoints.MapGet("/login-support-agent", async context =>
                {
                    await context.ChallengeAsync(_supportAgentAuthType, new AuthenticationProperties
                    {
                        RedirectUri = "/"
                    });
                });

                // Add endpoint for logout
                endpoints.MapGet("/logout", async context =>
                {
                    var user = context.User;
                    if (user.Identity.IsAuthenticated)
                    {
                        var authSchemeClaim = user.FindFirst(_authScheme);
                        if (authSchemeClaim != null)
                        {
                            var authScheme = authSchemeClaim.Value;
                            var tenant = user.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid")?.Value;
                            await context.SignOutAsync(authScheme);

                            // sign out from IDP
                            if (tenant != null)
                            {
                                // Construct the current full URL                                
                                var currentUrl = $"{context.Request.Scheme}://{context.Request.Host}{context.Request.PathBase}";
                                context.Response.Redirect($"https://login.microsoftonline.com/{tenant}/oauth2/v2.0/logout?post_logout_redirect_uri={currentUrl}");
                            }
                        }
                    }
                    await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);                    
                });
            });
        }

可以看到上面分别注册了三个路由 /login-customer,/login-support-agent,/logout

一个给客户登录用,一个给技术支持登录用,最后一个是登出,

这个时候再利用 HttpContext 去 Challenge 就不会报错了,那么 blazor 页面上所做就是跳转到上面的路由地址就可以实现相应的登录和登出了

    private void SupportAgentLogin()
    {
        navigation.NavigateTo("/login-support-agent", true);
    }
    private void Logout()
    {
        navigation.NavigateTo("/logout", true);
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/639117.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python数据可视化(七)

绘制 3D 图形 到目前为止,我们一直在讨论有关 2D 图形的绘制方法和绘制技术。3D 图形也是数据可视化的 一个很重要的应用方面,我们接下来就重点讲解有关 3D 图形的实现方法。绘制 3D 图形通常需要导 入 mpl_toolkits 包中的 mplot3d 包的相关模块&#x…

【openlayers系统学习】3.6-3.7添加可视化选择器,手动选择可视化的图像源

六、添加可视化选择器(选择可视化的图像类型) 在前面的示例中,我们已经看到了同一Sentinel-2图像的真彩色合成、假彩色合成和NDVI渲染。如果能让用户从这些可视化中选择一个或更多,而不必每次都更改我们的代码,那就太…

2024年顶级算法-黑翅鸢优化算法(BKA)-详细原理(附matlab代码)

黑翅鸢是一种上半身蓝灰色,下半身白色的小型鸟类。它们的显著特征包括迁徙和捕食行为。它们以小型哺乳动物、爬行动物、鸟类和昆虫为食,具有很强的悬停能力,能够取得非凡的狩猎成功。受其狩猎技能和迁徙习惯的启发,该算法作者建立…

C++利用TinyXML读取XML文件

TinyXML是什么? TinyXML是一个轻量级的C XML解析器,它提供了一种简单的方法来解析和操作XML文档。TinyXML被设计为易于使用和集成到C项目中,并且非常适合处理小型XML文件。 以下是TinyXML的一些主要特点和优点: 轻量级: T…

0基础从前端到Web3 —— Mine Clearance Frontend(二)

在一的基础上继续往下,本篇主要是链上调用部分,让整个项目可以进行最基本的扫雷游戏。 S u i M o v e \mathit {Sui\ Move} Sui Move 链上部署的自主实现的简单扫雷游戏可以点击查看,只不过这里将区域大小扩大为了 10 20 \text {10}\ \tim…

Plesk中如何移除之前添加的域名

我这边想要移除我之前绑定到主机的域名,但是不知道如何在主机上面进行移除,由于我使用的Hostease的Windows虚拟主机产品默认带普通用户权限的Plesk面板,但是不知道如何在Plesk上操作移除域名,因为也是对于Hostease主机产品不是很了…

python给图片加上图片水印

python给图片加上图片水印 作用效果代码 作用 给图片加上图片水印图片水印的透明度,位置可自定义 效果 原始图片: 水印图片: 添加水印后的图片: 代码 from PIL import Image, ImageDraw, ImageFontdef add_watermark(in…

联盟 | 歌者 AIPPT X HelpLook携手,开启企业高效办公新时代

面对日益增长的工作负荷和追求效率优化的压力,企业知识的积累与传播显得愈发重要。如何系统化地沉淀员工与企业的知识精华?如何快速分享内外部知识?更重要的是,如何在获取这些知识后,迅速将其转化为精美的PPT&#xff…

抖店一件代发,从0到1操作全流程

我是王路飞。 先说明一点,新手不需要纠结抖店一件代发(即无货源模式)还能不能做的问题。 无货源只是前期帮助新手阶段的你进入到这个市场里来的一种方式,不是你长期做店的思路。 入门之后,基本就转型为有货源去玩了…

漫画|基于SprinBoot+vue的漫画网站(源码+数据库+文档)

漫画网站 目录 基于SprinBootvue的漫画网站 一、前言 二、系统设计 三、系统功能设计 1系统功能模块 2管理员功能模块 3用户功能模块 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取: 博主介绍:✌️大…

node 版本对应的 node-sass 版本号

当我们在项目中使用 node-sass 时,电脑的 node版本号一定要与 node-sass 版本号对应,不对应时下载就会报错 ❌问题?node-sass: Command failed. ✅解决方案,可能是node 跟 node-sass版本不一致 1、查询node版本 node -v &#…

RabbitMQ - SimpleMessageListenerContainer的实现逻辑

RabbitMQ - SimpleMessageListenerContainer的实现逻辑 Queue(队列):在 RabbitMQ 中用于存储消息的数据结构。生产者将消息发送到队列中,而消费者从队列中接收消息。 Connection(连接):连接是应…

Unity 实现心电图波形播放(需波形图图片)

实现 在Hierarchy 面板从2D Object 中新建一个Sprite,将波形图图片的赋给Sprite。 修改Sprite 的Sprite Renderer 组件中Draw Mode 为Tiled, 修改Sprite Renderer 的Size 即可实现波形图播放。 在Hierarchy 面板从2D Object 中新建一个Sprite Mask 并赋以遮罩图片…

【学习笔记】Windows GDI绘图(六)图形路径GraphicsPath详解(中)

上一篇【学习笔记】Windows GDI绘图(五)图形路径GraphicsPath详解(上)介绍了GraphicsPath类的构造函数、属性和方法AddArc添加椭圆弧、AddBezier添加贝赛尔曲线、AddClosedCurve添加封闭基数样条曲线、AddCurve添加开放基数样条曲线、基数样条如何转Bezier、AddEllipse添加椭圆…

2024年了, 你还不会使用node.js做压力测试?

前些天刷抖音,看到网传的Java继父,求人攻击压测他的网站,这不得摩拳擦掌。 所以今天来聊聊如何对自己的项目、接口进行压力测试。 压力测试的目的 首先, 绝对不是为了压测、攻击别人的网站为乐。 1、探索线上系统流量承载的极限&#xff…

python批发模块的调试之旅:从新手到专家的蜕变

新书上架~👇全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我👆,收藏下次不迷路┗|`O′|┛ 嗷~~ 目录 一、调试技巧的重要性 二、批发模块调试的实战演练 1. 设置断点 2. 逐行执行代码 3. 观察…

安全风险 - 检测Android设备系统是否已Root

在很多app中都禁止 root 后的手机使用相关app功能,这种场景在金融app、银行app更为常见一些;当然针对 root 后的手机,我们也可以做出风险提示,告知用户当前设备已 root ,谨防风险! 最近在安全检测中提出了一…

【博主推荐】HTML5实现520表白、情人节表白模板源码

文章目录 1.设计来源1.1 表白首页1.2 甜蜜瞬间11.3 甜蜜瞬间21.4 甜蜜瞬间31.5 甜蜜瞬间41.6 甜蜜瞬间51.7 甜蜜瞬间61.8 永久珍藏 2.效果和源码2.1 页面动态效果2.2 页面源代码2.3 源码目录2.4 更多为爱表白源码 3.源码下载地址 作者:xcLeigh 文章地址:…

行业首发 | MS08067-SecGPT(送邀请码)

一、简介 MS08067-SecGPT基于LLM大模型技术专门为网络安全领域设计的智能助手,集问答、分析、工具为一体的对话式安全专家,支持可以创建多会话问答。目的是辅助用户完成网络安全相关的工作,学员通过问答方式体验到SecGPT所具备的威胁情报分…