视图常用返回函数、状态保持、路由别名、django自带的登录注册注销以及csrf攻击和防范

如何让浏览器知道用户的登录状态

htpp协议是无状态的,服务器不知道访问者是谁
cookie弥补了http无状态的不足,让服务器直到来的人是谁

当用户登录成功时,服务器应该将用户的登录状态存储
cookie和session(记录用户的登录状态) --- cookie在浏览器中,session在服务器中
在session记录登录用户的基本信息

在服务器中产生cookie,记录一串随机数然后存储在本地,当浏览器再次访问服务器时,浏览器会带上cookie,服务器使用session中记录同样的一串随机数存储在服务器,
当用户登录成功时,服务器判断浏览器中的cookie中的随机数在服务器的session中是否存在,如果存在,获得session中用户的基本信息。

cookie安全性较低,容易被窃取,session安全性较高,所以cookie中一般只存储一串随机数,用户的信息存储在session中

cookie和session的操作

# 跳转/app/index页面,并且在返回index页面时绑定cookie
res = HttpResponseRedirect(reverse('app:index'))
设置cook值 --- set_cookie(key, value, max_age, expires) - key值,value值,秒,分 -- 后两个参数是存活时间
res.set_cookie('session_id','sdfsdffsdf123',max_age=10)
注意:return后应该是res,不能单独写

设置cookie中的值,并且设置session中的值
数据的账户和密码存储在session中,加密保存
登录的时候,进行验证用户的用户名和密码是否正确,如果正确才向cookie中存入信息
request.session['login'] = True
request.session['username'] = '张三'
request.session['password'] = '123456'
生成一个键是sessionid的键,值是随机字符串的cookie
生成一个session_key -- 键,session_date -- 用户信息,expire_date -- 存活时间的数据表,通过request.session可以获得数据对象

删除cookie中的key值
1.delete_cookie(key)
res.delete_cookie('session_id')

2、将存活时间设置为0
res.set_cookie(key, value, max_age=0)

获取cookie值和session值
获取网页的cookie值其实就是获取数据库中session_key的值
注意:cookie是存储在第一次登陆时使用的浏览器上,使用其他浏览器以后cookie就不在存在

session_key = request.session.session_key --- 获取session_key
username = request.session.get('username') --- 获取设置的session的信息
password = request.session.get('password')

删除sessiond的整条记录 --- 将数据表(django_session)的数据删除
request.session.delete(session_key) --- session_key是唯一的
request.session.delete() --- 本质上request.session是获取了session对象,所以可以通过delete()进行删除

del request.session['username'] --- 删除session中的username
注意:删除用户的信息并不会影响到数据表的存在


    

存活时间

cookie的过程:
当用户访问浏览器时,服务器生成cookie,并存储在本地,当用户再次访问浏览器的时候,就能从浏览器中查看到在服务器中设置的cookie信息 -- 需要注意的是:如果设置了cookie存活时间,当用户第一次访问浏览器时,计时已经开始,不是第二次访问能看到cookie信息才开始计时。

在pycharm中新建项目

进入终端,cd回到存放项目的文件夹中 --- pycharm中的环境和window中一样(可以使用dir查看文件夹内容)
使用djagno-admin startproject 项目名 --- 创建项目
重新选择虚拟环境

设置run --- renserver ip:端口



新项目的配置


1、在站点的__init__中导入pymysql
import pymysql
pymysql.install_as_MySQLdb()

2、在settings中配置数据库
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'day1',
        'USER': 'root',
        'PASSWORD': '123456',
        'HOST': 'localhost',
        'PORT': '3306'

    }
}

3、在将应用名添加到站点settings.py的INSTALLED_APPS中

4、根据需求创建应用 --- 在每个应用下新建一个urls.py文件,并在站点的urls中使用include将站点urls和应用的urls进行连接,并进行别名,然后配置新建的urls

5、创建templates文件夹 --- 并在站点中的settings.py中设置路径,存模板,也就是html

6、创建static文件夹并设置路径 --- 存放静态文件


urls路由别名

站点中的urls别名使用namespace='名字'
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'app',include('app.urls', namespace='app'))
]

在应用的urls中别名使用name='名字'
urlpatterns = [
    url(r'index/',views.index, name='index'),
    url(r'setCookie', views.setCookie),
]

然后在views中跳转页面时:可以使用不适用路径跳转,使用reverse方法
from django.http import HttpResponseRedirect
from django.shortcuts import render, redirect
# HttpResponseRedirect和redirect一样的
def setCookie(request):
    if request.method == 'GET':
        return HttpResponseRedirect(reverse('app:index'))

csrf攻击和防范

csrf攻击说明:
1.用户C打开浏览器,访问受信任网站A,输入用户名和密码请求登录网站A;

2.在用户信息通过验证后,网站A产生Cookie信息并返回给浏览器,此时用户登录网站A成功,可以正常发送请求到网站A;

