修复了用户邮箱登录的问题

This commit is contained in:
王思川 2024-06-15 12:34:06 +08:00
parent 639aa38f7f
commit 57c9063ea9
8 changed files with 1779 additions and 137 deletions

View File

@ -1,36 +1,18 @@
"""
Django settings for XH_Digital_Management project.
Generated by 'django-admin startproject' using Django 5.0.6.
For more information on this file, see
https://docs.djangoproject.com/en/5.0/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/5.0/ref/settings/
"""
import os
import os
from pathlib import Path
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/5.0/howto/deployment/checklist/
SECRET_KEY = "django-insecure-m0r-(%p2^vzpb*5*4w4k8v$$h29zy=-!hul_hoj@m)-ykbr$c@" # 严格保密!
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = "django-insecure-m0r-(%p2^vzpb*5*4w4k8v$$h29zy=-!hul_hoj@m)-ykbr$c@"
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
DEBUG = True # 生产环节关闭调试!
ALLOWED_HOSTS = [
"o339q23220.goho.co",
"localhost"
]
# Application definition
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
@ -113,15 +95,12 @@ TEMPLATES = [
WSGI_APPLICATION = "XH_Digital_Management.wsgi.application"
# Database
# https://docs.djangoproject.com/en/5.0/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'xh_digital_manage', # 数据库名
'USER': 'office', # 用户名
'PASSWORD': 'office240603..', # 密码
'USER': 'wsc', # 用户名
'PASSWORD': 'jsxh9512..', # 密码
'HOST': 'bj-cdb-7qxczedm.sql.tencentcdb.com', # 地址
'PORT': '59450', # 端口号
'OPTIONS': {
@ -131,9 +110,6 @@ DATABASES = {
},
}
# Password validation
# https://docs.djangoproject.com/en/5.0/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
@ -149,9 +125,6 @@ AUTH_PASSWORD_VALIDATORS = [
},
]
# Internationalization
# https://docs.djangoproject.com/en/5.0/topics/i18n/
LANGUAGE_CODE = "zh-hans"
TIME_ZONE = "Asia/Shanghai"
@ -160,18 +133,12 @@ USE_I18N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/5.0/howto/static-files/
STATIC_URL = "/static/"
STATICFILES_DIRS = [
BASE_DIR / 'static',
]
# Default primary key field type
# https://docs.djangoproject.com/en/5.0/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
LOGIN_REDIRECT_URL = '/' # 登录后重定向的URL
@ -179,3 +146,10 @@ LOGOUT_REDIRECT_URL = '/' # 登出后重定向的URL
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
AUTHENTICATION_BACKENDS = [
'application.accounts.backends.EmailBackend',
'django.contrib.auth.backends.ModelBackend',
]
REMEMBER_ME_DURATION = 1209600 # 记住我账户登录状态持续14天

View File

@ -0,0 +1,14 @@
from django.contrib.auth.backends import ModelBackend
from django.contrib.auth import get_user_model
User = get_user_model()
class EmailBackend(ModelBackend):
def authenticate(self, request, username=None, password=None, **kwargs):
try:
user = User.objects.get(email=username)
if user.check_password(password):
return user
except User.DoesNotExist:
return None

View File

@ -1,6 +1,25 @@
from django import forms
from django.contrib.auth import get_user_model
from django.contrib.auth.forms import AuthenticationForm
class CustomAuthenticationForm(AuthenticationForm):
User = get_user_model()
class EmailAuthenticationForm(AuthenticationForm):
username = forms.EmailField(label="Email", required=True)
password = forms.CharField(label="Password", widget=forms.PasswordInput, required=True)
def clean(self):
email = self.cleaned_data.get('username')
password = self.cleaned_data.get('password')
if email and password:
try:
user = User.objects.get(email=email)
if not user.check_password(password):
raise forms.ValidationError('请输入一个正确的用户名和密码。注意,两者都区分大小写。')
except User.DoesNotExist:
raise forms.ValidationError('请输入一个正确的用户名和密码。注意,两者都区分大小写。')
return self.cleaned_data

