能否为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
相关产品推荐
相关产品推荐

