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

Django @login_required未重定向指定页面,用户编辑页权限异常排查

问题分析与修复方案

我来帮你梳理下代码里的核心问题,以及对应的修复方法,解决你的权限控制失效问题:

1. 最关键的漏洞:未校验登录用户与编辑页的user_id一致性

你用了@login_required装饰器,这只能确保访问页面的用户已经登录,但完全没限制用户只能访问自己的编辑页。所以登录后的用户只要改一下URL里的user_id,就能随便访问别人的页面,这是最核心的问题。

2. 路由与视图的小漏洞:无效URL能访问

你提到像http://127.0.0.1:8000/user//edit这种无效URL也能打开编辑页,大概率是因为:

  • Django默认会把URL里的多个斜杠合并成一个,所以/user//edit等价于/user/edit,而你的路由正则r'^(?P<user_id>\d+)/edit$要求user_id是至少一个数字,理论上这个URL应该返回404,但实际能打开的话,要么是你写错了正则(比如用了\d*而不是\d+),要么是视图里没校验user_id的有效性,空值也能渲染模板。

具体修复步骤

第一步:给user_edit视图加身份校验逻辑

在user_edit里加上代码,确保当前登录用户的ID和URL里的user_id完全一致,不一致就拒绝访问或者跳转到自己的编辑页:

from django.contrib.auth.decorators import login_required
from django.shortcuts import redirect, get_object_or_404
from django.contrib.auth.models import User
from django.http import HttpResponseForbidden

@login_required(login_url='/user/login/')
def user_edit(request, user_id):
    # 先把user_id转成整数,避免字符串匹配的坑
    try:
        target_user_id = int(user_id)
    except ValueError:
        # 如果user_id不是有效数字,直接返回404或者跳转到登录页
        return HttpResponseForbidden("无效的用户ID")
    
    # 核心校验:当前登录用户只能访问自己的编辑页
    if request.user.id != target_user_id:
        # 两种处理方式选其一:
        # 1. 跳转到当前用户自己的编辑页
        return redirect('user-edit', user_id=request.user.id)
        # 2. 返回403禁止访问页面
        # return HttpResponseForbidden("你没有权限访问此页面")
    
    # 如果需要操作用户实例,用get_object_or_404确保用户存在
    target_user = get_object_or_404(User, id=target_user_id)
    
    print(request, request.user)
    print("next is {}".format(request.GET.get('next')))
    return render(request, 'user_edit.html', {'userid': target_user_id, 'user': request.user})

第二步:修复路由正则,严格匹配有效ID

确保你的路由正则只匹配数字ID,并且和实际访问的URL格式一致(比如你的示例URL是/user/7/edit,路由里要对应好斜杠):

# urls.py
from django.conf.urls import url
from . import views

urlpatterns = [
    url(r'^login/$', views.user_login, name='user-login'),
    # 严格匹配数字ID,结尾加上斜杠和$确保没有多余字符
    url(r'^(?P<user_id>\d+)/edit/$', views.user_edit, name='user-edit'),
]

第三步:优化登录后的跳转逻辑(可选但更友好)

你的user_login视图现在登录成功后直接跳转到用户自己的编辑页,但如果用户是从其他需要登录的页面跳转过来的,应该优先回到原页面。修改一下:

from django.urls import reverse

def user_login(request):
    login_form = AuthenticationForm(request.POST or None)
    if request.method == 'POST':
        username = request.POST['username']
        password = request.POST['password']
        user = authenticate(request, username=username, password=password)
        if user:
            login(request, user)
            # 先取next参数,没有的话再跳转到自己的编辑页
            next_url = request.GET.get('next') or reverse('user-edit', args=[user.id])
            return redirect(next_url)
        else:
            # 登录失败别直接重定向,返回登录页并提示错误
            return render(request, 'user_login.html', {'form': login_form, 'error': '用户名或密码错误'})
    return render(request, 'user_login.html', {'form': login_form})

额外推荐:用Django类视图更规范地实现

如果想减少手动编写的代码,推荐用Django的通用类视图,自带权限控制的Mixin,代码更简洁不易出错:

# views.py
from django.views.generic.edit import UpdateView
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.contrib.auth.models import User
from django.urls import reverse_lazy

class UserEditView(LoginRequiredMixin, UserPassesTestMixin, UpdateView):
    model = User
    # 这里放你要让用户编辑的字段,比如用户名、邮箱
    fields = ['username', 'email']
    template_name = 'user_edit.html'
    # 编辑成功后跳转的页面,比如用户自己的编辑页
    def get_success_url(self):
        return reverse_lazy('user-edit', kwargs={'pk': self.request.user.id})
    
    def test_func(self):
        # 校验当前用户是否是要编辑的用户
        return self.request.user == self.get_object()
    
    def get_login_url(self):
        return '/user/login/'

对应的路由改成:

url(r'^(?P<pk>\d+)/edit/$', views.UserEditView.as_view(), name='user-edit'),

这样就不用自己写校验逻辑,Django会帮你处理好登录校验和用户权限校验。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:48:14