You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

能否为Swagger页面添加登录弹窗?实现Token自动注入授权头

实现Swagger自动登录弹窗并注入Token的方案

当然可以实现!我之前帮不少开发者搞定过这个需求——让Swagger自动弹出登录框获取Token,不用用户手动粘贴授权头,体验顺畅多了。下面是完整的实现步骤:

一、后端Swagger安全配置(完善你的现有代码)

你已经配置了AddSecurityDefinition,这一步是对的,但还需要添加全局安全要求,让Swagger默认对所有接口启用授权检查:

services.AddSwaggerGen(c =>
{
    // 你的现有Bearer安全定义
    c.AddSecurityDefinition("Bearer", new ApiKeyScheme 
    { 
        Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"", 
        Name = "Authorization", 
        In = "header", 
        Type = "apiKey" 
    });

    // 全局添加安全要求,确保所有接口默认触发授权校验
    c.AddSecurityRequirement(new Dictionary<string, IEnumerable<string>>
    {
        { "Bearer", Enumerable.Empty<string>() }
    });
});

然后在Configure方法里指定自定义的Swagger UI首页,这样我们才能注入登录弹窗的逻辑:

app.UseSwaggerUI(c =>
{
    c.SwaggerEndpoint("/swagger/v1/swagger.json", "你的API名称 V1");
    // 替换成你的项目命名空间和HTML文件路径,确保HTML是嵌入资源
    c.IndexStream = () => typeof(Program).Assembly.GetManifestResourceStream("YourProjectNamespace.Swagger.index.html");
});

二、自定义Swagger UI首页(添加登录弹窗)

创建一个index.html文件,放在项目的Swagger文件夹下(自己新建),然后右键文件→属性→生成操作,设置为嵌入的资源。这个文件会替换默认的Swagger UI页面,加入登录弹窗和自动注入Token的逻辑:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>API文档</title>
    <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/3.52.5/swagger-ui.css" />
    <style>
        .login-modal {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0,0,0,0.6);
            display: flex;
            justify-content: center;
            align-items: center;
            z-index: 9999;
        }
        .login-card {
            background: #fff;
            padding: 2.5rem;
            border-radius: 10px;
            width: 320px;
            box-shadow: 0 4px 12px rgba(0,0,0,0.15);
        }
        .login-card h3 {
            margin-top: 0;
            color: #333;
            text-align: center;
        }
        .login-card input {
            width: 100%;
            margin: 0.8rem 0;
            padding: 0.7rem;
            border: 1px solid #ddd;
            border-radius: 6px;
            box-sizing: border-box;
            font-size: 1rem;
        }
        .login-card button {
            width: 100%;
            padding: 0.7rem;
            background: #2563eb;
            color: white;
            border: none;
            border-radius: 6px;
            font-size: 1rem;
            cursor: pointer;
            margin-top: 0.5rem;
        }
        .login-card button:hover {
            background: #1d4ed8;
        }
        .error-msg {
            color: #dc2626;
            margin-top: 1rem;
            text-align: center;
            display: none;
        }
    </style>
</head>
<body>
    <div id="swagger-ui"></div>

    <!-- 登录弹窗 -->
    <div id="loginModal" class="login-modal">
        <div class="login-card">
            <h3>请登录访问API</h3>
            <input type="text" id="username" placeholder="用户名" required />
            <input type="password" id="password" placeholder="密码" required />
            <button onclick="handleLogin()">登录</button>
            <div id="errorMsg" class="error-msg"></div>
        </div>
    </div>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/3.52.5/swagger-ui-bundle.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/3.52.5/swagger-ui-standalone-preset.js"></script>
    <script>
        // 从本地存储读取Token,避免每次刷新都登录
        let authToken = localStorage.getItem('swagger_auth_token');

        // 初始化Swagger UI的方法
        function initSwagger(token) {
            const ui = SwaggerUIBundle({
                url: "/swagger/v1/swagger.json",
                dom_id: '#swagger-ui',
                presets: [
                    SwaggerUIBundle.presets.apis,
                    SwaggerUIStandalonePreset
                ],
                layout: "StandaloneLayout",
                // 请求拦截器:自动给所有API请求添加Authorization头
                requestInterceptor: (request) => {
                    if (token) {
                        request.headers.Authorization = `Bearer ${token}`;
                    }
                    return request;
                },
                // 可选:Token过期后自动清空存储并重新弹窗
                onComplete: () => {
                    // 这里可以添加Token过期检查逻辑,比如解析Token的exp字段
                }
            });
            window.ui = ui;
        }

        // 登录处理函数
        async function handleLogin() {
            const username = document.getElementById('username').value.trim();
            const password = document.getElementById('password').value.trim();
            const errorMsg = document.getElementById('errorMsg');

            if (!username || !password) {
                errorMsg.textContent = '请输入用户名和密码';
                errorMsg.style.display = 'block';
                return;
            }

            try {
                // 替换成你的实际登录接口地址
                const response = await fetch('/api/account/login', {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json'
                    },
                    body: JSON.stringify({ username, password })
                });

                if (!response.ok) {
                    throw new Error('登录失败,请检查用户名或密码');
                }

                const result = await response.json();
                authToken = result.accessToken; // 假设接口返回的Token字段是accessToken

                // 保存Token到本地存储
                localStorage.setItem('swagger_auth_token', authToken);
                // 隐藏登录弹窗
                document.getElementById('loginModal').style.display = 'none';
                // 初始化Swagger UI
                initSwagger(authToken);
            } catch (err) {
                errorMsg.textContent = err.message;
                errorMsg.style.display = 'block';
            }
        }

        // 页面加载时判断是否需要显示登录弹窗
        if (!authToken) {
            document.getElementById('loginModal').style.display = 'flex';
        } else {
            initSwagger(authToken);
        }
    </script>
</body>
</html>

三、关键注意事项

  • 登录接口适配:把代码里的/api/account/login替换成你项目实际的登录接口,确保返回的Token字段和代码里的result.accessToken一致。
  • Token安全:前端本地存储Token有一定风险,生产环境可以考虑用sessionStorage(关闭浏览器就失效),或者在后端设置较短的Token过期时间,配合刷新Token机制。
  • 嵌入资源设置:一定要把自定义的index.html设置为嵌入资源,否则后端找不到这个文件。
  • Token过期处理:可以在requestInterceptor里解析Token的过期时间,如果已过期,清空本地存储并重新弹出登录弹窗。

这样配置后,用户打开Swagger页面时,如果没有Token就会自动弹出登录框,登录成功后Token会自动注入到所有API请求的Authorization头里,完全不用手动输入授权信息啦!

内容的提问来源于stack exchange,提问作者Gabriel Scavassa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 11:13:56