django-react 服务端挂载apache代理 域名 sessionid不存储问题

本文记录了一位开发者在进行前后端分离项目重构时遇到的Session存储问题。在使用React作为前端,Django作为后端的环境中,由于Apache代理导致Session无法存储。经过排查,发现问题在于'SameSite' cookie属性和安全连接。最终通过将前端和后端部署在同一域名的不同子域名下解决了问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近在工作上需要将一个旧项目进行前后端分离, 前端采用react。
前期进展顺利,本地测试是有个问题,login存储不上,但在将host改为localhost后就可以了。
当上线服务端是出现了问题,登录后sessionid不进行存储。

INSTALLED_APPS = [
  ...
  'corsheaders'
]
CORS_ALLOWED_ORIGINS = [
    'http://域名.com',
    'https://域名.com',
    'http://react服务器ip:3000',
    'https://react服务器ip:3000'
]
CORS_ALLOW_CREDENTIALS = True
CORS_ORIGIN_ALLOW_ALL = True
MIDDLEWARE = [
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.common.CommonMiddleware',
    # 'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'django.middleware.security.SecurityMiddleware',
    'whitenoise.middleware.WhiteNoiseMiddleware'
]
REST_FRAMEWORK = {
    "DEFAULT_AUTHENTICATION_CLASSES": ("CustomAuthentication", )
}

CORS_ALLOW_METHODS = (
    'DELETE',
    'GET',
    'OPTIONS',
    'PATCH',
    'POST',
    'PUT',
    'VIEW',
)
CORS_ALLOW_HEADERS = (
    'XMLHttpRequest',
    'X_FILENAME',
    'accept-encoding',
    'authorization',
    'content-type',
    'dnt',
    'origin',
    'user-agent',
    'x-csrftoken',
    'x-requested-with',
    'Pragma',
)
CACHES = {
    'default': {
        'BACKEND': "django_redis.cache.RedisCache",
        "LOCATION": "redis://localhost:6379/3",  # TODO 3作为登录验证
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
            "CONNECTION_POOL_KWARGS": {"max_connections": 100}
        }
    }
}
SESSION_ENGINE = "django.contrib.sessions.backends.cache"
# 指定本地的session使用的本地缓存名称是'default'
SESSION_CACHE_ALIAS = "default"
export default class App extends Component {
    testRequest = () => {
        axios({
            method: 'GET',
            url: 'http://指向后端/login/',
            headers: {
                'Accept': 'application/json',
                'Content-Type': 'application/json'
            },
            withCredentials: true
        }).then(res => {
            alert(res.data)
        })
    }
    handleSubmit = (event) => {
        event.preventDefault()
        this.testRequest()

        axios.defaults.withCredentials = true;
        const csrftoken = GetCookie('csrftoken')
        console.log(csrftoken)
        const data = new FormData(event.currentTarget);
        axios({
            method: 'POST',
            url: 'http://指向后端/login/',
            dataType: 'json',
            data: {
                'username': data.get('username'),
                'password': data.get('password'),
            },
            headers: {
                "X-CSRFtoken": csrftoken,
                'Accept': 'application/json',
                'Content-Type': 'application/json',
            },
            timeout: 100000000000,
            withCredentials: true
        }).then(res => {
            console.log(res)
        }).catch(res => {
            console.log(res)
        })
    }

    render() {
        return (
            <Box component="form" onSubmit={this.handleSubmit} noValidate sx={{mt: 1}}>
                <TextField
                    margin="normal"
                    required
                    fullWidth
                    id="username"
                    label="UserName"
                    name="username"
                    autoComplete="username"
                    autoFocus
                />
                <TextField
                    margin="normal"
                    required
                    fullWidth
                    name="password"
                    label="Password"
                    type="password"
                    id="password"
                    autoComplete="current-password"
                />
                <FormControlLabel
                    control={<Checkbox value="remember" color="primary"/>}
                    label="Remember me"
                />
                <Button
                    type="submit"
                    fullWidth
                    variant="contained"
                    sx={{mt: 3, mb: 2}}
                >
                    Sign In
                </Button>
                <Grid container>
                    <Grid item xs>
                        <Link href="http://指向后端/logout/" variant="body2">
                            logout
                        </Link>
                    </Grid>
                    <Grid item>
                        <Link href="#" variant="body2">
                            {"Don't have an account? Sign Up"}
                        </Link>
                    </Grid>
                </Grid>
        </Box>)
    }
}

查了下以为是django设置问题,搞了半天,发现毫无意义。
开了个小demo项目,测试发现是代理问题,本人使用apache代理,如果直接IP请求,sessionid是可以存储的,而使用ip代理后,sessionid不进行存储。这时候意识到是apache的问题。(这里已经过了一天了 笑)

打开浏览器的开发者工具,查看登录post请求,发现set cookies后面有个黄色感叹号。(这里不放图了,搞了两天累了)
this attempt to set a cookie via a set-cookie header was blocked because it had the ‘secure’ attribute but was not received over a secure connection
this set-cookie header didn’t specify a “samesite” attribute and was defaulted to “samesite=LAX” and was blocked because it came from a cross-site response which w…
这时候判断是这个samesite问题,查谷歌能不能设置,之后就是漫长的瞎折腾。

瞎找

到刚刚才突发奇想,既然是同源问题,那将前端与后端都挂在一个域名下试试呢
前端设置 login.域名.com
后端设置server.域名.com
成功!
cookie存储在server.域名.com下 并且成功完成了登录后下一页的数据展示。

到此花了两天时间搞这么个破事。
记录完毕。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值