首页 > 解决方案 > 如何使 Azure AD 身份验证接受 url 查询字符串访问令牌

问题描述

有没有办法将内置 Azure AD 身份验证配置为同时接受 Authorization: Bearer <token>标头和access_token=<token>url 查询字符串?

我需要这个来允许来自浏览器的 SingalR WebSocket 连接。

我的情景

我有一个托管 SignalR Core 集线器的 ASP.Net Core 后端。该站点作为启用了 Azure AD 身份验证的 Azure 应用服务托管。

从 .Net 应用程序和网站访问 REST API 都可以正常工作。

来自.Net

与 .Net 应用程序的 SignalR 连接工作正常并使用 websocket。使用以下 HTTP 请求建立 websocket 连接:

GET https://<url>/hubs/chat?id=rk-Adzl1EWGCv8wsVF5ayg HTTP/1.1
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Key: m02nzEFDAFVwCgUPlF2rEA==
Sec-WebSocket-Version: 13
X-Requested-With: XMLHttpRequest
Authorization: Bearer <token>
Host: evotrqhub.evopro-ag.de
Cookie: ARRAffinity=8666c8fbc8cd126e76e2b31c5880dd9c4968a103221108a610b408e12a15fa39

请注意,授权是通过Authorization: Bearer <token>标头完成的。

从浏览器

当我从浏览器(Chrome 或 Firefox)建立 SignalR 连接时,无法建立 websocket 连接,并且使用长轮询作为后备。websocket 连接的 HTTP 请求是:

GET https://evotrqhub.evopro-ag.de/hubs/coilthickness?id=QB5xx4MLGi6uSvVK4QmvZA&access_token=<token> HTTP/1.1
Host: evotrqhub.evopro-ag.de
Connection: Upgrade
Pragma: no-cache
Cache-Control: no-cache
Upgrade: websocket
Origin: http://localhost:5000
Sec-WebSocket-Version: 13
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36
Accept-Encoding: gzip, deflate, br
Accept-Language: de,en-US;q=0.9,en;q=0.8
Cookie: ARRAffinity=8666c8fbc8cd126e76e2b31c5880dd9c4968a103221108a610b408e12a15fa39
Sec-WebSocket-Key: K4hUR2QFyRxcDKxfoNwn2w==
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits

这里的授权是通过auth_token=<token>url 查询参数完成的。

来自服务器的响应是到 Azure AD 登录页面的重定向(响应代码 302)。

SignalR Core 文档建议使用JwtBearerEvents OnMessageReceived来处理这种情况,但在这种情况下,Azure 服务应用程序的 Azure AD 身份验证会在我的用户代码处理之前拒绝查询。

那么有没有办法配置 Azure App Service AD Authentication 来接受access_token参数呢?

标签: azuresignalrazure-active-directoryazure-web-app-service

解决方案


我不知道是否有内置方法可以使用Microsoft 身份平台进行管理(可能是),无论如何您可以简单地在管道中添加一个中间件来检查请求上下文中是否存在承载令牌,如果不存在,检查查询字符串集合中是否存在access_token参数,然后将其作为承载令牌添加到新的授权标头中,如以下代码片段所示。

启动.cs

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {

        ...  
      
        app.UseCors("CorsPolicy");

        // START BEARER TOKEN MIDDLEWARE ---------------------------------------------
        app.Use(async (context, next) =>
        {
            if (
                string.IsNullOrWhiteSpace(context.Request.Headers["Authorization"]) &&
                context.Request.QueryString.HasValue
            )
            {
                var token = context.Request.QueryString.Value
                    .Split('&')
                    .SingleOrDefault(x => x.Contains("access_token"))?.Split('=')[1];
                if (!string.IsNullOrWhiteSpace(token))
                {
                    context.Request.Headers.Add(
                        "Authorization", 
                        new[] { $"Bearer {token}" }
                    );
                }
            }
            await next.Invoke();
        });
        // END BEARER TOKEN MIDDLEWARE -----------------------------------------------

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

        ...

    }

显然,从安全角度来看,这不是最好的方案,因此请确保您的 api 通过 https 并注意加密或完全避免请求日志。


推荐阅读