如何使Azure AD身份验证接受URL查询字符串访问令牌

时间:2019-04-03 13:19:09

标签: azure signalr azure-active-directory azure-web-sites

是否可以将内置的Azure AD身份验证配置为同时接受Authorization: Bearer <token>标头和access_token=<token> url查询字符串?

我需要这样做才能允许来自浏览器的SingalR WebSocket连接。

我的场景

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

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

来自.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>网址查询参数完成的。

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

SignalR Core docs建议使用JwtBearerEvents OnMessageReceived来处理这种情况,但是在这种情况下,Azure Service App的Azure AD身份验证会拒绝该查询,然后我才能对其进行处理。用户代码。

有没有办法配置Azure App Service AD身份验证以接受access_token参数?

2 个答案:

答案 0 :(得分:1)

如果您正在使用SignalR JavaScript客户端,则可以提供一种方法,该方法将返回访问令牌,该令牌将作为承载令牌包含在客户端的请求中。无论使用哪种运输方式,该应该都可以工作(尽管我自己还没有尝试过)

文档中的示例(https://docs.microsoft.com/aspnet/core/signalr/configuration?#configure-bearer-authentication):

let connection = new signalR.HubConnectionBuilder()
    .withUrl("/myhub", {
        accessTokenFactory: () => {
            // Get and return the access token.
            // This function can return a JavaScript Promise if asynchronous
            // logic is required to retrieve the access token.
        }
    })
    .build();

答案 1 :(得分:1)

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

Startup.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 并注意加密或完全避免请求日志。