feat(认证): 添加用户登录和注销功能
添加用户认证功能,包括登录页面、视图逻辑和模板 配置登录URL设置并保护首页视图需要认证 在导航栏添加登录状态显示和操作按钮
This commit is contained in:
19
core/migrations/0007_alter_insightrecord_speaker.py
Normal file
19
core/migrations/0007_alter_insightrecord_speaker.py
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# Generated by Django 5.1.4 on 2026-01-28 10:34
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('core', '0006_add_summary'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='insightrecord',
|
||||||
|
name='speaker',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.familymember', verbose_name='发言人'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -66,6 +66,18 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<ul class="navbar-nav">
|
<ul class="navbar-nav">
|
||||||
|
{% if user.is_authenticated %}
|
||||||
|
<li class="nav-item">
|
||||||
|
<span class="nav-link">欢迎,{{ user.username }}</span>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="{% url 'logout' %}">注销</a>
|
||||||
|
</li>
|
||||||
|
{% else %}
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="{% url 'login' %}">登录</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="/houtai/">后台管理</a>
|
<a class="nav-link" href="/houtai/">后台管理</a>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
27
core/templates/core/login.html
Normal file
27
core/templates/core/login.html
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
{% extends 'core/base.html' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header bg-primary text-white">
|
||||||
|
<h5 class="card-title mb-0 text-center">用户登录</h5>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<form method="POST">
|
||||||
|
{% csrf_token %}
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="username" class="form-label">用户名</label>
|
||||||
|
<input type="text" class="form-control" id="username" name="username" required>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="password" class="form-label">密码</label>
|
||||||
|
<input type="password" class="form-control" id="password" name="password" required>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-primary w-100">登录</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
@@ -2,6 +2,10 @@ from django.urls import path
|
|||||||
from . import views
|
from . import views
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
|
# 登录和注销
|
||||||
|
path('login/', views.user_login, name='login'),
|
||||||
|
path('logout/', views.user_logout, name='logout'),
|
||||||
|
|
||||||
# 首页
|
# 首页
|
||||||
path('', views.index, name='index'),
|
path('', views.index, name='index'),
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,9 @@ from django.db.models import Count
|
|||||||
from django.core.mail import send_mail, EmailMessage
|
from django.core.mail import send_mail, EmailMessage
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.views.decorators.csrf import csrf_exempt
|
from django.views.decorators.csrf import csrf_exempt
|
||||||
|
from django.contrib.auth import authenticate, login, logout
|
||||||
|
from django.contrib.auth.decorators import login_required
|
||||||
|
from django.contrib import messages
|
||||||
from datetime import timedelta, datetime
|
from datetime import timedelta, datetime
|
||||||
import os
|
import os
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
@@ -55,6 +58,7 @@ from .forms import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
# 首页视图
|
# 首页视图
|
||||||
|
@login_required
|
||||||
def index(request):
|
def index(request):
|
||||||
"""首页"""
|
"""首页"""
|
||||||
logger.info("用户访问首页")
|
logger.info("用户访问首页")
|
||||||
@@ -864,3 +868,39 @@ def api_submit_summary(request):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"API: 提交汇总记录失败: {str(e)}")
|
logger.error(f"API: 提交汇总记录失败: {str(e)}")
|
||||||
return JsonResponse({'success': False, 'message': f"提交失败: {str(e)}"}, status=500)
|
return JsonResponse({'success': False, 'message': f"提交失败: {str(e)}"}, status=500)
|
||||||
|
|
||||||
|
# 登录视图
|
||||||
|
def user_login(request):
|
||||||
|
"""用户登录"""
|
||||||
|
if request.user.is_authenticated:
|
||||||
|
logger.info(f"用户 {request.user.username} 已登录,重定向到首页")
|
||||||
|
return redirect('index')
|
||||||
|
|
||||||
|
if request.method == 'POST':
|
||||||
|
username = request.POST.get('username')
|
||||||
|
password = request.POST.get('password')
|
||||||
|
|
||||||
|
logger.info(f"用户登录尝试: {username}")
|
||||||
|
|
||||||
|
user = authenticate(request, username=username, password=password)
|
||||||
|
|
||||||
|
if user is not None:
|
||||||
|
login(request, user)
|
||||||
|
logger.info(f"用户 {username} 登录成功")
|
||||||
|
messages.success(request, '登录成功!')
|
||||||
|
return redirect('index')
|
||||||
|
else:
|
||||||
|
logger.warning(f"用户 {username} 登录失败: 用户名或密码错误")
|
||||||
|
messages.error(request, '用户名或密码错误,请重新尝试。')
|
||||||
|
|
||||||
|
return render(request, 'core/login.html')
|
||||||
|
|
||||||
|
# 注销视图
|
||||||
|
def user_logout(request):
|
||||||
|
"""用户注销"""
|
||||||
|
if request.user.is_authenticated:
|
||||||
|
logger.info(f"用户 {request.user.username} 注销")
|
||||||
|
logout(request)
|
||||||
|
messages.success(request, '已成功注销!')
|
||||||
|
|
||||||
|
return redirect('login')
|
||||||
|
|||||||
@@ -124,6 +124,9 @@ STATIC_URL = 'static/'
|
|||||||
|
|
||||||
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
||||||
|
|
||||||
|
# Login URL configuration
|
||||||
|
LOGIN_URL = '/login/'
|
||||||
|
|
||||||
# Media files configuration
|
# Media files configuration
|
||||||
MEDIA_URL = '/media/'
|
MEDIA_URL = '/media/'
|
||||||
MEDIA_ROOT = BASE_DIR / 'media'
|
MEDIA_ROOT = BASE_DIR / 'media'
|
||||||
|
|||||||
Reference in New Issue
Block a user