前后端实现简单账号密码登录
涉及知识点
- Django框架
- MySQL
- html+css+javascript
- Ajax
- Node.js
原理
利用python中的Django框架创建一个model类,注册账号写入数据库,登录简单验证是否与数据库相匹配。前端主页利用vue.js实现图片轮播,Ajax发送post请求与服务器交互,利用Node.js的cors模块解决跨域问题
效果图
前端代码
前端代码图片路径需要放在项目static文件夹中,并加载
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>游戏主页</title>
{% load static %}
<style type="text/css">
#main{
width: 100%;
height: 100%;
background-image:url({% static 'img/index.jpg' %});
background-repeat: no-repeat;
background-size: cover;
}
button{
border: 1px solid blue;
background-color: blue;
color: whitesmoke;
width: 100px;
height:30px;
border-radius: 10px;
}
#login{
position: absolute;
top: 85%;
left: 40%;
}
#res{
position:absolute;
top: 85%;
left: 50%;
margin-left:5rem ;
}
a{
text-decoration: none;
color: whitesmoke;
}
.left{
width: 50px;
height: 100px;
position: absolute;
top: 30%;
}
.right{
width: 50px;
height: 100px;
position: absolute;
top:30%;
left: 90%;
}
.index{
width: 1300px;
height: 600px;
}
</style>
</head>
<body>
{% load static %}
<div id="main">
<img :src="imgArr[index]" class="index" v-on:mouseover="change" v-on:mouseout="stop">
<br/>
<!-- <a href="javascript:void[0]" @click="prev" v-show="index!=0" ><img src="{% static 'img/left.jpg' %}" class="left"></a>-->
<!-- <a href="javascript:void[0]" @click="next" v-show="index<imgArr.length-1" ><img src="{% static 'img/right.jpg' %}" class="right"></a>-->
<button id="login"><a href="{% url 'login' %}">登录</a></button>
<button id="res"><a href="{% url 'res' %}">注册</a></button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
{% load static %}
var app = new Vue({
el:'#main',
data:{
imgArr:[
'{% static "img/b1.jpg" %}',
'{% static "img/b2.jpg" %}',
'{% static "img/b3.jpg" %}',
'{% static "img/b4.jpg" %}',
'{% static "img/b5.jpg" %}',
],
index:0,
timer:0
},
methods:{
prev:function (){
this.index--;
},
next:function (){
this.index++;
if(this.index===5){
this.index=0
}
},
change:function(){
this.timer=setInterval(this.next,3500);
},
stop:function (){
clearInterval(this.timer)
}
}
})
</script>
</body>
</html>
res.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>注册</title>
{% load static %}
<style type="text/css">
div{
width: 100%;
height: 40rem;
text-align: center;
background: url({% static 'img/index.jpg' %}) no-repeat;
background-size: cover;
}
form{
position: relative;
top: 70%;
color: whitesmoke;
}
</style>
</head>
<body>
<div>
<form action="{% url 'doupload' %}" method="post" enctype="multipart/form-data">
{% csrf_token%}
<p>昵称:<input type="text" placeholder="请输入昵称" name="name"/></p>
<p>密码:<input type="text" placeholder="请输入密码" name="pwd"/></p>
<input type="submit" value="注册" id="submit">
</form>
</div>
<script>
btn=document.getElementById('submit')
btn.onclick=function (){
alert('提交成功');
}
</script>
</body>
</html>
login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<title>登录</title>
{% load static %}
<style type="text/css">
div{
width: 100%;
height: 40rem;
text-align: center;
background: url({% static 'img/index.jpg' %}) no-repeat;
background-size: cover;
}
form{
position: relative;
top: 70%;
color: whitesmoke;
}
</style>
</head>
<body>
<div>
<form action="{% url 'dologin' %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
<p>昵称:<input type="text" name="my_name" id="name" required/></p>
<p>密码:<input type="text" name="my_pwd" id="pwd" required/></p>
<input type="submit" value="登录" id="btn">
</form>
</div>
<script>
btn=document.getElementById('btn');
names=document.getElementById('name');
pwd=document.getElementById('pwd');
$('#btn').on('click',function(){
$.ajax({
type:'POST',
url:'http://127.0.0.1:8080/server',
data:{name:names.value,passwd:pwd.value},
success:function(response){
console.log(response)
}
})
})
</script>
</body>
</html>
main.js
const express=require('express')
const app=express()
app.use(express.urlencoded({ extended:false }))
const cors=require('cors')
app.use(cors())
app.post('/server',(request,response)=>{
const body=request.body
response.send({
status:0,
msg:'登陆成功',
data:body
})
});
app.listen(8080,()=>{
console.log('服务已经启动');
})
info.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h3>{{info}}</h3>
</body>
</html>
error.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script>
window.onload=function (){
alert('账号密码错误!');
}
</script>
</body>
</html>
WZ.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
{% load static %}
<style type="text/css">
*{
margin: 0;
padding: 0;
}
.king{
width: 100%;
height: 40rem;
position: relative;
background: radial-gradient(circle,#ccc,#161d4f 85%);
}
.player-layout{
position: relative;
width: 100%;
height: 8rem;
top:50%;
transform: translate(0,-50%);
background: linear-gradient(to right,#212f4620,#212f4670,#212f4620);
}
.center{
position: absolute;
height: 8rem;
width: 8rem;
top: 50%;
left: 50%;
transform: translate(-50%,-50%) rotate(-45deg);
padding: 0.2rem;
border: 0.3rem solid #55a9ef;
box-shadow: 0 0 0.8rem #88c0f0;
background: linear-gradient(90deg,#212f4620,#5b99ff);
}
.center img{
width: 100%;
height: 100%;
}
.group{
position: relative;
width: calc((100% - 13rem)/2);
top:50%;
transform: translate(0,-50%);
z-index: 99;
}
.player{
position: relative;
display: inline-block;
width: 4rem;
height: 4rem;
background: url({% static '/img/dc.png' %});
background-size: cover;
border: 0.3rem solid #55a9ef;
box-shadow: 0 0 .8rem #88c0f0;
}
.group1{
float: left;
text-align: right;
}
.group2{
float: right;
text-align: left;
}
.player:before,.player:after{
position: absolute;
content: '';
top: 0;
right: 0;
bottom: 0;
left: 0;
margin: -8%;
box-shadow: inset 0 0 0 0.3rem #fff;
animation: clipMe 6s linear infinite;
}
.player:before{
animation-delay: -3s;
}
@keyframes clipMe{
0%{
clip: rect(0,4.8rem,4.8rem,4.3rem);
}
25%{
clip: rect(0,4.8rem,0.3rem,0);
}
50%{
clip: rect(0,0.3rem,4.8rem,0);
}
75%{
clip: rect(4.3rem,4.8rem,4.8rem,0);
}
100%{
clip: rect(0,4.8rem,4.8rem,4.3rem);
}
}
.group:before,.group:after{
position: absolute;
content: '';
width: 10rem;
height: 0.3rem;
background: linear-gradient(to right,#212f4602,#4499d7,#212f4602);
}
.group:before{
top: -1.5rem;
}
.group:after{
top: -1.5rem;
}
.group1:before{
right: 0;
}
.group1:after{
right: 5rem;
}
.group2:after{
left: 5rem;
}
.square{
position: absolute;
width: 16.7rem;
height: 16.7rem;
padding: .4rem;
border: 0.1rem solid #7499d7;
top: 50%;
left: 50%;
transform: translate(-50%,-50%) rotate(-45deg);
z-index: 1;
}
.border{
text-align: center;
position: absolute;
width: 16.7rem;
height: 16.7rem;
animation: text-an 1.5s linear infinite;
}
@keyframes text-an{
0%{
text-shadow: 0 0 0 #fff;
}
100%{
text-shadow: 0 -6rem .4rem #fff;
}
}
.border:before,.border:after{
position: absolute;
display: block;
width: 100%;
height: 2.5rem;
color: #fff;
background: linear-gradient(to top,#212f4602,#7499d7);
}
.border1:before{
content: '匹配成功';
}
.border1:after{
content: '秀起来';
bottom: 0;
transform: rotate(180deg);
}
.border2{
transform: rotate(90deg);
}
.border2:before{
content: '是你吗?';
}
.border2:after{
content: '秀';
bottom: 0;
transform: rotate(180deg);
}
.button{
position: relative;
background: #3e3a31;
width: 6.5rem;
height: 2rem;
line-height: 2rem;
text-align: center;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
color: #fff;
z-index: 11;
cursor: pointer;
}
.button:before,.button:after{
position: absolute;
content: '';
display: block;
width: 0;
height: 0;
border-width: 1.43rem;
border-style: solid;
border-color: #3e3a31 transparent transparent transparent;
}
.button:before{
transform: rotate(-135deg);
left: -1.39rem;
top: -1.41rem;
}
.button:after{
transform: rotate(135deg);
right: -1.39rem;
top: -1.4rem;
}
</style>
</head>
<body>
{% load static %}
<div class="king">
<div class="group group1">
<div class="player"></div>
<div class="player"></div>
<div class="player"></div>
<div class="player"></div>
<div class="player"></div>
</div>
<div class="group group2">
<div class="player"></div>
<div class="player"></div>
<div class="player"></div>
<div class="player"></div>
<div class="player"></div>
</div>
<div class="player-layout">
<div class="center">
<img src="{% static '/img/dc.png' %}"/>
</div>
<div class="square">
<div class="border border1"></div>
<div class="border border2"></div>
</div>
</div>
<div class="button">确认</div>
</div>
<script>
window.onload=function (){
const x=new XMLHttpRequest();
x.open('POST','http://127.0.0.1:8080/server');
x.send();
x.onreadystatechange=function (){
if(x.readyState===4){
if(x.status>=200&&x.status<=300){
console.log(x.response);
}
}
}
}
</script>
</body>
</html>
后端代码
setting.py
from pathlib import Path
import os
# 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/3.1/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'e$&4ho0gu@b1#4y8qc%fp53h-xw&!kz06s@xd8k8@k3f78rtry'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = ['*']
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'MyApp',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'WangZhe.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR,'templates')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'WangZhe.wsgi.application'
# Database
# https://docs.djangoproject.com/en/3.1/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'db_test',
'USER':'root',
'PASSWORD':'*****',
'HOST':'localhost',
'PORT':3306
}
}
# Password validation
# https://docs.djangoproject.com/en/3.1/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/3.1/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.1/howto/static-files/
STATIC_URL = '/static/'
STATICFILES_DIRS = (
os.path.join(BASE_DIR, "static"),
)
urls.py(主路由)
from django.contrib import admin
from django.urls import path,include
urlpatterns = [
path('admin/', admin.site.urls),
path('',include('MyApp.urls'))
]
models.py
from django.db import models
from datetime import datetime
# Create your models here.
class WZ(models.Model):
id=models.AutoField(primary_key=True)
name=models.CharField(max_length=100,unique=True) #账号名
passwd=models.IntegerField() #账号密码
time=models.DateTimeField(default=datetime.now)#注册时间
class Meta:
db_table='wz'
urls.py
from django.contrib import admin
from django.urls import path
from MyApp import views
urlpatterns = [
path('index/',views.index,name='index'), #主页
path('login/',views.login,name='login'),#登录
path('res/',views.res,name='res'),#注册
path('doupload/',views.doupload,name='doupload'),#处理注册信息
path('dologin/',views.dologin,name='dologin')#验证登录
]
views.py
import time
from django.shortcuts import render
from MyApp.models import WZ
from django.contrib import auth
from MyApp.forms import NameForm
# Create your views here.
#主页
def index(request):
return render(request,'MyApp/index.html')
#登录页
def login(request):
return render(request,'MyApp/login.html')
#注册页
def res(request):
return render(request,'MyApp/res.html')
#处理注册信息
def doupload(request):
myname=request.POST.get('name',None)
mypwd=request.POST.get('pwd',None)
WZ.objects.create(name=myname,passwd=mypwd)
context={'info':'信息保存成功!'}
return render(request,'MyApp/info.html',context)
#验证登录
def dologin(request):
if request.method=='POST':
myname = request.POST.get('my_name', None)
mypwd = request.POST.get('my_pwd', None)
if WZ.objects.filter(name=myname,passwd=mypwd):
request.session['user_pwd']=myname+mypwd
return render(request,'MyApp/WZ.html')
else:
return render(request,'MyApp/error.html')
启动
- python manage.py runserver 127.0.0.1:8000启动Django(8000端口)
- nodemon main.js启动Node.js服务器(8080端口)
总结
学了两个星期的Django,也只能写这种比较简单的页面。刚好最近也在看前端,所以就一起整合了。
同时,深深感受到全栈的痛苦。
当然,我这个连皮毛都算不上。
跨域问题搞得我头疼,还好最近看了Node.js,解决跨域有两个方法:cors模块和jsonp。但是,jsonp真的没搞懂,而且不支持post请求,只支持get请求。