Azure Static Web Apps:login_hint 现已生效

发布: (2025年12月24日 GMT+8 01:37)
3 min read
原文: Dev.to

Source: Dev.to

本文展示了 login_hint 的实现方式,而 Azure 静态 Web 应用(SWA)默认 支持该功能。

参考文献

(未列出条目)

认证流程

  1. 访问

    https://swa.azurestaticapps.net/.auth/login/aad?login_hint=user@mail.com
  2. 用户被重定向到

    https://swa.azurestaticapps.net/.auth/login/aad?post_login_redirect_uri=/.auth/complete&staticWebAppsAuthNonce=aTakZLY%2fCmXnnD%2foxHxXW%2fWDcXGAy27B84se3dzrpE7UcwEFqKGy2VNnXRqvPInletF6R26ZDfdMSD0kKda41Y8%2b3BXO%2bHUoG3VEbaJpSkhdQ%2fRFWgFb1nKNWZ80dtzW
  3. 然后再跳转到

    https://login.microsoftonline.com/c74da02d-281d-4a45-a4af-cc520eafa6e3/oauth2/v2.0/authorize?
    response_type=code+id_token&
    redirect_uri=https%3A%2F%2Fswa.azurestaticapps.net%2F.auth%2Flogin%2Faad%2Fcallback&
    client_id=6c3476f8-54c2-4322-8401-f7774963a1e1&
    scope=openid+profile+email&
    response_mode=form_post&
    resource=https%3A%2F%2Fgraph.microsoft.com&
    nonce=9108b12ec87a4effa26bd5287d792605_20251223165427&
    state=redir%3D%252F.auth%252Fcomplete

问题

login_hint 丢失,未能传递到 login.microsoftonline.com 端点。

解决方案

我使用 Azure Functions v4(Node)并通过 HTTP/2 请求实现了一个中间件。

为什么使用 HTTP/2?

认证流程使用了属于 HTTP/2 协议的伪头部(:authority:path)。

完整的项目设置稍后会提供。

步骤

  1. 用户请求 – 用户访问

    https://swa.azurestaticapps.net/api/whoami?login_hint=user@mail.com
  2. 函数触发 – 请求被函数 app.http("whoami"... ) 接收并调用 handler 函数。

  3. 处理handler 从请求中提取原始 SWA URL 和 login_hint,跟随重定向,注册 Cookie,最终构造包含正确 nonce Cookie 的 login.microsoftonline.com 完整 URL。

  4. 重定向 – 函数返回一个重定向响应给 SWA 页面,随后完成认证流程。

  5. 错误处理 – 若出现异常,函数会重定向回 /.auth/login/aad,并使用 context.log 记录细节,日志可在 Azure 门户中查看。

函数代码

import { app } from "@azure/functions";
import { connect } from "node:http2";

let count = 5;

/**
 * Recursively follows redirects using HTTP/2 and injects login_hint when needed.
 *
 * @param {string} url               – The URL to request.
 * @param {PromiseWithResolvers} pWithResolvers  – Optional promise resolvers (for recursion).
 * @param {Object} headersObj        – HTTP/2 pseudo‑headers for the request.
 * @param {string} loginHint         – The login_hint value (may be empty).
 * @returns {Promise}
 */
async function getData(url, pWithResolvers, headersObj = {}, loginHint) {
    const p = pWithResolvers ?? Promise.withResolvers();
    const clientSession = connect(url);

    clientSession.on("error", (err) => console.error(err));

    const req = clientSession.request({
        ...headersObj,
    });

    req.on("response", (headers) => {
        req.on("error", (e) => {
            context.log(`problem with request:`, {
                msg: e.message,
                stack: e.stack,
                e,
            });
            clientSession.close();
            p.reject(e.message);
        });

        const status = headers
Back to Blog

相关文章

阅读更多 »

了解 JSON Web Token (JWT)

在创建 Web 应用程序的某个时刻,我们需要为系统开发一个认证解决方案。有多种策略可以实现,例如 aute...