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

React+FastAPI集成Microsoft单点登录的CORS跨域问题求助

React + FastAPI 实现Microsoft SSO时的CORS跨域问题解决

问题背景

我用React和FastAPI开发Microsoft单点登录(SSO)功能,一直被CORS跨域问题困扰,尝试过中间件配置、请求头设置等方案都无效。直接访问后端/login路由能正常跳转到Microsoft登录页面,说明Azure凭据配置正确,但前端调用http://localhost:5050/login时被CORS策略拦截,提示:

'http://localhost:5050/login' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

另外,不配置Starlette的SessionMiddleware会触发错误:"session" in self.scope AssertionError: SessionMiddleware must be installed to access request.session,同时启用两个中间件后问题仍未解决。


前端代码

import React, { useState } from 'react';
import './App.css';

function App() {
  
    const handleSubmit = (event) => {
    event.preventDefault(); // 阻止表单提交时刷新页面
    
    const url = 'http://localhost:5050/login';

    fetch(url, {method: 'GET'})
      .then((response) => {
        if (!response.ok) {
          throw new Error('请求出错');
        }
        window.location.href = response.json()
        return response.json();
      })
      .then((data) => {
        console.log('服务器响应:', data);
      })
      .catch((error) => {
        console.error('错误:', error);
      });
  };

  return (
    <div className="login-container">
      <h2>Login</h2>
      <form onSubmit={handleSubmit}>
        <button type="submit" className="login-button">登录</button>
      </form>
    </div>
  );
}

export default App;

后端代码

from authlib.integrations.starlette_client import OAuth
import uvicorn
import logging
from fastapi import FastAPI, Request
from starlette.middleware.sessions import SessionMiddleware
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

logger = logging.getLogger('uvicorn.error')

app.add_middleware(
    SessionMiddleware,
    secret_key="?",  # 需替换为强随机密钥
)

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

oauth = OAuth()
oauth.register(
    name='azure',
    client_id='SEU_CLIENT_ID',
    client_secret='SEU_CLIENT_SECRET',
    authorize_url='https://login.microsoftonline.com/SEU_TENANT_ID/oauth2/v2.0/authorize',
    token_url='https://login.microsoftonline.com/SEU_TENANT_ID/oauth2/v2.0/token',
    client_kwargs={'scope': 'openid email profile User.Read'}
)

@app.api_route('/login')
async def login(request: Request):
    redirect_uri = request.url_for('auth')
    return await oauth.azure.authorize_redirect(request, redirect_uri)

@app.get("/callback")
async def auth(request: Request):
    token = await oauth.azure.authorize_access_token(request)
    user = await oauth.azure.parse_id_token(request, token)
    return {"token": token, "user_info": user}

@app.get("/")
def hello_world_root():
    return {"Hello": "World"}

if __name__ == '__main__':
    uvicorn.run(app, port=5050)

问题根源与修复方案

1. 核心问题:错误的请求方式

SSO登录流程的本质是页面跳转,而非AJAX请求。你用fetch发起跨域AJAX请求获取重定向地址,浏览器会严格拦截这类跨域重定向请求,即使配置了CORS也无法绕过。

前端修复:直接跳转登录地址

把handleSubmit改成直接跳转到后端登录路由,完全绕开AJAX的CORS限制:

const handleSubmit = (event) => {
  event.preventDefault();
  window.location.href = 'http://localhost:5050/login';
};

2. 后端CORS配置优化

  • 调整中间件顺序:将CORSMiddleware放在SessionMiddleware之前添加,确保CORS头能被正确注入到所有响应(包括重定向):
    # 先添加CORS中间件
    app.add_middleware(
        CORSMiddleware,
        allow_origins=["http://localhost:3000"],  # 不要用*,明确指定前端地址,配合credentials=True
        allow_credentials=True,
        allow_methods=["*"],
        allow_headers=["*"],
    )
    
    # 再添加SessionMiddleware
    app.add_middleware(
        SessionMiddleware,
        secret_key="your-strong-random-secret-key",  # 替换为随机强密钥
    )
    
  • 避免使用通配符*:当allow_credentials=True时,浏览器不允许allow_origins设为*,必须指定具体的前端域名。

3. 验证Azure回调地址

确保Azure应用注册中的重定向URI设置为http://localhost:5050/callback,与后端request.url_for('auth')生成的地址完全一致。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 14:14:51