本文介绍如何使用 Django 内置的 @login_required 装饰器,为关键页面(如书籍详情、图书列表等)添加登录保护,防止未认证用户通过直接输入 URL 绕过登录页访问受保护资源。
本文介绍如何使用
django
内置的 `@login_required` 装饰器,为关键页面(如书籍详情、图书列表等)添加登录保护,防止未认证用户通过直接输入 url 绕过登录页访问受保护资源。
在你当前的 Django 项目中,所有视图(如 get_book、get_books、get_book_category 等)均未做身份验证检查,导致任何用户只需知道 URL 即可直接访问——这是典型的
授权缺失(Missing Authorization)
问题。Django 提供了简洁、安全且符合最佳实践的解决方案:@login_required 装饰器。
✅ 正确做法:为需要保护的视图添加 @login_required
首先,在 views.py 顶部导入装饰器:
然后,将 @login_required 应用于所有
必须登录后才能访问
的视图函数。例如:
?
提示
:@login_required 默认会在用户未登录时重定向至 /accounts/login/。若你的登录页 URL 是 /login(如 path('login', views.index, name="index")),请在 settings.py 中显式配置:
Python 网站开发之Django环境搭建 WORD版
本文档主要讲述的是Python 网站开发之Django环境搭建;希望本文档会给有需要的朋友带来帮助;感兴趣的朋友可以过来看看
下载
或更推荐使用命名 URL(Django 4.1+ 支持):
⚠️ 注意事项与增强建议
不要保护登录/注册页本身
:signin、registration、signout 等视图
不应
加 @login_required,否则会引发重定向循环。
避免重复逻辑
:你当前在 get_book 中手动检查 if request.user.is_authenticated: 是冗余的——@login_required 已在请求进入视图前完成该检查,可安全移除。
敏感操作需双重校验
:虽然装饰器能阻止未登录访问,但对修改类操作(如提交评论、支付),仍建议在业务逻辑中再次确认 request.user.is_authenticated 和权限(如是否为本人评论),以防御潜在绕过。
考虑细粒度权限(进阶)
:若未来需区分“普通用户”和“管理员”,可结合 @user_passes_test 或 UserPassesTestMixin 实现角色级控制。
✅ 效果验证
添加装饰器后:
未登录用户访问 /book/5/ → 自动跳转至 /login/(或你配置的 LOGIN_URL);
登录后访问正常,request.user 可靠可用;
URL 直接访问失效,权限控制由框架层统一保障,安全且可维护。
通过这一最小改动,你便完成了从“完全开放”到“登录强制”的关键安全升级。坚持“默认拒绝(deny-by-default)”原则,是构建健壮 Web 应用的第一道防线。
from django.contrib.auth.decorators import login_required@login_required
def get_book(request, id):
# 原有逻辑保持不变
form = ReviewForm(request.POST or None)
book = get_object_or_404(Book, id=id)
# ... 其余代码
return render(request, "store/book.html", context)
@login_required
def get_books(request):
books_ = Book.objects.all().order_by('-created')
paginator = Paginator(books_, 10)
page = request.GET.get('page')
books = paginator.get_page(page)
return render(request, "store/category.html", {"book": books})
@login_required
def get_book_category(request, id):
book_ = Book.objects.filter(category_id=id)
paginator = Paginator(book_, 10)
page = request.GET.get('page')
book = paginator.get_page(page)
return render(request, "store/category.html", {"book": book})
@login_required
def get_writer(request, id):
wrt = get_object_or_404(Writer, id=id)
book = Book.objects.filter(writer_id=wrt.id)
context = {"wrt": wrt, "book": book}
return render(request, "store/writer.html", context)LOGIN_URL = '/login/'LOGIN_URL = 'store:signin' # 对应你 urls.py 中的 name="signin"