Django--4、认证系统

  • cookie与session

    概念

    因http协议无法保存状态,但是又需要保存状态,所以有了cookie。它不属于http协议范畴

    工作原理:相当于一段标识数据。在访问服务器产生标识内容(cookie),加入到响应里返回,浏览器再次访问时会自动带上cookie。服务器就能识别出身份了。 数据缓存在浏览器中。减轻服务器端的压力。但安全性不高。

    cookie随可实现保持状态,但其最大支持4096字节,且保存在客户端不安全,于是产生了支持更多字节,保存在服务端的机制--session。

    session的机制:给客户端cookie加入不同的ID,访问时提供cookie,服务端根据ID拿出私密的数据,就可以识别出身份了。

    但是cookie中内容被盗依然危险,所以有了失效时间。

    总结:cookie与session要配合使用。cookie弥补了http无状态的不足,但存在客户端且安全性差。所以仅用cookie存标识号(sessionID),它对应服务端存的数据。

    是开发界共通的概念

    django实现cookie

    • 获取cookie
    request.COOKIES['key']
    request.get_signed_cookie(key,default=RAISE_ERROR,salt='',max_age=None)
        default:默认值
        salt:加密盐
        max_age:过期时间
    
    • 设置cookie
    res = 任何一种响应方式实例对象。
    res.set_cookie(key,value,……)
    res.set_signed_cookie(key,value,salt='加密盐',……)
    
    def set_cookie(self, key,                         value='',                    max_age=None,        超长时间
            expires=None,        超长时间
            path='/',           Cookie生效的路径,浏览器只会把cookie回传给带有该路径的页面,这样可以避免将cookie传给站点中的其他的应用。
                          / 表示根路径,特殊的:根路径的cookie可以被任何url的页面访问
                 
                    domain=None,         Cookie生效的域名
                        你可用这个参数来构造一个跨站cookie如, domain=".example.com"
                        所构造的cookie对下面这些站点都是可读的:
                          www2.example.com 
                和an.other.sub.domain.example.com 如果该参数设置为 None ,cookie只能由设置它的站点读取。
    
            secure=False,        如果设置为 True ,浏览器将通过HTTPS来回传cookie        httponly=False       只能http协议传输,无法被JavaScript获取
                            (不是绝对,底层抓包可以获取到也可以被覆盖)
              ): pass
    

    由于cookie保存在客户端,所以,JavaScript和jquery也可以操作cookie。

    <script src='/static/js/jquery.cookie.js'>
     
    </script> $.cookie("key", value,{ path: '/' });
    
    • 删除cookie res.delete_cookie("cookie_key",path="/",domain=name)

    Django实现session

    设置session值
    request.session['sname']="root"
    
    获取session值
    sname = request.session['sname']
    
    删除session值
    del request.session['sname']
    
    检测是否操作sessionif "sname" is request.session
    
    .get
    .pop
    .keys
    .items
    .setdefault
    .flush  删数据和cookie
    .session_key
    .clear_expired
    .exists
    .delete  删数据
    
    .set_expiry(value)
                * 如果value是个整数,session会在些秒数后失效。
                * 如果value是个datatime或timedelta,session就会在这个时间后失效。
                * 如果value0,用户关闭浏览器session就会失效。
                * 如果value是None,session会依赖全局session失效策略。
    

    流程解析图

    1. 登录后生产个字典,字典存入session库,key是随机标识。value是数据字典
    2. 在value中存信息。
    3. 把Key写入cookie中返回,request.session看到的是value。

    总结:Django中用session时,cookie由服务端生成,写到请求里返回给浏览器。浏览器会缓存。cookie是寻找用户信息的唯一标识。

    session函数示例

    def log_in(request):
    
        if request.method=="POST":
            username=request.POST['user']
            password=request.POST['pwd']
    
            user=UserInfo.objects.filter(username=username,password=password)
    
            if user:
                #设置session内部的字典内容
                request.session['is_login']='true'
                request.session['username']=username
    
                #登录成功就将url重定向到后台的url
                return redirect('/backend/')
    
        #登录不成功或第一访问就停留在登录页面
        return render(request,'login.html')
    
    
    
    
    def backend(request):
        print(request.session,"------cookie")
        print(request.COOKIES,'-------session')
        """
        这里必须用读取字典的get()方法把is_login的value缺省设置为False当用户访问backend这个url先尝试获取这个浏览器对应的session中的
        is_login的值。如果对方登录成功的话,在login里就已经把is_login
        的值修改为了True,反之这个值就是False的
        """
    
        is_login=request.session.get('is_login',False)
        #如果为真,就说明用户是正常登陆的
        if is_login:
            #获取字典的内容并传入页面文件
            cookie_content=request.COOKIES
            session_content=request.session
    
            username=request.session['username']
    
            return render(request,'backend.html',locals())
        else:
            """
            如果访问的时候没有携带正确的session就直接被重定向url回login页面
            """
            return redirect('/login/')
    
    
    
    def log_out(request):
        """
        直接通过request.session['is_login']回去返回的时候,
        如果is_login对应的value值不存在会导致程序异常。所以
        需要做异常处理
        """
        try:
            #删除is_login对应的valuedel request.session['is_login']
            
            # OR---->request.session.flush() # 删除django-session表中的对应一行记录
    
        except KeyError:
            pass
        #点击注销之后,直接重定向回登录页面
        return redirect('/login/')
    
    ===================================login.html==================
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    
    <form action="/login/" method="post">
        <p>用户名: <input type="text" name="user"></p>
        <p>密码: <input type="password" name="pwd"></p>
        <p><input type="submit"></p>
    </form>
    
    
    </body>
    </html>
    
    
    ===================================backend.html==================
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    
    <h3>hello {{ username }}</h3>
    <a href="/logout/">注销</a>
    
    </body>
    </html>
    

    session存储的相关配置

    • 数据库配置(默认)
    Django默认支持Session,并且默认是将Session数据存储在数据库中,即:django_session 表中。
      
    a. 配置 settings.py
      
        SESSION_ENGINE = 'django.contrib.sessions.backends.db'   # 引擎(默认)
          
        SESSION_COOKIE_NAME "sessionid"                       # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认)
        SESSION_COOKIE_PATH "/"                               # Session的cookie保存的路径(默认)
        SESSION_COOKIE_DOMAIN = None                             # Session的cookie保存的域名(默认)
        SESSION_COOKIE_SECURE = False                            # 是否Https传输cookie(默认)
        SESSION_COOKIE_HTTPONLY = True                           # 是否Session的cookie只支持http传输(默认)
        SESSION_COOKIE_AGE = 1209600                             # Session的cookie失效日期(2周)(默认)
        SESSION_EXPIRE_AT_BROWSER_CLOSE = False                  # 是否关闭浏览器使得Session过期(默认)
        SESSION_SAVE_EVERY_REQUEST = False                       # 是否每次请求都保存Session,默认修改之后才保存(默认)
    
    • 缓存配置
    a. 配置 settings.py
      
        SESSION_ENGINE = 'django.contrib.sessions.backends.cache'  # 引擎
        SESSION_CACHE_ALIAS = 'default'                            # 使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置
      
      
        SESSION_COOKIE_NAME "sessionid"                        # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串
        SESSION_COOKIE_PATH "/"                                # Session的cookie保存的路径
        SESSION_COOKIE_DOMAIN = None                              # Session的cookie保存的域名
        SESSION_COOKIE_SECURE = False                             # 是否Https传输cookie
        SESSION_COOKIE_HTTPONLY = True                            # 是否Session的cookie只支持http传输
        SESSION_COOKIE_AGE = 1209600                              # Session的cookie失效日期(2周)
        SESSION_EXPIRE_AT_BROWSER_CLOSE = False                   # 是否关闭浏览器使得Session过期
        SESSION_SAVE_EVERY_REQUEST = False                        # 是否每次请求都保存Session,默认修改之后才保存
    
    • 文件配置(了解)
    a. 配置 settings.py
      
        SESSION_ENGINE = 'django.contrib.sessions.backends.file'    # 引擎
        SESSION_FILE_PATH = None                                    # 缓存文件路径,如果为None,则使用tempfile模块获取一个临时地址tempfile.gettempdir()        
        SESSION_COOKIE_NAME "sessionid"                          # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串
        SESSION_COOKIE_PATH "/"                                  # Session的cookie保存的路径
        SESSION_COOKIE_DOMAIN = None                                # Session的cookie保存的域名
        SESSION_COOKIE_SECURE = False                               # 是否Https传输cookie
        SESSION_COOKIE_HTTPONLY = True                              # 是否Session的cookie只支持http传输
        SESSION_COOKIE_AGE = 1209600                                # Session的cookie失效日期(2周)
        SESSION_EXPIRE_AT_BROWSER_CLOSE = False                     # 是否关闭浏览器使得Session过期
        SESSION_SAVE_EVERY_REQUEST = False                          # 是否每次请求都保存Session,默认修改之后才保存
    

    用户认证

    auth模块

    导入

    from django.contrib import auth
    

    authenticate

    用户认证,需要user和password关键字参数,认证有效会返回user对象,该对象会在后续的登录过程中使用。

    login

    认证成功后登录并返回页面 接收一个HttpRequest对象,以及认证后生成的user对象。
    会给已认证的用户附加上sessionID等信息。

    logout

    注销用户 接收一个HttpRequest对象,无返回值。
    调用后,当前请求的session信息会全部清除。
    即使用户没登录调用这个函数也不会报错。

    login认证后user对象的is_authenticated

    判断认证是否通过。 不验证权限和激活状态。

    实现未登录跳到登录,登录后再跳回来。

    使用auth模块的 decorators的login_required方法。
    若用户没有登录,则会跳转到django默认的 登录URL '/accounts/login/ ' (在settings文件中通过LOGIN_URL进行修改)。并传递当前访问url的绝对路径 (登陆成功后,会重定向到该路径)。

    auth.models的user对象

    is_staff 是否有管理权限
    is_active  是否允许登录
    

    创建用户create_user

    user = User.objects.create_user(username='',password='',email=''

    密码验证check_password

    接收密码字符串。
    用户需要修改密码的时候 首先要让他输入原来的密码 ,如果给定的字符串通过了密码检查,返回 True

    修改密码set_password

    user = User.objects.get(username='')
    user.set_password(password='')
    user.save 
    

    示例

    注册

    def sign_up(request):
     
        state = None
        if request.method == 'POST':
     
            password = request.POST.get('password', '')
            repeat_password = request.POST.get('repeat_password', '')
            email=request.POST.get('email', '')
            username = request.POST.get('username', '')
            if User.objects.filter(username=username):
                    state = 'user_exist'
            else:
                    new_user = User.objects.create_user(username=username, password=password,email=email)
                    new_user.save()
     
                    return redirect('/book/')
        content = {
            'state': state,
            'user': None,
        }
        return render(request, 'sign_up.html', content)  
    

    改密码

    @login_required
    def set_password(request):
        user = request.user
        state = None
        if request.method == 'POST':
            old_password = request.POST.get('old_password', '')
            new_password = request.POST.get('new_password', '')
            repeat_password = request.POST.get('repeat_password', '')
            if user.check_password(old_password):
                if not new_password:
                    state = 'empty'
                elif new_password != repeat_password:
                    state = 'repeat_error'
                else:
                    user.set_password(new_password)
                    user.save()
                    return redirect("/log_in/")
            else:
                state = 'password_error'
        content = {
            'user': user,
            'state': state,
        }
        return render(request, 'set_password.html', content)
原文地址:https://www.cnblogs.com/jinyudong/p/8463115.html