3.用户未退出网站A之前,在同一浏览器中,打开一个TAB页访问网站B;

4.网站B接收到用户请求后,返回一些攻击性代码,并发出一个请求要求访问第三方站点A;

5.浏览器在接收到这些攻击性代码后,根据网站B的请求,在用户不知情的情况下携带Cookie信息,向网站A发出请求。网站A并不知道该请求其实是由B发起的,所以会根据用户C的Cookie信息以C的权限处理该请求,导致来自网站B的恶意代码被执行。

csrf的攻击之所以会成功是因为服务器端身份验证机制可以通过Cookie保证一个请求是来自于某个用户的浏览器,但无法保证该请求是用户允许的。因此,预防csrf攻击简单可行的方法就是在客户端网页上添加随机数,在服务器端进行随机数验证,以确保该请求是用户允许的。Django也是通过这个方法来防御csrf攻击的。

django中防御csrf攻击:
原理
在用户访问django的可信站点时,django反馈给用户的表单中有一个隐含字段csrftoken,这个值是在服务器端随机生成的,每一次提交表单都会生成不同的值。当用户提交django的表单时,服务器校验这个表单的csrftoken是否和自己保存的一致,来判断用户的合法性。当用户被csrf攻击从其他站点发送精心编制的攻击请求时,由于其他站点不可能知道隐藏的csrftoken字段的信息这样在服务器端就会校验失败,攻击被成功防御,这样就能避免被 CSRF 攻击。

在客户端页面上添加csrftoken,服务器端进行验证,服务器端验证的工作通过'django.middleware.csrf.CsrfViewMiddleware'这个中间层来完成。在django当中防御csrf攻击的方式有两种, 1.在表单当中附加csrftoken 2.通过request请求中添加X-CSRFToken请求头。注意:Django默认对所有的POST请求都进行csrftoken验证,若验证失败则403错误侍候。

csrf防范:


1、首先,最基本的原则是:GET 请求不要用有副作用。也就是说任何处理 GET 2、请求的代码对资源的访问都一定要是“只读“的。
3、要启用 django.middleware.csrf.CsrfViewMiddleware 这个中间件。
4、再次,在所有的 POST 表单元素时,需要加上一个 {% csrf_token %} tag。
5、在渲染模块时,使用 render。render会处理 csrf_token 这个 tag,从而自动为表单添加一个名为 csrfmiddlewaretoken 的 input。

通过form提交
在form表单里面需要添加{%csrf_token%}
这样当你查看页面源码的时候,可以看到form中有一个input是隐藏的
<form action="" method="post">
     <input type='hidden' name='csrfmiddlewaretoken' value='0232bM2TQIRhlznMxFcyl8oPIe8drKJSMYsF7A7trU5605NgHqdqF8lMYILzF2DH'
     
总结原理:当用户访问login页面的时候,会生成一个csrf的随机字符串,,并且cookie中也存放了这个随机字符串,当用户再次提交数据的时候会带着这个随机字符串提交,如果没有这个随机字符串则无法提交成功

用户访问页面,服务器创建随机数,并保存然后返回给页面
当用户再次从浏览器发送请求的时候,就会带着随机数到后端,后端进行验证页面传过来的随机数是否和之前保存的随机数一致,如果一致,再进行判断浏览器中的cookie中的sessionid在服务端中是否能找到,如果找到了服务端在能肯定是本人的行为。

随机数只能使用一次,每次去访问页面值都不一样

用户登录、注册和注销

通过python manage.py createsuperuser创建新用户

通过request.POST.get('表单的name属性') --- 通过表单post提交的的name属性获得对应的values值
<input type="text" name="username" placeholder="账号" class="login_txtbx"/>
if request.method == 'POST':
    username = request.POST.get('username')
    password = request.POST.get('password')
    # 验证用户名和密码是否正确
    # 和数据库的auth_user表对应的模型是User
    # authenticate 鉴定
    # 如果鉴定成功呢,返回用户实例,不成功返回空
    user = auth.authenticate(request, username=username, password=password)
    if user:
        # 登录
        auth.login(request, user)
        # 登录成功,返回首页
        return HttpResponseRedirect(reverse('backweb:index'))
    else:
        return HttpResponseRedirect(reverse('backweb:login'))
使用django的auth去验证用户名和密码是否正确
auth.authenticate() --- 鉴定用户名和密码,如果鉴定成功返回用户(User的一个对象),不成功返回空
auth.login() --- 登录
auth.logout() --- 退出

退出:
def logout(request):
    if request.method == 'GET':
        # 退出
        auth.logout(request)
        return HttpResponseRedirect(reverse('backweb:login'))
<!-- 在页面中获得点击退出后的退出页面的地址 -->
 <li><a href="{% url 'backweb:logout' %}" class="quit_icon">安全退出</a></li>
 或者
 <li><a href="/backweb/logout" class="quit_icon">安全退出</a></li>

