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

Django/Apache2部署后登录成功无法访问@login_required视图跳转首页

问题描述

现有一套采用token-based auth的Django/Vue应用,此前在AWS上部署运行无异常,改用Apache2提供服务后,出现登录成功后无法打开login required保护页面的问题。
输入用户名密码点击登录后,登录接口正常请求完成,但页面重定向至携带?next=memory参数的首页,服务端未识别用户为已登录状态。登录成功后已将token以apitoken为键存入cookie。
相关代码如下:

views.py

def index(request):
    print('Access to page "home"')
    return render(request, 'index.html')


@login_required(login_url='/')
def memory(request):
    print('Access to page "memory"')
    return render(request, 'memory.html')

user_api.py

@api_view(["POST"])
@permission_classes((AllowAny,))
@csrf_exempt
def doLogin(request):
    body_unicode = request.body.decode('utf-8')
    user = json.loads(body_unicode)
    dbUser = User.objects.filter(username=user['username'])
    if not dbUser:
        return HttpResponse(status=404)

    authenticatedUser = authenticate(username=user['username'], password=user['password'])

    if authenticatedUser:
        login(request, authenticatedUser)
        token, _ = Token.objects.get_or_create(user=authenticatedUser)

        return Response({'token': token.key},
                        status=HTTP_200_OK)
    else:
        return Response(status=401)

LoginModal.vue

login() {
    if (!this.user.username || this.user.username == '' ||
        !this.user.password || this.user.password == '') {
        this.warningText = 'All fields must be filled.'
        return
    }

    axios.post(this.backendAddress + 'api/user/login', this.user)
        .then((response) => {
            sessionStorage.setItem('token', response.data.token)
            document.cookie = 'apitoken=' + response.data.token
            window.location.href = 'memory'
        }, function (err) {
            printError(err)
        })
}

问题根因&修复方案

核心问题是认证逻辑混用+部署配置不匹配,具体点如下:

  1. 装饰器认证逻辑不匹配:@login_required是Django原生session认证的装饰器,它只会读取请求携带的sessionid cookie,从服务端session里读取用户登录态,完全不会识别你手动存在cookie里的apitoken字段,也不会读你存在sessionStorage里的token。
  2. 整页跳转的请求特性:你用window.location.href = 'memory'触发的是浏览器原生整页跳转,这类请求由浏览器直接发起,不会自动携带sessionStorage里存储的token,只会自动携带匹配当前域名、路径、安全策略的cookie。
  3. Apache部署配置问题:之前AWS部署能正常运行,大概率是因为当时服务端返回的sessionid cookie能被浏览器正常存储;换成Apache后常见问题是WSGI配置缺失、cookie属性不匹配导致sessionid没被浏览器保存:
    • Apache默认会剥离请求的Authorization头不传给WSGI应用,如果后续要走token认证需要加对应配置
    • 若站点是HTTPS部署,Django的SESSION_COOKIE_SECURE、CSRF_COOKIE_SECURE配置和实际协议不匹配、cookie的Domain/Path/SameSite属性配置错误,都会导致浏览器不存储登录接口返回的sessionid,后续跳转请求不带session,自然被判定为未登录。
  4. 你代码里手动写apitoken cookie的操作对当前的@login_required鉴权完全无效,属于冗余操作。

修复方案

根据你的认证选型二选一即可:

方案1:保留页面路由用session鉴权(适配现有代码改动最小)

  • 给Apache的虚拟主机配置加上WSGIPassAuthorization On,避免认证头被Apache拦截
  • 打开浏览器开发者工具-应用面板,检查登录接口返回的Set-Cookie头,确认sessionid的Domain、Path、SameSite、Secure属性和当前访问的站点匹配:如果是HTTP站点不要开SESSION_COOKIE_SECURE = True,cookie域要配置为当前访问的域名,不要出现跨域、跨路径写cookie失败的问题
  • 删掉前端手动写apitoken cookie的冗余代码,只要sessionid能正常被浏览器存储,@login_required就能正常识别登录态

方案2:全链路使用Token认证

  • 不要给返回模板页面的视图用Django原生@login_required装饰器,自定义鉴权装饰器,从请求的cookie或者头里读取token做校验
  • 注意:原生整页跳转的请求无法自定义添加Authorization请求头,如果要靠cookie传token,需要修改DRF的TokenAuthentication逻辑,让它主动读取你存在cookie里的apitoken字段做校验,否则token不会被识别

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 10:18:43