Django登录用户资料访问权限控制问题求助
解决Django用户资料编辑的权限漏洞:限制用户仅能编辑自身资料
问题根源
你的代码目前存在两个核心问题:
- 未校验当前登录用户与URL中
user_id对应的用户是否一致,导致任意登录用户修改user_id即可访问他人资料 - 原视图通过
@user_passes_test(check_role_super)限制仅超级管理员能访问,不符合普通用户编辑自身资料的需求
解决方案
根据需求,我们可以分两种场景处理:普通用户仅能编辑自身资料,超级管理员可编辑所有用户资料,同时对越权访问触发错误提示。
方案1:拆分视图(推荐,职责更清晰)
1. 普通用户资料编辑视图(无需URL参数)
直接使用当前登录用户,从根源避免用户通过修改URL参数越权:
@login_required(login_url='signin') def profile_edit(request): # 直接获取当前登录用户 user = request.user # 通过OneToOne关联获取用户资料,比直接用pk更可靠 user_profile = get_object_or_404(userMember, user=user) if request.method == 'POST': # 使用普通用户专属表单(仅开放可修改的个人字段,如姓名、联系方式等) form = UserForm(request.POST, instance=user) # 处理图片上传需传入request.FILES form_profile = MemberForm(request.POST, request.FILES, instance=user_profile) if form.is_valid() and form_profile.is_valid(): form.save() form_profile.save() # 保存后跳转回个人资料页 return redirect('profile') else: form = UserForm(instance=user) form_profile = MemberForm(instance=user_profile) context = { 'form': form, 'user': user, 'form_profile': form_profile, 'user_profile': user_profile } return render(request, 'pages/profile_edit.html', context)
2. 超级管理员资料编辑视图(保留原逻辑并优化)
保留超级管理员的全局编辑权限,同时优化关联资料的获取方式:
@login_required(login_url='signin') @user_passes_test(check_role_super) def sa_profile_edit(request, user_id=None): user = get_object_or_404(User, pk=user_id) # 通过User实例关联获取userMember,避免主键不一致问题 user_profile = get_object_or_404(userMember, user=user) if request.method == 'POST': form = UserFormAdmin(request.POST, instance=user) form_profile = MemberForm(request.POST, request.FILES, instance=user_profile) if form.is_valid() and form_profile.is_valid(): form.save() form_profile.save() return redirect('sa_user_list') # 跳转回用户管理列表 else: form = UserFormAdmin(instance=user) form_profile = MemberForm(instance=user_profile) context = { 'form': form, 'user': user, 'form_profile': form_profile, 'user_profile': user_profile } return render(request, 'pages/sa_editProfile.html', context)
方案2:合并视图(支持两种角色共用一个接口)
如果需要用同一个视图处理两种角色,可在视图内添加权限判断逻辑:
@login_required(login_url='signin') def profile_edit(request, user_id=None): # 默认使用当前登录用户ID,未传参时直接编辑自身资料 target_user_id = user_id or request.user.id user = get_object_or_404(User, pk=target_user_id) user_profile = get_object_or_404(userMember, user=user) # 权限校验:超级管理员可编辑任意用户,其他用户仅能编辑自己 if request.user.role != User.SUPERADMIN and user.id != request.user.id: raise PermissionDenied("你仅能编辑自己的资料") if request.method == 'POST': # 根据角色选择对应的表单,普通用户无法修改敏感字段 form_class = UserFormAdmin if request.user.role == User.SUPERADMIN else UserForm form = form_class(request.POST, instance=user) form_profile = MemberForm(request.POST, request.FILES, instance=user_profile) if form.is_valid() and form_profile.is_valid(): form.save() form_profile.save() return redirect('profile', user_id=request.user.id) else: form_class = UserFormAdmin if request.user.role == User.SUPERADMIN else UserForm form = form_class(instance=user) form_profile = MemberForm(instance=user_profile) context = { 'form': form, 'user': user, 'form_profile': form_profile, 'user_profile': user_profile } return render(request, 'pages/profile_edit.html', context)
错误提示处理
为了给用户明确的越权提示,需要配置自定义403错误页面:
- 在项目
urls.py中添加:
handler403 = 'your_app.views.permission_denied'
- 在
views.py中编写错误处理视图:
def permission_denied(request, exception): return render(request, '403.html', {'message': str(exception)}, status=403)
- 创建
403.html模板显示错误信息:
<!DOCTYPE html> <html> <head> <title>权限不足</title> </head> <body> <h1>权限不足</h1> <p>{{ message }}</p> <a href="{% url 'profile' %}">返回个人资料页</a> </body> </html>
额外优化建议
- 普通用户的表单(
UserForm)应限制可编辑字段,隐藏role、status等敏感字段,避免用户通过表单篡改权限 - 确保
userMember模型的user关联正确使用OneToOneField,避免数据不一致问题
内容的提问来源于stack exchange,提问作者Kimberly Chan
相关产品推荐
相关产品推荐

