本文将通过一个完整的Django项目,对比实现两种用户认证系统:Django内置Auth组件和手动Session认证。适合Django初学者理解认证机制差异。

一、项目概述

本项目将创建一个Django项目,实现两种用户认证方式的完整示例:

  1. /auth/路径​ - 使用Django内置的auth组件

  2. /custom/路径​ - 使用自定义模型手动实现Session认证

技术对比

特性

Django内置Auth

手动Session认证

用户模型

内置User模型

自定义UserInfo模型

密码存储

自动加密

明文存储(仅演示)

登录验证

authenticate()函数

手动数据库查询

登录状态

login()自动管理

手动设置Session

访问控制

@login_required装饰器

自定义装饰器

二、环境准备

1. 环境要求

  • Python 3.8+

  • Django 4.0+

  • PyCharm(或其他Python IDE)

2. 创建虚拟环境

python -m venv venv
source venv/bin/activate  # Linux/Mac
venv\Scripts\activate     # Windows

3. 安装Django

pip install django

三、项目创建和配置

1. 创建Django项目

django-admin startproject django_auth_demo
cd django_auth_demo

2. 创建两个应用

python manage.py startapp auth_demo
python manage.py startapp custom_auth

3. 项目结构

django_auth_demo/
├── manage.py
├── auth_project/           # 项目配置目录
├── auth_demo/             # 内置Auth应用
├── custom_auth/           # 手动Session应用
└── templates/             # 全局模板目录

4. 配置settings.py

修改auth_project/settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'auth_demo',
    'custom_auth',
]

# 添加模板目录
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [
            BASE_DIR / 'templates',  # 全局模板目录
        ],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

四、实现Django内置Auth认证系统

1. 配置URL路由

主路由​ (auth_project/urls.py):

from django.contrib import admin
from django.urls import path, include
from django.shortcuts import render

def home(request):
    return render(request, 'home.html')

urlpatterns = [
    path('admin/', admin.site.urls),
    path('auth/', include('auth_demo.urls')),
    path('custom/', include('custom_auth.urls')),
    path('', home, name='home'),
]

应用路由​ (auth_demo/urls.py):

from django.urls import path
from . import views

app_name = 'auth_demo'
urlpatterns = [
    path('login/', views.auth_login, name='login'),
    path('logout/', views.auth_logout, name='logout'),
    path('index/', views.auth_index, name='index'),
    path('protected/', views.protected_view, name='protected'),
]

2. 编写视图函数 (auth_demo/views.py)

from django.shortcuts import render, redirect
from django.contrib import auth
from django.contrib.auth.decorators import login_required

def auth_login(request):
    """登录视图"""
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        user = auth.authenticate(request, username=username, password=password)
        
        if user is not None:
            auth.login(request, user)
            next_url = request.GET.get('next') or 'auth_demo:index'
            return redirect(next_url)
        else:
            return render(request, 'auth_demo/login.html', {'error': '用户名或密码错误'})
    
    return render(request, 'auth_demo/login.html')

@login_required(login_url='/auth/login/')
def auth_index(request):
    """受保护的首页"""
    return render(request, 'auth_demo/index.html', {'user': request.user})

@login_required
def protected_view(request):
    """另一个受保护页面"""
    return render(request, 'auth_demo/protected.html')

def auth_logout(request):
    """退出登录"""
    auth.logout(request)
    return redirect('auth_demo:login')

3. 创建模板文件

登录页面​ (auth_demo/templates/auth_demo/login.html):

