项目元素:
用户身份验证系统:注册。登录,编辑个人信息,修改或重置密码功能
关注系统,共享任意位置的网站并显示共享图像,活动流:用户可查看所关注用户上传的内容
目录
登录模块
创建项目
cmd
>mkdir env
> python -m venv env/bookmarks
#激活系统
.\env\bookmarks\Scripts\activate
激活虚拟环境并且创建项目:
.\env\bookmarks\Scripts\activate
>django-admin startproject bookmarks
并且切换到下一个目录中,创建一个app:
(bookmarks) PS D:\工作\bookmarks> cd bookmarks
(bookmarks) PS D:\工作\bookmarks\bookmarks> django-admin startapp account
并且在setting.py的INSTALLED_APPS中添加该应用:
INSTALLED_APPS = [
'account',#身份认证模板放首位
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
并且进行模型同步:
python3 manage.py migrate
使用djiango身份认证框架
框架位置djnago.contrib.auth;与之前做的项目不同,这次加了个中间件,在请求或响应阶段以全局方式进行。
并且在account app中创建新的forms.py文件,在里面添加代码:
from django import forms
#该表单用于用户和数据库之间的身份认证
class LoginForm(forms.Form):
username =forms.CharField()#
password =forms.CharField(widget =forms.PasswordInput)
#在HTML中包含password,以便使浏览器将其视为密码输入
编辑该app的views.py:
from django.shortcuts import render
from django.shortcuts import HttpResponse
from django.contrib.aut import authenticate,login #身份验证框架
from .forms import LoginForm
def user_login(request):
if request.method =='POST':
form =LoginForm(request.POST)#当user_login被调用时,将实例化form =LoginForm
if form.is_valid():
cd =form.cleaned_data#如果表单无效,将提醒用户哪个没写完整
user =authenticate(request,username =cd['username'],password=cd['password'])#在数据库进行身份验证
if user is not None:#验证成功,那么将检查是否处于活动状态
if user.is_active:#如果用户处于未活动状态,则返回包含认证失败的信息
Login(request,user)
return HttpResponse('认证成功')
else:
return HttpResponse('认证失败')
else:
return HttpResponse('无效登录')
else :
form =LoginForm()
return render(request,'account/login.html',{'form':form})
注意事项:authenticcate()和login()差别,authenticcate()检查用户证书,如正确则返回一个User对象,login()则在当前会话中设置用户。
在account app中创建urls.py文件,设置路由:
from django.urls import path
from . import views
urlpatterns =[
path('login/',views.user_login,name = 'login'),
]
并且在bookmarks的urls.py中,导入include,并且添加account的路由:
from django.contrib import admin
from django.urls import path,include
urlpatterns = [
path('admin/', admin.site.urls),
path('account/',include('account.urls')),
]
在account下创建以下文件和文件夹,挡住那个是base.html:
base.html:
{% load static %}
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}{% endblock %}</title>
<link href="{% static 'css/base.css' %}" rel="stylesheet">
</head>
<body>
<div id="header">
<span class="logo">Bookmarks</span>
</div>
<div id="content">
{% block content %}
{% endblock %}
</div>
</body>
login.html
{% extends "base.html" %}
{% block title %}Log-in{% endblock %}
{% block content %}
<h1>Log-in</h1>
<p>请进行登录</p>
<form method="post">
{{form.as_p}}
{% csrf_token %}
<p><input type='submit' value="Log in"></p>
</form>
{% endblock %}
控制台再次再次输入:
python manage.py makemigrations
ython manage.py migrate
python manage.py createsuperuser
然后运行:
python manage.py runserver
没有设置首页,直接进入后台
进行添加:
填写:
Django提供基于类的视图以处理身份验证:
LoginView:处理表单和用户日志
LogoutView:注销用户
密码修改视图:
PasswordChange View:处理表单并修改用户密码
PasswordChangeDoneView:在成功修改密码后用户被重定向的成功视图
密码重置视图:
PasswoResetView:允许用户重置密码,并生成一个带有令牌的一次性使用链接,将其发送到用户的电子邮箱当中
PasswordResetDoneView:通知用户向其发送一封电子邮件,其中包含一个重置密码链接
PasswordResetConfirmView:允许用户设置新密码
PasswordResetCompleteView:在成功重置密码后用户被重定向的成功视图
登录和注销视图
修改accoun的urls.py:
from django.urls import path
from django.contrib.auth import views as auth_views
from . import views
urlpatterns =[
#path('login/',views.user_login,name = 'login'),
#登录和注销url
path('login/',auth_views.LoginView.auth_views(),name='login'),
path('logout/',auth_views.LoginView.auth_views(),name='logout'),
]
在templates中创建一个registration并且创建login.html:
{% extends "base.html" %}
{% block title %}Log-in{% endblock %}
{% block content %}
<h1>Log-in</h1>
{% if form.errors %}
<p>
你的用户名和密码并不匹配
请重新输入
</p>
{% else %}
<p>
请使用下面的表格进行登录
</p>
{% endif %}
<div class="login-form">
<form action="{% url 'login' %}" method="post">
{{form.as_p}}
{% csrf_token %}
<input type="hidden" name="next" value="{{next}}" />
<p><input type="submit" value="Log-in" ></p>
</form>
</div>
{% enblock %}
在registration中创建logged_out.html模板:
在用户注销后,django将显示该模板
{% extends "base.html" %}
{% block title %}Logged out{% endblock %}
{% block content %}
<h1>Logged out</h1>
<p>
成功注销
你可以再次进行<a href="{% url 'login' %}">登录</a>。
</p>
{% endblock %}
在account的views.py进行添加:
from django.contrib.auth.decorators import login_required#当前用户是否被认证
#用来检查当前用户身份被认证,如果经过认证,则执行装饰视图,否则重定向到登录URL
@login_required
def dashboard(request):
return render(request,'account/dashboard.html',{'section':dashboard})
templates的account添加dashboard.html:
{% extends "base.html" %}
{% block title %}Logged out{% endblock %}
{% block content %}
<h1>Dashboard</h1>
<p>欢迎来到你的操作台</p>
{% endblock %}
并且在urls.py添加路由:
path('',views.dashboard,name='dashboard'),
编辑项目的setting文件,添加:
LOGIN_REDIRECT_URL ='dashboard'
LOGIN_URL='login'
LOGOUT_URL='logout'
以上代码总结:添加了登录和注销视图。建立了玩家登录之后的操作台,添加了默认状态下使用这些ur
在base.html代码中添加以下代码,用来做登录和注销链接:
<head>
<title>{% block title %}{% endblock %}</title>
<link href="{% static 'css/base.css' %}" rel="stylesheet">
</head>
<body>
<div id="header">
<span class="logo">Bookmarks</span>
{% if request.user.is_authenticated %}
<ul class="menu">
<li {% if section =="dashboard" %} class="selected" {% endif %}><a href="{% url "dashboard" %}">我的操作台</a></li>
<li {% if section =="images" %} class="selected" {% endif %} ><a href="#">图片</a></li>
<li {% if section =="people" %} class="selected" {% endif %} ><a href="#">形态</a></li>
</ul>
{% endif %}
<span class="user">
{% if request.user.is_authenticated %}
Hello {{ request.user.first_name | default:request.user.username}},
<a href="{% url "login" %}">注销</a>
{% else %}
<a href="{% url "logout" %}">登录</a>
{% endif %}
</span>
</div>
运行:
修改密码视图
在account的urls中:
#修改密码的视图,PasswordChangeView将处理表单以修改密码,PassChangeDoneView将在用户更改密码成功后添加一道信息
path('password-change/',auth_views.PasswordChangeView.as_view(),name='password_change'),
path('password-change/done/',auth_views.PasswordChangeDoneView.as_view(),name='password_change_done'),
并且在registration中创建password_change_form.html:
{% extends "base.html" %}
{% block title %}修改你的密码{% endblock %}
{% block content %}
<h1>修改你的密码</h1>
<p>
使用下面的表格更改您的密码
</p>
<form method="post">{{form.as_p}}
<p><input type="submit" value="Change"></p>
{% csrf_token %}
</form>
{% endblock %}
并在同一目录下创建另一个文件,password_change_done.html:
{% extends "base.html" %}
{% block title %}修改你的密码{% endblock %}
{% block content %}
<h1>修改你的密码</h1>
<p>
密码修改成功
</p>
{% endblock %}
打开网页:http://127.0.0.1:8000/account/password-change
重置密码视图
编辑account的urls.py文件,并且添加代码:
#修改密码的视图,PasswordChangeView将处理表单以修改密码,PassChangeDoneView将在用户更改密码成功后添加一道信息
。。。。。。。。。。。。。
#重置密码操作
path('password-reset/',auth_views.PasswordResetView.as_view(),name='password_reset'),
path('password-reset/done/',auth_views.PasswordResetDoneView.as_view(),name='password_reset_confirm'),
path('password-reset/complete/',auth_views.PasswordResetCompleteView.as_view(),name='password_reset_complete'),
并且在registration中添加新文件:password-reset_form.html:
{% extends "base.html" %}
{% block title %}重置你的密码{% endblock %}
{% block content %}
<h1>忘记密码</h1>
<p>输入你的邮箱来验证更改密码
</p>
<form method="post">
{{form.as_p}}
<p><input type="submit" value="Send e-mail"></p>
{% csrf_token %}
</form>
{% endblock %}
同一目录下创建另外一个文件,password_reset_email.html,并且去添加以下代码:
Some asked for password reset for email {{email}}.Follow the link link below:
{{protocol}}://{{domain}}{% url "password_reset_confirm" uidb64=uid token=token %}
Your username,in case you've forgotten:{{user.get_username}}
<!--该html用来渲染发送至用户的电子邮箱,并且重置密码,其中含有视图生成的重置令牌 -->
进行添加文件password_reset_done.html:
{% extends "base.html" %}
{% block title %}重置你的密码{% endblock %}
{% block content %}
<h1>重置密码</h1>
<p>输入你的邮箱来验证更改密码</p>
<p>我们已将密码说明发送到您的邮箱</p>
<p>如果没有收到,请确定您输入注册时使用的地址</p>
{% endblock %}
再创建一个模板为password_reset_confirm.html:
{% extends "base.html" %}
{% block title %}重置你的密码{% endblock %}
{% block content %}
<h1>重置密码</h1>
{% if validlink %}
<p>请输入新的密码</p>
<form method="post">
{{form.as_p}}
{% csrf_token %}
<p><input type="submit" value="Change my password"> </p>
</form>
{ % else % }
<p>这个密码使用过了,请重新设置</p>
{% endblock %}
再添加password_reset_complete.html:
{% extends "base.html" %}
{% block title %}密码重置{% endblock %}
{% block content %}
<h1>密码设置</h1>
<p>您已经设置好你的密码了,你可以<a href="{% url "login" %}">进行登录</a></p>
{% endblock %}
在registration/login.html添加以下代码:
<div class="login-form">
<form action="{% url 'login' %}" method="post">
{{form.as_p}}
{% csrf_token %}
<input type="hidden" name="next" value="{{next}}" />
<p><input type="submit" value="Log-in" ></p>
</form>
<p>
<a href="{% url "password_reset" %}">忘记密码</a>
</p>
</div>
{% endblock %}
并且在setting进行添加邮件发送类:
EMAIL_BACKEMD ="django.core.mail.backends.console.EmailBackend"
#设置邮箱发送类
运行:
注释掉url,用于自己的视图:
from django.urls import path,include
from django.contrib.auth import views as auth_views
from . import views
urlpatterns =[
#path('login/',views.user_login,name = 'login'),
#登录和注销url
#path('login/',auth_views.LoginView.as_view(),name='login'),
#path('logout/',auth_views.LogoutView.as_view(),name='logout'),
#修改密码的视图,PasswordChangeView将处理表单以修改密码,PassChangeDoneView将在用户更改密码成功后添加一道信息
#path('password-change/',auth_views.PasswordChangeView.as_view(),name='password_change'),
#path('password-change/done/',auth_views.PasswordChangeDoneView.as_view(),name='password_change_done'),
#重置密码操作
#path('password-reset/',auth_views.PasswordResetView.as_view(),name='password_reset'),
#path('password-reset/confirm/<uidb64>/<token>/',auth_views.PasswordResetDoneView.as_view(),name='password_reset_confirm'),
#path('password-reset/complete/',auth_views.PasswordResetCompleteView.as_view(),name='password_reset_complete'),
path('',include('django.contrib.auth.urls')),
path('',views.dashboard,name='dashboard'),
]
用户注册和用户个人信息
用户注册
创建一个简单的视图以使用户在网站上注册,初始状态下,我们需要创建一个表单,以使用户输入用户名,姓名和密码。
编辑account的forms.py,并且添加以下代码:
from django.contrib.auth.models import User
class UserRegistrationForm(forms.ModelForm):
password =forms.CharField(label='Password',widget=forms.PasswordInput)
password2 =forms.CharField(label='Repeat Password',widget=forms.PasswordInput)
class Meta:
models =User
fields=['username','first_name','email']
#字段验证操作,验证密码是否相同
def clean_password2(self):
cd=self.clean_data
if cd['password'] != cd['password2']:
raise forms.ValidationError('密码不匹配')
return cd['password2']
编辑account的views:
from .forms import LoginForm,UserRegistrationForm
def register(request):
if request.method == 'POST':
user_form =UserRegistrationForm(request.POST)
if user_form.is_valid():
new_user =user_form.save(commit=False)
new_user.set_password(
user_form.cleaned_data['password'])
new_user.save()
return render(request,'account/register_done.html',{'new_user':new_user})
else:
user_form=UserRegistrationForm()
return render(request,'account/register.html',{'user_form':user_form})
编辑account的urls.py文件:
path('register/',views.register,name='register')
在templates的account添加两个文件:register.html、register_done.html
register.html
{% extends "base.html" %}
{% block title %}创建一个用户{% endblock %}
{% block content %}
<h1>创建一个用户</h1>
<p>请对以下表单进行输入</p>
<form method="post">
{{user_form.as_p}}
{% csrf_token %}
<p><input type='submit' value="Cretae ny account"></p>
</form>
{% endblock %}
register_done.html
{% extends "base.html" %}
{% block title %}欢迎{% endblock %}
{% block content %}
<h1>欢迎{{ new_user.first_name}}!</h1>
<p>请对以下表单进行输入</p>
<p>
你的账号已成功注册。
现在你可以进行<a href="{% url "login" %}">登录</a>
</p>
{% endblock %}
并且在registration的login.html添加:
<p>
请使用下面的表格进行登录
如果你没有账号,请进行<a href="{% url "register" %}">注册</a>
</p>
拓展用户模型
我们使用的User模型包含有限的字段集,使用我们需要对其进行拓展:创建一个资料模型。他包含与django模型的一对一广西,以及任何附加字段,一对一的关系类似于带yunique=true参数的ForeignKey字段,隐性的一对一关系,而不是多个元素管理器。
编辑account的models.py:
from django.db import models
from django.conf import settings
class Profile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL,on_delete=models.CASCADE)#当删除对象时,也将相关信息删除
date_of_birth =models.DateField(blank=True,null=True)
photo=models.ImageField(upload_to='users/%Y/%m/%d/',blank=True)
def _str_(self):
return f'Profile of {self.user.username}'
安装Pillow并处理媒体文件
pip install Pillow
编辑setting.py:
#用于处理用户上传的媒体文件
EMDIA_URL='media/'
MEDIA_ROOT=BASE_DIR / 'media'#路径
以及根目录的urls.py:
from django.contrib import admin
from django.urls import path,include
from django.conf import setting
from django.conf.urls.static import static
urlpatterns = [
path('admin/', admin.site.urls),
path('account/',include('account.urls')),
]
#添加static帮助函数并利用开发服务器处理媒体文件
if settings.DEBUG:
urlpatterns +=static(settings.MEDIA_URL,document_root=settings.MEDIA_ROOT)
然后进行模型迁移;
python manage.py makemigrations
python manage.py migrate
然后在account的admin文件中添加注册模型:
from django.contrib import admin
#向管理网站中注册模型
from .models import Profile
@admin.register(Profile)
class ProfileAdmin(admin.ModelAdmin):
list_display =['user','date_of_birth','photo']
raw_id_fields=['user']
再运行网站
针对每个用户以手动的方式创建一个Profile对象,令其在网站上编辑资料,编辑account的forms.py文件:
from .models import Profile
#允许用户编辑其姓名和电子邮件
class UserEditForm(forms.ModelForm):
class Meta:
model =User
fields ={'first_name','last_name','email'}
#允许用户编辑Profile的资料数据
class ProfileEditForm(forms.ModelForm):
class Meta:
model =Profile
fields =['date_of_birth','photo']
并且编辑account的views.py文件:
from .models import Profile
def register(request):
if request.method == 'POST':
user_form =UserRegistrationForm(request.POST)
if user_form.is_valid():
new_user =user_form.save(commit=False)
new_user.set_password(
user_form.cleaned_data['password'])
new_user.save()
#注册时,创建用户profile与其关联
Profile.objects.create(user=new_user)
return render(request,'account/register_done.html',{'new_user':new_user})
else:
user_form=UserRegistrationForm()
return render(request,'account/register.html',{'user_form':user_form})
在这个文件中,编辑用户个人资料:
from .forms import LoginForm,UserRegistrationForm,UserEditForm,ProfileEditForm
@login_required
def edit(request):
if request.method == 'POST':
user_form =UserEditForm(instance=request.user,data=request.POST)
profile_form =ProfileEditForm(instance=request.user.profile,files=request.FILES)
if user_form.is_valid() and profile_form.is_valid():
user_form.save()
profile_form.save()
else:
user_form =UserEditForm(instance=request.user)
profile_form =ProfileEditForm(instance =request.user.profile )
return render(request,'account/edit.html',{'user_form':user_form,'profile_form':profile_form})
并且在urls添加上路由:
path('edit/',views.edit,name='edit'),
然后在templates/account中创建edit.html:
{% extends "base.html" %}
{% block title %}Edit your account{% endblock %}
{% block content %}
<h1>Edit your account</h1>
<p>You can edit your account using the following form:</p>
<form method="post" enctype="multipart/form-data">
{{ user_form.as_p }}
{{ profile_form.as_p }}
{% csrf_token %}
<p><input type="submit" value="Save changes"></p>
</form>
{% endblock %}
然后在bashboard.html添加一下路由:
{% extends "base.html" %}
{% block title %}Logged out{% endblock %}
{% block content %}
<h1>Dashboard</h1>
<p>欢迎来到你的操作台。
你可以进行修改你的<a href="{% url "edit" %}" >信息</a>或者<a href="{% url "password_change" %}">修改你的密码</a></p>
{% endblock %}
使用消息框架
当用户和平台交互的时候,可能需要通知他们与特定的动作结果相关信息。django的框架可允许我们向用户显示单次通知。
我们将在base.html中添加以下代码实现全局通知:
</div>
{% if messages %}
<ul class="messages">
{% for message in messages %}
<li class="{{ message.tags }}">
{{ message|safe}}
<a href="#" class="close">x</a>
</li>
{% endfor %}
</ul>
{% endif %}
<div id="content">
{% block content %}
{% endblock %}
</div>
打开account的views.py,添加以下代码:
from django.contrib import message
@login_required
def edit(request):
if request.method == 'POST':
user_form =UserEditForm(instance=request.user,data=request.POST)
profile_form =ProfileEditForm(instance=request.user.profile,files=request.FILES)
if user_form.is_valid() and profile_form.is_valid():
user_form.save()
profile_form.save()
messages.success(request,'Profile updated'\ 'successfully')
else:
messages.error(request,'Error updatingh your profile')
else:
。。。。。。。。。。。。。。
创建自定义身份认证
在account app中创建一个新的文件,authentication.py:
#身份认证后端
from django.contrib.auth.models import User
class EmailAuthBackend:
"""
Authenticate using an e-mail address.
"""
def authenticate(self, request, username=None, password=None):#协同工作
try:
user = User.objects.get(email=username)
if user.check_password(password):
return user
return None
except (User.DoesNotExist, User.MultipleObjectsReturned):
return None
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)#primary key,对与数据库每一条记录,是唯一标识符
except User.DoesNotExist:
return None
在setting中添加:
#用户证书通过ModelBackend被检查,如果未返回用户,证书则通过EmailAuthBackend被检查
AUTHENTICATION_BACKENDS =[
'django.contrib.auth.backends.ModelBackend',
'account.authentication.EmailAuthBackend',
]
为了防止多个用户用同一个邮箱地址注册,我们需要在forms.py文件UserRegistrationForm类中添加以下代码:
#否则多个用户用同一个邮箱地址注册
def clean_email(self):
data=self.cleaned_data['email']
if User.objects.filter(email=data).exists():
raise forms.ValidationError('这个邮箱已被注册')
return data
我们还需要把用户修改信息部分进行设置,防止用户修改为其他用户的邮箱,在UserEditForm中添加代码:
#防止用户修改为其他用户的邮箱
def clean_email(self):
data=self.cleaned_data['email']
qs =User.objects.exclude(id=self.instance.id)+.filter(email=data)
if qs.ex():
raise forms.ValidationError('这个邮箱已被注册')
return data
实现社交身份验证
我们将利用Facebook,Twitter和Google,qq向网站中添加社交身份验证
将使用OAuth2.0进行身份认证,OAuth代表开发授权。
pip install git+https://github.com/python-social-auth/social-app-django.git
在setting的INSTALLED_APPS添加:'social_django'
然后继续数据库同步:
python manage.py migrate
然后在bookmarks的urls.py中添加:
path('social-auth/',include('social_django.urls',namespace='social'))
然后在这里继续进行添加:C:\Windows\System32\drivers\etc的host文件中:
127.0.0.1 mysite.com
进行社交认证
然后在这个网页中会看到这样:
我们可以通过编辑setting.py,调整ALLOWED_HOSTS设置项:
ALLOWED_HOSTS = ['mysite.com','localhost','127.0.0.1']
通过HTTPS运行开发服务器
通过安装以下协议,让TLS设置该服务器为安全服务器
pip install django-extensions
pip install werkzeug
pip install pyOpenSSL
然后在setting中INSTALLED_APPS添加:
'django_extensions',
然后我们使用以下代码运行服务器:
python manage.py runserver_plus --cert-file cert.crt
注意,我们使用的是https;//而不是http://:
会出现这个错误
这是正常的,打开高级进行访问就可以了
利用QQ进行身份认证
在setting.py的AUTHENTICATION_BACKENDS设置代码行:
'social_core.backends.facebook.FacebookOAuth2',
我们需要一个QQ开发者账号,且需要一个新的QQ应用程序,打开QQ开发平台进行注册
需要等待,暂时跳过
共享网站内容
待续。。。