View File

@ -1,64 +1,60 @@
<!DOCTYPE html>
<html lang="en">
{% load static %}
<head>
<title>数字化管理系统-登录</title>
<title>星环集团-数字化管理系统-登录</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0, minimal-ui">
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<!-- 网站图标 -->
<link rel="icon" href="{% static 'images/favicon.svg' %}" type="image/x-icon">
<!-- fontawesome icon -->
<link rel="stylesheet" href="{% static 'fonts/fontawesome/css/fontawesome-all.min.css' %}">
<!-- animation css -->
<link rel="stylesheet" href="{% static 'plugins/animation/css/animate.min.css' %}">
<!-- vendor css -->
<link rel="stylesheet" href="{% static 'css/style.css' %}">
<script src="{% static 'js/particles.js' %}"></script>
<style>
#particles-js {
position: absolute;
width: 100%;
height: 100%;
background: linear-gradient(135deg, #41317f, #382a6d, #2f235b);
background-repeat: no-repeat;
background-size: cover;
}
.auth-wrapper {
position: relative;
z-index: 1;
}
</style>
</head>
<body>
<div id="alertContainer" style="position: fixed; top: 10px; right: 10px; z-index: 9999; width: 300px;"></div>
{% if user.is_authenticated %}
<!-- 用户已登录时重定向到首页 -->
<script type="text/javascript">
window.location.href = "{% url 'index' %}";
</script>
{% else %}
<!-- [ auth-signin ] start -->
<div id="particles-js"></div>
<div class="auth-wrapper">
<div class="auth-content container">
<div class="card">
<div class="row align-items-center">
<div class="col-md-6">
<!-- 添加Django表单处理的action和method -->
<form method="post" action="{% url 'user_login' %}">
{% csrf_token %}
<div class="card-body">
<!-- LOGO -->
<img src="{% static 'images/logo-dark.svg' %}" alt="" class="img-fluid mb-4">
<h4 class="mb-3 f-w-400">欢迎登录 星环集团 数字化管理系统</h4>
<!-- 表单字段使用Django的表单变量 -->
<div class="form-group mb-2">
<label class="form-label" for="id_username">用户名</label>
<input type="text" name="username" class="form-control" placeholder="请输入用户名称" id="id_username">
</div>
<div class="form-group mb-3">
<label class="form-label" for="id_password">密码</label>
<input type="password" name="password" class="form-control" placeholder="请输入登录密码" id="id_password">
</div>
<div class="form-group text-start mt-2">
<div class="checkbox checkbox-primary d-inline">
<input type="checkbox" name="remember_me" id="checkbox-fill-a1">
<label for="checkbox-fill-a1" class="cr">记住我</label>
</div>
</div>
<!-- 提交按钮 -->
<button type="submit" class="btn btn-primary mb-4">登录</button>
<p class="mb-2 text-muted">忘记密码? <a href="{% url 'password_reset' %}" class="f-w-400">重置密码</a></p>
<h4 class="mb-3 f-w-400">欢迎登录 星环集团 数字化管理系统</h4>
<div class="form-group mb-2">
<label class="form-label" for="id_username">邮箱</label>
<input type="email" name="username" class="form-control" placeholder="请输入邮箱" id="id_username">
</div>
<div class="form-group mb-3">
<label class="form-label" for="id_password">密码</label>
<input type="password" name="password" class="form-control" placeholder="请输入登录密码" id="id_password">
</div>
<div class="form-group text-start mt-2">
<div class="checkbox checkbox-primary d-inline">
<input type="checkbox" name="remember_me" id="checkbox-fill-a1">
<label for="checkbox-fill-a1" class="cr">记住我</label>
</div>
</div>
<button type="submit" class="btn btn-primary mb-4">登录</button>
</div>
</form>
</div>
@ -69,13 +65,138 @@
</div>
</div>
</div>
<!-- [ auth-signin ] end -->
<!-- Required Js -->
<script src="{% static 'js/vendor-all.min.js' %}"></script>
<script src="{% static 'plugins/bootstrap/js/bootstrap.min.js' %}"></script>
{% endif %}
</body>
<script src="{% static 'plugins/bootstrap/js/bootstrap.min.js' %}"></script>
<script src="{% static 'js/jquery.com_jquery-3.6.0.js' %}"></script>
<script>
particlesJS('particles-js', {
"particles": {
"number": {
"value": 80,
"density": {
"enable": true,
"value_area": 800
}
},
"color": {
"value": "#efedf8" // 粒子颜色
},
"shape": {
"type": "circle",
"stroke": {
"width": 0,
"color": "#000000"
},
"polygon": {
"nb_sides": 5
},
"image": {
"src": "img/github.svg",
"width": 100,
"height": 100
}
},
"opacity": {
"value": 0.5,
"random": false,
"anim": {
"enable": false,
"speed": 1,
"opacity_min": 0.1,
"sync": false
}
},
"size": {
"value": 3,
"random": true,
"anim": {
"enable": false,
"speed": 40,
"size_min": 0.1,
"sync": false
}
},
"line_linked": {
"enable": true,
"distance": 150,
"color": "#efedf8", // 粒子线条颜色
"opacity": 0.4,
"width": 1
},
"move": {
"enable": true,
"speed": 6,
"direction": "none",
"random": false,
"straight": false,
"out_mode": "out",
"bounce": false,
"attract": {
"enable": false,
"rotateX": 600,
"rotateY": 1200
}
}
},
"interactivity": {
"detect_on": "canvas",
"events": {
"onhover": {
"enable": true,
"mode": "repulse"
},
"onclick": {
"enable": true,
"mode": "push"
},
"resize": true
},
"modes": {
"grab": {
"distance": 400,
"line_linked": {
"opacity": 1
}
},
"bubble": {
"distance": 400,
"size": 40,
"duration": 2,
"opacity": 8,
"speed": 3
},
"repulse": {
"distance": 200,
"duration": 0.4
},
"push": {
"particles_nb": 4
},
"remove": {
"particles_nb": 2
}
}
},
"retina_detect": true
});
</script>
<script>
window.onload = function() {
{% if messages %}
{% for message in messages %}
showAlert('danger', '{{ message }}');
{% endfor %}
{% endif %}
}
function showAlert(type, message) {
const alertHtml = `
<div class="alert alert-${type} alert-dismissible fade show" role="alert">
<strong>操作提示:</strong> ${message}
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
</div>`;
$('#alertContainer').html(alertHtml);
}
</script>
</html>

