从空 Django 项目开始,到 MySQL 存储,再到 User + Role 权限控制跑通*2
·
下面从 登录页面开始,完整梳理你现在这套流程。
你现在实现的是:
用户访问登录页
↓
输入用户名和密码
↓
Django 校验账号密码
↓
登录成功
↓
根据用户角色自动跳转
↓
admin -> 管理员页面
editor -> 编辑员页面
viewer -> 查看者页面
一、最终访问地址
你的系统现在主要有这些地址:
/user/login/ 登录页面
/user/logout/ 退出登录
/user/admin-page/ 管理员页面
/user/editor-page/ 编辑员页面
/user/viewer-page/ 查看者页面
/user/no-role/ 没有角色时的提示页面
/admin/ Django 管理后台
二、登录页面文件
登录页面文件是:
user/templates/user/login.html
内容是:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>用户登录</title>
</head>
<body>
<h2>用户登录</h2>
{% if error %}
<p style="color: red;">{{ error }}</p>
{% endif %}
<form method="post">
{% csrf_token %}
<p>
<label>用户名:</label>
<input type="text" name="username">
</p>
<p>
<label>密码:</label>
<input type="password" name="password">
</p>
<button type="submit">登录</button>
</form>
</body>
</html>
这里最重要的是:
<input type="text" name="username">
<input type="password" name="password">
因为后端会通过这两个名字拿到用户名和密码。
三、登录地址对应的路由
文件是:
user/urls.py
完整内容:
from django.urls import path
from . import views
urlpatterns = [
path("login/", views.user_login, name="login"),
path("logout/", views.user_logout, name="logout"),
path("no-role/", views.no_role_page, name="no_role"),
path("admin-page/", views.admin_page, name="admin_page"),
path("editor-page/", views.editor_page, name="editor_page"),
path("viewer-page/", views.viewer_page, name="viewer_page"),
]
这一行表示:
path("login/", views.user_login, name="login")
当你访问:
/user/login/
就会执行:
views.user_login
四、项目主路由
文件是:
DjangoProject_RBAC/urls.py
内容是:
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path("admin/", admin.site.urls),
path("user/", include("user.urls")),
]
这里的意思是:
/admin/ 交给 Django 后台处理
/user/ 交给 user/urls.py 处理
所以:
/user/login/
实际匹配流程是:
DjangoProject_RBAC/urls.py
↓
path("user/", include("user.urls"))
↓
user/urls.py
↓
path("login/", views.user_login)
五、登录视图逻辑
核心文件是:
user/views.py
完整代码如下:
from functools import wraps
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.decorators import login_required
from django.core.exceptions import PermissionDenied
from django.http import HttpResponse
from django.shortcuts import redirect, render
def role_required(role_name):
def decorator(view_func):
@wraps(view_func)
def wrapper(request, *args, **kwargs):
user = request.user
if not user.is_authenticated:
return redirect("/user/login/")
if not user.role:
raise PermissionDenied("你还没有分配角色")
if user.role.name != role_name:
raise PermissionDenied("你没有权限访问这个页面")
return view_func(request, *args, **kwargs)
return wrapper
return decorator
def get_role_redirect_url(user):
"""
根据用户角色返回跳转地址
"""
if not user.role:
return "/user/no-role/"
if user.role.name == "admin":
return "/user/admin-page/"
if user.role.name == "editor":
return "/user/editor-page/"
if user.role.name == "viewer":
return "/user/viewer-page/"
return "/user/no-role/"
def user_login(request):
"""
登录页面:
GET 请求:显示登录页面
POST 请求:校验用户名和密码
"""
if request.user.is_authenticated:
return redirect(get_role_redirect_url(request.user))
if request.method == "POST":
username = request.POST.get("username")
password = request.POST.get("password")
user = authenticate(
request,
username=username,
password=password,
)
if user is not None:
login(request, user)
return redirect(get_role_redirect_url(user))
return render(
request,
"user/login.html",
{
"error": "用户名或密码错误",
},
)
return render(request, "user/login.html")
def user_logout(request):
logout(request)
return redirect("/user/login/")
@login_required
def no_role_page(request):
return HttpResponse("当前用户还没有分配角色,请联系管理员")
@login_required
@role_required("admin")
def admin_page(request):
return render(request, "user/admin_page.html")
@login_required
@role_required("editor")
def editor_page(request):
return render(request, "user/editor_page.html")
@login_required
@role_required("viewer")
def viewer_page(request):
return render(request, "user/viewer_page.html")
六、登录函数的执行流程
登录页面第一次打开时,是 GET 请求:
访问 /user/login/
↓
执行 user_login(request)
↓
request.method 不是 POST
↓
返回 login.html
对应代码:
return render(request, "user/login.html")
当你输入用户名密码并点击登录时,是 POST 请求:
输入 username 和 password
↓
点击登录
↓
提交 POST 请求到 /user/login/
↓
后端拿到 username 和 password
↓
authenticate 校验账号密码
对应代码:
username = request.POST.get("username")
password = request.POST.get("password")
user = authenticate(
request,
username=username,
password=password,
)
如果账号密码错误:
return render(
request,
"user/login.html",
{
"error": "用户名或密码错误",
},
)
页面会显示:
用户名或密码错误
如果账号密码正确:
login(request, user)
return redirect(get_role_redirect_url(user))
意思是:
让用户登录
↓
根据角色跳转到对应页面
七、根据角色自动跳转
这个函数决定登录后去哪里:
def get_role_redirect_url(user):
if not user.role:
return "/user/no-role/"
if user.role.name == "admin":
return "/user/admin-page/"
if user.role.name == "editor":
return "/user/editor-page/"
if user.role.name == "viewer":
return "/user/viewer-page/"
return "/user/no-role/"
所以跳转规则是:
| 用户角色 | 登录后跳转 |
|---|---|
| admin | /user/admin-page/ |
| editor | /user/editor-page/ |
| viewer | /user/viewer-page/ |
| 没有角色 | /user/no-role/ |
例如你的 admin 用户角色是:
管理员 admin
所以登录成功后会跳到:
/user/admin-page/
八、权限装饰器的作用
这个函数是权限控制核心:
def role_required(role_name):
def decorator(view_func):
@wraps(view_func)
def wrapper(request, *args, **kwargs):
user = request.user
if not user.is_authenticated:
return redirect("/user/login/")
if not user.role:
raise PermissionDenied("你还没有分配角色")
if user.role.name != role_name:
raise PermissionDenied("你没有权限访问这个页面")
return view_func(request, *args, **kwargs)
return wrapper
return decorator
它的作用是:
检查当前用户是否登录
检查当前用户是否有角色
检查当前用户角色是否匹配页面要求
例如管理员页面:
@login_required
@role_required("admin")
def admin_page(request):
return render(request, "user/admin_page.html")
意思是:
必须登录
并且角色必须是 admin
才能访问 admin_page
九、三个独立页面
1. 管理员页面
文件:
user/templates/user/admin_page.html
内容:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>管理员页面</title>
</head>
<body>
<h2>管理员页面</h2>
<p>当前用户:{{ request.user.username }}</p>
<p>当前角色:{{ request.user.role }}</p>
<p>这是管理员专属页面,只有 admin 可以访问。</p>
<a href="/user/logout/">退出登录</a>
</body>
</html>
对应视图:
@login_required
@role_required("admin")
def admin_page(request):
return render(request, "user/admin_page.html")
2. 编辑员页面
文件:
user/templates/user/editor_page.html
内容:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>编辑员页面</title>
</head>
<body>
<h2>编辑员页面</h2>
<p>当前用户:{{ request.user.username }}</p>
<p>当前角色:{{ request.user.role }}</p>
<p>这是编辑员专属页面,只有 editor 可以访问。</p>
<a href="/user/logout/">退出登录</a>
</body>
</html>
对应视图:
@login_required
@role_required("editor")
def editor_page(request):
return render(request, "user/editor_page.html")
3. 查看者页面
文件:
user/templates/user/viewer_page.html
内容:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>查看者页面</title>
</head>
<body>
<h2>查看者页面</h2>
<p>当前用户:{{ request.user.username }}</p>
<p>当前角色:{{ request.user.role }}</p>
<p>这是查看者专属页面,只有 viewer 可以访问。</p>
<a href="/user/logout/">退出登录</a>
</body>
</html>
对应视图:
@login_required
@role_required("viewer")
def viewer_page(request):
return render(request, "user/viewer_page.html")
十、退出登录流程
退出地址是:
/user/logout/
路由是:
path("logout/", views.user_logout, name="logout")
视图是:
def user_logout(request):
logout(request)
return redirect("/user/login/")
流程是:
点击退出登录
↓
访问 /user/logout/
↓
Django 清除当前登录状态
↓
跳回 /user/login/
十一、用户和角色的数据库关系
你现在的模型是:
User 用户
Role 角色
一个用户对应一个角色。
数据库关系:
role 表
id
name
desc
user 表
id
username
password
email
phone
role_id
关系是:
user.role_id -> role.id
例如:
role 表:
id name
1 admin
2 editor
3 viewer
user 表:
id username role_id
1 admin 1
所以:
admin 用户 -> role_id = 1 -> admin 角色
十二、后台操作流程
你现在在 Django 后台做了这些事:
1. 创建超级管理员 admin
2. 创建三个角色:
admin
editor
viewer
3. 给 admin 用户分配 admin 角色
后台地址:
/admin/
角色管理:
Role / 角色
用户管理:
User / 用户
十三、完整登录访问流程
以 admin 用户为例:
浏览器访问:
/user/login/
↓ 输入账号密码
username = admin
password = 你的密码
↓ 点击登录
POST /user/login/
↓ 后端执行
user_login(request)
↓ 校验账号密码
authenticate(request, username, password)
↓ 登录成功
login(request, user)
↓ 判断角色
user.role.name == "admin"
↓ 自动跳转
/user/admin-page/
↓ 进入管理员页面
admin_page(request)
↓ 权限判断
@role_required("admin")
↓ 判断通过
渲染 admin_page.html
↓ 页面显示
管理员页面
当前用户:admin
当前角色:管理员
十四、如果访问错误页面会怎样
如果当前用户是 admin,但是访问:
/user/editor-page/
流程是:
访问 editor_page
↓
@role_required("editor")
↓
当前用户角色是 admin
↓
admin != editor
↓
抛出 PermissionDenied
↓
显示 403 Forbidden
这说明权限控制生效了。
十五、当前项目核心文件
你现在这套登录和权限跳转,主要靠这些文件:
DjangoProject_RBAC/urls.py
DjangoProject_RBAC/settings.py
user/models.py
user/admin.py
user/views.py
user/urls.py
user/templates/user/login.html
user/templates/user/admin_page.html
user/templates/user/editor_page.html
user/templates/user/viewer_page.html
role/models.py
role/admin.py
十六、最终效果总结
你现在已经实现了:
1. 用户访问登录页面
2. 输入账号密码
3. Django 验证用户
4. 登录成功后判断用户角色
5. admin 自动进入管理员页面
6. editor 自动进入编辑员页面
7. viewer 自动进入查看者页面
8. 不同角色不能访问别人的页面
9. 点击退出登录返回登录页
10. 用户和角色数据存储在 MySQL
也就是一个完整的:
Django + MySQL + User + Role + 登录认证 + 角色跳转 + 页面权限控制
系统。
更多推荐




所有评论(0)