当用户退出登录时,我们还能直接登录index界面,这是不合理的,需要进行设置,让用户在未登录状态时,不能直接访问index页面,在这里可以使用from django.contrib.auth.decorators import login_required方法
用login_requied(英文意思:登录需要)将需要是登录状态才能访问的页面包装起来
 url(r'index/',login_required(views.index), name='index'),
 当用户再次访问时,就会跳转到一个位未知的网站,如果想要指定这个网站,可以在settings.py中进行设置,具体设置如下:
 # 没有登录,跳转此地址
LOGIN_URL = '/backweb/login/'

自定义用户登录注册退出

应用的urls中:
from django.conf.urls import url
from backweb import views
urlpatterns = [
url(r'^my_login/',views.my_login,name='my_login'),
url(r'^my_register/',views.my_register,name='register'),
url(r'^my_logout/',views.my_logout,name='my_logout'),
]

对应的views中:
注册 --------
思路:首先获取到用户输入的用户名和密码,验证其用户名是否被注册,如果被注册,重新返回用户注册页面,如果用户名通过,判断其两次输入的密码是否一致,如果一致就创建用户数据,否则重新跳转注册页面
实例:
def my_register(request):
    if request.method == 'GET':
        return render(request,'backweb/register.html')

    if request.method == 'POST':
        username = request.POST.get('username')
        password1 = request.POST.get('password1')
        password2 = request.POST.get('password2')

        # 先验证用户是否注册过
        user = User.objects.filter(username=username).exists()
        if user:
            error = '用户名已注册'
            return render(request, 'backweb/register.html',{'error' :  error})
        else:
            if password1 == password2:
                User.objects.create(username=username,password=password1)
                return HttpResponseRedirect(reverse('backweb:my_login'))
            else:
                error = '两次密码不一致'
                return render(request,'backweb/register.html', {'error': error})
                
登录----------
思路:
获取到用户输入的账户名和密码,判断用户是否存在,如果存在就判断用户对应的密码是否正确,否则跳转到登录页面,输入正确则要保存用户的状态。
保存状态的思路:在cookie中和在服务器中都要设值。可以通过随机函数生成随机字符,时间函数生成cookie存活时间。
例子:
import random
def my_login(request):
    if request.method == 'GET':
        return render(request,'backweb/login.html')

    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        user = User.objects.filter(username=username).first()
        if user:

            if password == user.password:
                # 第一步,在cookie中设值
                res = HttpResponseRedirect(reverse('backweb:index'))
                s = 'sdfdsjgfdsifusjdifjsdlkfjlkdsfjdlksjd123123874'
                session_id = ''
                for i in range(20):
                    session_id += random.choice(s)
                out_time = datetime.now() + timedelta(days=1)

                res.set_cookie('session_id', session_id, expires=out_time)
                """
              在服务器中存值 --- 存过期时间和sessoin_id值,
              如果时间过期就将数据库中的session_id值置空,判断用户登录时浏览器的session_id值和数据库的session_id值是否匹配
              """
                user.session_id = session_id
                user.out_time = out_time
                user.save()
                return res
            else:
                error = '密码错误'
                return render(request,'backweb/login.html', {'error':error})
        else:
            error = '用户名不存在'
            return render(request,'backweb/login.html', {'error': error})
            
退出-----
用户退出的实质也就是删除服务器的ticket值并且删除cookie中的ticket值
def my_logout(request):
    if request.method == 'GET':
        pass
        # 删除服务器端的sessoin_id值
        user = request.user
        user.session_id = ''
        user.save()
        # 删除cookie中的session_id
        res = HttpResponseRedirect(reverse('backweb:my_login'))
        res.delete_cookie('session_id')
        return res


HttpResponse、render,、redirect

1.HttpResponse

它是作用是内部传入一个字符串参数,然后发给浏览器。

2、render

render方法可接收三个参数,一是request参数,二是待渲染的html模板文件,三是保存具体数据的字典参数。

它的作用就是将数据填充进模板文件,最后把模板中渲染的html页面返回给浏览器。

3、redirect

接受一个URL参数,表示让浏览器跳转去指定的URL.


if user:
    # 登录
    auth.login(request, user)
    return HttpResponseRedirect(reverse('backweb:index'))
    # 或者 return HttpResponseRedirect('/backweb/index/')

# 将渲染好的模板返回给浏览器
def index(request):
    if request.method == 'GET':
        return render(request, 'backweb/index.html')
        
#渲染变量到模板中,最后将结果返回给浏览器
def selStuen(request):
    if request.method == 'GET':
        stus = Student.objects.all()
        return render(request, 'students.html',
                      {'stus': stus})

猜你喜欢

转载自blog.csdn.net/weixin_42750983/article/details/81949687