<!DOCTYPE html>
<html>
<head>
    <title>Django Auth登录</title>
    <style>
        body { font-family: Arial; max-width: 400px; margin: 50px auto; }
        .error { color: red; }
        input { width: 100%; padding: 8px; margin: 5px 0; }
        button { background: #4CAF50; color: white; padding: 10px; border: none; }
    </style>
</head>
<body>
    <h2>Django内置Auth组件 - 登录</h2>
    {% if error %}<p class="error">{{ error }}</p>{% endif %}
    
    <form method="post">
        {% csrf_token %}
        <input type="text" name="username" placeholder="用户名" required>
        <input type="password" name="password" placeholder="密码" required>
        <button type="submit">登录</button>
    </form>
    
    <p><small>使用超级用户账号登录</small></p>
    <p><a href="/custom/register/">前往手动Session注册页面</a></p>
</body>
</html>

首页​ (auth_demo/templates/auth_demo/index.html):

<!DOCTYPE html>
<html>
<head>
    <title>Auth主页</title>
</head>
<body>
    <h2>欢迎回来,{{ user.username }}!</h2>
    <p>您已通过Django内置Auth组件成功登录。</p>
    <p>用户邮箱:{{ user.email }}</p>
    <p>超级用户:{% if user.is_superuser %}是{% else %}否{% endif %}</p>
    
    <ul>
        <li><a href="{% url 'auth_demo:protected' %}">访问受保护页面</a></li>
        <li><a href="{% url 'auth_demo:logout' %}">退出登录</a></li>
    </ul>
    
    <p><a href="/custom/">前往手动Session认证系统</a></p>
</body>
</html>

五、实现手动Session认证系统

1. 定义数据模型 (custom_auth/models.py)

from django.db import models

class UserInfo(models.Model):
    """自定义用户模型(密码明文存储,仅用于演示!)"""
    username = models.CharField(max_length=32, unique=True, verbose_name="用户名")
    password = models.CharField(max_length=64, verbose_name="密码")
    email = models.EmailField(blank=True, verbose_name="邮箱")
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
    
    def __str__(self):
        return self.username

2. 创建并应用迁移

python manage.py makemigrations custom_auth
python manage.py migrate

3. 配置URL路由 (custom_auth/urls.py)

from django.urls import path
from . import views

app_name = 'custom_auth'
urlpatterns = [
    path('', views.index, name='index'),
    path('register/', views.register, name='register'),
    path('login/', views.login_view, name='login'),
    path('logout/', views.logout_view, name='logout'),
    path('dashboard/', views.dashboard, name='dashboard'),
    path('profile/', views.profile, name='profile'),
]

4. 编写视图函数 (custom_auth/views.py)

from django.shortcuts import render, redirect
from .models import UserInfo

# 自定义登录检查装饰器
def login_required_custom(view_func):
    def wrapper(request, *args, **kwargs):
        if not request.session.get('is_logged_in'):
            return redirect('custom_auth:login')
        return view_func(request, *args, **kwargs)
    return wrapper

def index(request):
    """主页"""
    return render(request, 'custom_auth/index.html')

def register(request):
    """注册视图"""
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        email = request.POST.get('email', '')
        
        if UserInfo.objects.filter(username=username).exists():
            return render(request, 'custom_auth/register.html', {
                'error': '用户名已存在',
                'username': username,
                'email': email
            })
        
        user = UserInfo.objects.create(
            username=username,
            password=password,  # 注意:实际项目应对密码进行哈希加密!
            email=email
        )
        
        # 注册成功后自动登录
        request.session['is_logged_in'] = True
        request.session['user_id'] = user.id
        request.session['username'] = user.username
        
        return redirect('custom_auth:dashboard')
    
    return render(request, 'custom_auth/register.html')

def login_view(request):
    """登录视图"""
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        
        try:
            user = UserInfo.objects.get(username=username, password=password)
            request.session['is_logged_in'] = True
            request.session['user_id'] = user.id
            request.session['username'] = user.username
            request.session.set_expiry(3600)  # 1小时后过期
            return redirect('custom_auth:dashboard')
        except UserInfo.DoesNotExist:
            return render(request, 'custom_auth/login.html', {
                'error': '用户名或密码错误',
                'username': username
            })
    
    return render(request, 'custom_auth/login.html')

@login_required_custom
def dashboard(request):
    """用户仪表板(需要登录)"""
    user_id = request.session.get('user_id')
    try:
        user = UserInfo.objects.get(id=user_id)
    except UserInfo.DoesNotExist:
        request.session.flush()
        return redirect('custom_auth:login')
    
    return render(request, 'custom_auth/dashboard.html', {
        'user': user,
        'session_info': dict(request.session)
    })

@login_required_custom
def profile(request):
    """用户个人资料页(需要登录)"""
    user_id = request.session.get('user_id')
    try:
        user = UserInfo.objects.get(id=user_id)
    except UserInfo.DoesNotExist:
        request.session.flush()
        return redirect('custom_auth:login')
    
    return render(request, 'custom_auth/profile.html', {'user': user})

def logout_view(request):
    """退出登录"""
    request.session.flush()
    return redirect('custom_auth:index')

5. 创建模板文件

注册页面​ (custom_auth/templates/custom_auth/register.html):

<!DOCTYPE html>
<html>
<head>
    <title>注册</title>
</head>
<body>
    <h2>注册新用户</h2>
    {% if error %}<p style="color: red;">{{ error }}</p>{% endif %}
    
    <form method="post">
        {% csrf_token %}
        <p><input type="text" name="username" value="{{ username|default:'' }}" placeholder="用户名" required></p>
        <p><input type="password" name="password" placeholder="密码" required></p>
        <p><input type="email" name="email" value="{{ email|default:'' }}" placeholder="邮箱(可选)"></p>
        <button type="submit">注册</button>
    </form>
    
    <p>已有账户?<a href="{% url 'custom_auth:login' %}">立即登录</a></p>
</body>
</html>

仪表板​ (custom_auth/templates/custom_auth/dashboard.html):

<!DOCTYPE html>
<html>
<head>
    <title>用户仪表板</title>
</head>
<body>
    <h2>欢迎回来,{{ user.username }}!</h2>
    <h3>用户信息</h3>
    <ul>
        <li>用户名: {{ user.username }}</li>
        <li>邮箱: {{ user.email|default:"未设置" }}</li>
        <li>注册时间: {{ user.created_at }}</li>
    </ul>
    
    <h3>Session信息</h3>
    <pre>{{ session_info }}</pre>
    
    <h3>导航</h3>
    <ul>
        <li><a href="{% url 'custom_auth:profile' %}">查看个人资料</a></li>
        <li><a href="{% url 'custom_auth:logout' %}">退出登录</a></li>
    </ul>
    
    <p><small>这是一个通过手动Session管理登录状态的页面</small></p>
</body>
</html>

六、创建对比首页

在项目根目录创建templates/home.html

<!DOCTYPE html>
<html>
<head>
    <title>Django认证系统演示</title>
    <style>
        body { font-family: Arial; max-width: 800px; margin: 50px auto; padding: 20px; }
        .container { display: flex; justify-content: space-around; margin-top: 30px; }
        .system-box { border: 1px solid #ddd; border-radius: 8px; padding: 20px; width: 45%; }
        .auth-box { background-color: #f0f8ff; }
        .custom-box { background-color: #fff0f5; }
        .btn { display: inline-block; padding: 10px 20px; background: #4CAF50; color: white; text-decoration: none; }
    </style>
</head>
<body>
    <h1>Django用户认证系统演示</h1>
    <p>本项目包含两种用户认证实现方式,用于学习和对比:</p>
    
    <div class="container">
        <div class="system-box auth-box">
            <h2>Django内置Auth组件</h2>
            <p>使用Django自带的认证系统</p>
            <a href="/auth/login/" class="btn">体验内置Auth系统</a>
        </div>
        
        <div class="system-box custom-box">
            <h2>手动Session认证</h2>
            <p>自定义实现的认证系统</p>
            <a href="/custom/" class="btn">体验手动Session系统</a>
        </div>
    </div>
    
    <div style="margin-top: 40px;">
        <h3>技术对比</h3>
        <table style="width: 100%; border-collapse: collapse;">
            <tr>
                <th style="border: 1px solid #ddd; padding: 8px;">特性</th>
                <th style="border: 1px solid #ddd; padding: 8px;">Django内置Auth</th>
                <th style="border: 1px solid #ddd; padding: 8px;">手动Session</th>
            </tr>
            <tr>
                <td style="border: 1px solid #ddd; padding: 8px;">用户模型</td>
                <td style="border: 1px solid #ddd; padding: 8px;">内置User模型</td>
                <td style="border: 1px solid #ddd; padding: 8px;">自定义UserInfo模型</td>
            </tr>
            <tr>
                <td style="border: 1px solid #ddd; padding: 8px;">密码存储</td>
                <td style="border: 1px solid #ddd; padding: 8px;">自动加密(安全)</td>
                <td style="border: 1px solid #ddd; padding: 8px;">明文存储(演示用)</td>
            </tr>
            <tr>
                <td style="border: 1px solid #ddd; padding: 8px;">登录验证</td>
                <td style="border: 1px solid #ddd; padding: 8px;">authenticate()函数</td>
                <td style="border: 1px solid #ddd; padding: 8px;">手动数据库查询</td>
            </tr>
        </table>
    </div>
</body>
</html>

七、运行和测试

1. 创建超级用户

python manage.py createsuperuser

2. 运行开发服务器

python manage.py runserver

3. 访问测试

4. 测试流程

  1. 访问首页,选择要测试的系统

  2. 内置Auth系统:使用createsuperuser创建的账号登录

  3. 手动Session系统:先注册新用户,然后登录

  4. 观察两个系统的差异

八、核心概念总结

1. Django内置Auth组件特点

  • 自动化程度高:提供完整的认证流程

  • 安全性好:密码自动加密存储

  • 集成度高:与Django其他组件无缝集成

  • 适合场景:标准Web应用,快速开发

2. 手动Session认证特点

  • 控制度高:完全掌控认证流程

  • 灵活性强:可自定义所有环节

  • 学习价值:帮助理解认证原理

  • 适合场景:特殊需求,教学演示

3. 实际项目建议

  • 生产环境必须使用Django内置Auth或第三方认证库

  • 手动Session实现仅用于学习和理解原理

  • 实际项目中应对密码进行哈希加密(使用make_passwordcheck_password

九、常见问题解决

1. ModuleNotFoundError: No module named 'xxx'

  • 检查应用是否在settings.pyINSTALLED_APPS中注册

  • 检查应用目录是否有__init__.py文件

2. TemplateDoesNotExist

  • 检查模板路径是否正确

  • 确认TEMPLATES配置中的DIRS设置

3. 数据库迁移错误

  • 删除数据库文件db.sqlite3和迁移文件

  • 重新运行python manage.py makemigrationsmigrate

十、扩展学习

1. 安全性改进

# 在实际项目中对密码进行哈希加密
from django.contrib.auth.hashers import make_password, check_password

# 存储时加密
hashed_password = make_password('plain_password')

# 验证时比较
check_password('plain_password', hashed_password)  # 返回True/False

2. 使用Django内置Auth的自定义用户模型

from django.contrib.auth.models import AbstractUser

class CustomUser(AbstractUser):
    phone = models.CharField(max_length=20)
    # 添加自定义字段

3. 第三方认证库

  • Django-allauth:提供社交账号登录

  • Django-rest-framework:REST API认证

  • Django-oauth-toolkit:OAuth2认证

总结

通过本教程,您已经:

  1. 创建了一个包含两种认证系统的完整Django项目

  2. 理解了Django内置Auth组件的工作原理

  3. 掌握了手动Session认证的实现方法

  4. 学习了两种方式的优缺点和适用场景

这个项目可以帮助您深入理解Django认证机制,为实际项目开发打下坚实基础。建议您根据本文的代码和思路,尝试扩展更多功能,如用户权限管理、密码重置、邮箱验证等。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