View File

@ -6,7 +6,7 @@ from .views import *
urlpatterns = [
# 账号基本操作,登录、退出、密码重置
path('login/', auth_views.LoginView.as_view(template_name='accounts/login.html'), name='user_login'),
path('login/', custom_login_view, name='user_login'),
path('logout/', logout_view, name='user_logout'),
path('password_reset/', include('django.contrib.auth.urls')),
path('homepage', user_homepage_view, name='user_homepage'),

View File

@ -2,7 +2,6 @@
import json
from datetime import datetime, date
from django.contrib.auth.forms import AuthenticationForm
from django.db import transaction
from django.db.models import Q, Sum
from django.http import JsonResponse
@ -10,13 +9,14 @@ from django.shortcuts import redirect, render, get_object_or_404
# Django组件导入
from django.contrib import messages
from django.contrib.auth import logout, authenticate, login
from django.contrib.auth import logout, login, authenticate
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import Permission, User, Group
from django.utils.timezone import now
from django.views.decorators.csrf import csrf_protect
from django.views.decorators.http import require_http_methods
from application.accounts.forms import EmailAuthenticationForm
# 本地Django应用导入
from application.accounts.models import AccountProfile
from application.accounts.viewmodels import UserPermissionItem
@ -24,7 +24,7 @@ from application.hrm_mgnt.models import AnnualLeaveRecord
from application.hrm_mgnt.models import EmployeeInformation
from application.perf_mgnt.models import EmployeePerformanceTarget
from application.pjt_mgnt.models import ProjectLedger
from common.auth import group_required, custom_permission_required
from common.auth import custom_permission_required
from common.utils.page_helper import paginate_query_and_assign_numbers
from pypinyin import lazy_pinyin
@ -77,40 +77,35 @@ def format_permissions(permissions):
@csrf_protect
def custom_login_view(request):
template_name = 'accounts/login.html'
# 用户已登录,重定向到首页或其他页面
if request.user.is_authenticated:
return redirect('home') # 替换 'home' 为实际的重定向目标
return redirect('user_homepage')
if request.method == 'POST':
form = AuthenticationForm(request, data=request.POST)
if form.is_valid():
username = form.cleaned_data.get('username')
password = form.cleaned_data.get('password')
form = EmailAuthenticationForm(data=request.POST)
# 邮箱登录逻辑
if '@' in username:
try:
user = User.objects.get(email=username)
if user.check_password(password):
login(request, user)
return redirect('home') # 替换 'home' 为实际的重定向目标
else:
messages.error(request, '用户名或密码错误。')
except User.DoesNotExist:
messages.error(request, '用户名或密码错误。')
else:
# 用户名登录逻辑
user = authenticate(request, username=username, password=password)
if user is not None and user.is_active:
login(request, user)
return redirect('home') # 替换 'home' 为实际的重定向目标
if form.is_valid():
email = form.cleaned_data.get('username')
password = form.cleaned_data.get('password')
remember_me = request.POST.get('remember_me')
user = authenticate(request, username=email, password=password)
if user is not None:
login(request, user)
if remember_me:
request.session.set_expiry(settings.REMEMBER_ME_DURATION)
else:
messages.error(request, '用户名或密码错误。')
request.session.set_expiry(0)
return redirect('user_homepage')
else:
messages.error(request, '邮箱或密码错误。')
else:
messages.error(request, '用户名或密码错误。')
messages.error(request, '表单无效,请检查输入的内容。')
return redirect('user_login')
else:
form = AuthenticationForm()
form = EmailAuthenticationForm()
return render(request, template_name, {'form': form})

View File

@ -1,26 +1,4 @@
@charset "UTF-8";
/**======================================================================
=========================================================================
Template Name: Dasho Admin Template
Author: Phoenixcoded
File: style.css
更多下载Http://www.bootstrapmb.com
=========================================================================
=========================================================================
== Table of Contents==
- Generic classes
- Margin, Padding, Font class, text align, position, floating, overflow, background class, text color, display class, boarder class
- Theme Elements
- Accordion, Button, tabs, typography, buttons, box shadow, Lable & Badges, Alert, Pagination, Breadcumb, Cards, Collapse,
- Carousel, Grid, Progress, Model, tooltip, popover, Datepicker, Gridstack, lightbox, notification, Nestable, pnotify, rating,
- Rangeslider, Slider, Syntax Highlighter, Tour, Treeview, Toolbar, Session Timeout, Session idle Timeout, offline, Animation
- Forms
- Forms Elements, Advance Form Control, Validation, Masking, Wizard, Picker, Select
- Pages
- Chat, authentication, Maintenance, Maps, Landingpage messages, task, Todo, Notes, Charts, Icons, Gallery, Editors,
- Invoice, Full Calender, File Upload,
=================================================================================
=================================================================================== */
/*
description Of variables for build for theme layouts
1) menu-caption-color

1541
static/js/particles.js Normal file

File diff suppressed because it is too large Load Diff