zoukankan      html  css  js  c++  java
  • Django-认证系统

    Django中操作Cookie

     Cookie 就是保存在浏览器端(客户端)的键值对   
      1.Cookie是服务端(提供cookie数据)让浏览器保存的键值对
      2. 保存了该网站的Cookie之后,后续的请求都会携带着相关Cookie发送到服务端
      3. Cookie是有效时间的
       4.浏览器可以设置不保存Cookie
      5. 可以用来做登录或其他事情
            
    为什么要有Cookie?
        Http请求是没有状态的
            
    Cookie应用的地方:
            1. 登录
            2. 前天免登陆
            3. 记住用户的某些浏览习惯
            4. 简单的请求限制(投票)            

    获取Cookie

    request.COOKIES['key']
    request.get_signed_cookie(key, default=RAISE_ERROR, salt='', max_age=None)

    参数:

    • default: 默认值
    • salt: 加密盐
    • max_age: 后台控制过期时间

    设置Cookie

    rep = HttpResponse(...)
    rep = render(request, ...)
    
    rep.set_cookie(key,value,...)
    rep.set_signed_cookie(key,value,salt='加密盐',...)

    参数:

    • key, 键
    • value='', 值
    • max_age=None, 超时时间
    • expires=None, 超时时间(IE requires expires, so set it if hasn't been already.)
    • path='/', Cookie生效的路径,/ 表示根路径,特殊的:根路径的cookie可以被任何url的页面访问
    • domain=None, Cookie生效的域名
    • secure=False, https传输
    • httponly=False 只能http协议传输,无法被JavaScript获取(不是绝对,底层抓包可以获取到也可以被覆盖)

    删除Cookie

    def logout(request):
        rep = redirect("/login/")
        rep.delete_cookie("user")  # 删除用户浏览器上之前设置的usercookie值
        return rep

    Cookie版登陆校验

    # 登录
    def login(request):
        if request.method=="POST":
            name=request.POST.get("name")
            pwd=request.POST.get("pwd")
            if name=="cao" and pwd=="123":
    
                rep=redirect("/index1/")
                # rep.set_cookie("name",name)
                # 加盐
                # rep.set_signed_cookie("name",name ,salt="nidaye
                # 设置时间,时间一到自动跳转到登录页面
                # rep.set_signed_cookie("name",name,salt="nidaye",max_age=10)
                #path='/', Cookie生效的路径,/ 表示根路径,特殊的:根路径的cookie可以被任何url的页面访问
                rep.set_signed_cookie("name1", name, salt="nidaye", max_age=100,path="/index1/")
                return rep
    
        return render(request,"login.html")
    
    
    def index1(request):
        
        # name=request.COOKIES.get("name")
        # 加盐的
        # name=request.get_signed_cookie("name",None,salt="nidaye")
    
        # 时间一到,name取不到值则跳转到登录页面
        name = request.get_signed_cookie("name1", None, salt="nidaye")
        # 如果取不到name则自动跳转到登录页面
        if not name:
            return redirect("/login/")
        return render(request,"index1.html",{"name":name})
    
    
    def index2(request):
    
        name = request.get_signed_cookie("name1", None, salt="nidaye")
        if not name:
            return redirect("/login/")
        return render(request,"index2.html",{"name":name})
    登录校验

    Session

      知识点:
        import         views  
        import_module "views"  (引入字符串模块)


    Django中默认支持Session,其内部提供了5种类型的Session供开发者使用:
    1.数据库(默认)  2.缓存   3.文件  4.缓存+数据库  5.加密cookie 一、Session是保存在服务端的“键值对”(数据) 二、ession必须依赖于Cookie 三、Session要做的事儿:

      (1)session写操作:
        request.session["k"]=user
        request.sessions 是什么? 类对象
        1. 生成随机字符      
        2. 写到Cookie{"sessionID":"234asd243dv35fd"}回给浏览器,
        3. 自己保留一份,作为一个KEY,存到一个地方,KEY后面对应一个保存用户相关信息的键值对 

           django-session表:
             session-key       session-data
            234asd243dv35fd         {"user":"alex"}

       (2)session读操作
          user=request.session.get("k")

            1.取cookie值{"sessionID":"234asd243dv35fd"}
            2.去django-session表:
              session-key        session-data
              234asd243dv35fd      {"user":"alex"}
            3.{"user":"alex"}.get("user")

    删除session

    request.session.delete()

    request.session.flush() #及时更新   两个效果一样


    在浏览器第一次登录新用户(django_session表中会出现一条记录,(相当于一个浏览器只产生一条记录)),再登录一个新用户,session表中的记录会更新(django_session表中还是一条记录,此时随机字符串不变,session_data中的值会更新原来的值)

    数据库Session

    SESSION_ENGINE = 'django.contrib.sessions.backends.db'   # 引擎(默认)

    缓存Session

    SESSION_ENGINE = 'django.contrib.sessions.backends.cache'  # 引擎
    SESSION_CACHE_ALIAS = 'default'                            
    # 使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置
            django-redis组件:
                - 将django的缓存放置到redis中
                    from django.shortcuts import render,HttpResponse
                    from django.views.decorators.cache import cache_page
    
    
                    @cache_page(60 * 15)
                    def index(request):
                        # 去连接池中获取连接
                        return HttpResponse('...')
                - 将session保存到redis中
                    CACHES = {
                        "default": {
                            "BACKEND": "django_redis.cache.RedisCache",
                            "LOCATION": "redis://127.0.0.1:6379",
                            "OPTIONS": {
                                "CLIENT_CLASS": "django_redis.client.DefaultClient",
                                "CONNECTION_POOL_KWARGS": {"max_connections": 100}
                                # "PASSWORD": "密码",
                            }
                        },
                    }
    
                    SESSION_ENGINE = 'django.contrib.sessions.backends.cache'  # 引擎
                    SESSION_CACHE_ALIAS = 'default'  # 使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置
    View Code

    文件Session

    SESSION_ENGINE = 'django.contrib.sessions.backends.file'    # 引擎
    SESSION_FILE_PATH = None                                    # 缓存文件路径,如果为None,则使用tempfile模块获取一个临时地址tempfile.gettempdir() 

    缓存+数据库

    SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db'        # 引擎

    加密Cookie Session

    SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies'   # 引擎

    其他公用设置项:

    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,默认修改之后才保存(默认)

    不管你怎么设置Session,使用方式都一样:

    def index(request):
        # 获取、设置、删除Session中数据
        request.session['k1']
        request.session.get('k1',None)
        request.session['k1'] = 123
        request.session.setdefault('k1',123) # 存在则不设置
        del request.session['k1']
    
        # 所有 键、值、键值对
        request.session.keys()
        request.session.values()
        request.session.items()
        request.session.iterkeys()
        request.session.itervalues()
        request.session.iteritems()
    
    
        # 用户session的随机字符串
        request.session.session_key
    
        # 将所有Session失效日期小于当前日期的数据删除
        request.session.clear_expired()
    
        # 检查 用户session的随机字符串 在数据库中是否
        request.session.exists("session_key")
    
        # 删除当前用户的所有Session数据
        request.session.delete()
    
        request.session.set_expiry(value)
            * 如果value是个整数,session会在些秒数后失效。
            * 如果value是个datatime或timedelta,session就会在这个时间后失效。
            * 如果value是0,用户关闭浏览器session就会失效。
            * 如果value是None,session会依赖全局session失效策略。

    Session版登陆验证

    from functools import wraps
    
    
    def check_login(func):
        @wraps(func)
        def inner(request, *args, **kwargs):
            next_url = request.get_full_path()
            if request.session.get("user"):
                return func(request, *args, **kwargs)
            else:
                return redirect("/login/?next={}".format(next_url))
        return inner
    
    
    def login(request):
        if request.method == "POST":
            user = request.POST.get("user")
            pwd = request.POST.get("pwd")
    
            if user == "alex" and pwd == "alex1234":
                # 设置session
                request.session["user"] = user
                # 获取跳到登陆页面之前的URL
                next_url = request.GET.get("next")
                # 如果有,就跳转回登陆之前的URL
                if next_url:
                    return redirect(next_url)
                # 否则默认跳转到index页面
                else:
                    return redirect("/index/")
        return render(request, "login.html")
    
    
    @check_login
    def logout(request):
        # 删除所有当前请求相关的session
        request.session.delete()
        return redirect("/login/")
    
    
    @check_login
    def index(request):
        current_user = request.session.get("user", None)
        return render(request, "index.html", {"user": current_user})
    Session版登录验证

    CBV中加装饰器相关

    CBV实现的登录视图

    class LoginView(View):
    
        def get(self, request):
            """
            处理GET请求
            """
            return render(request, 'login.html')
    
        def post(self, request):
            """
            处理POST请求 
            """
            user = request.POST.get('user')
            pwd = request.POST.get('pwd')
            if user == 'alex' and pwd == "alex1234":
                next_url = request.GET.get("next")
                # 生成随机字符串
                # 写浏览器cookie -> session_id: 随机字符串
                # 写到服务端session:
                # {
                #     "随机字符串": {'user':'alex'}
                # }
                request.session['user'] = user
                if next_url:
                    return redirect(next_url)
                else:
                    return redirect('/index/')
            return render(request, 'login.html')
    CBV实现登录视图

    要在CBV视图中使用我们上面的check_login装饰器,有以下三种方式:

    from django.utils.decorators import method_decorator

    1. 加在CBV视图的get或post方法上

    from django.utils.decorators import method_decorator
    
    
    class HomeView(View):
    
        def dispatch(self, request, *args, **kwargs):
            return super(HomeView, self).dispatch(request, *args, **kwargs)
    
        def get(self, request):
            return render(request, "home.html")
        
        @method_decorator(check_login)
        def post(self, request):
            print("Home View POST method...")
            return redirect("/index/")

    2. 加在dispatch方法上

    from django.utils.decorators import method_decorator
    
    
    class HomeView(View):
    
        @method_decorator(check_login)
        def dispatch(self, request, *args, **kwargs):
            return super(HomeView, self).dispatch(request, *args, **kwargs)
    
        def get(self, request):
            return render(request, "home.html")
    
        def post(self, request):
            print("Home View POST method...")
            return redirect("/index/")

    因为CBV中首先执行的就是dispatch方法,所以这么写相当于给get和post方法都加上了登录校验。

    3. 直接加在视图类上,但method_decorator必须传 name 关键字参数

    如果get方法和post方法都需要登录校验的话就写两个装饰器。

    from django.utils.decorators import method_decorator
    
    @method_decorator(check_login, name="get")
    @method_decorator(check_login, name="post")
    class HomeView(View):
    
        def dispatch(self, request, *args, **kwargs):
            return super(HomeView, self).dispatch(request, *args, **kwargs)
    
        def get(self, request):
            return render(request, "home.html")
    
        def post(self, request):
            print("Home View POST method...")
            return redirect("/index/")

    用户认证 

    auth模块

    from django.contrib import auth
    1 使用auth模块必须以django自带的auth_user表作为用户表

    2 自己的用户表继承Django的auth_user表
      from django.contrib.auth.models import AbstractUser

    1 、authenticate()   

    提供了用户认证,即验证用户名以及密码是否正确,一般需要username  password两个关键字参数

    如果认证信息有效,会返回一个  User  对象。authenticate()会在User 对象上设置一个属性标识那种认证后端认证了该用户,且该信息在后面的登录过程中是需要的。当我们试图登陆一个从数据库中直接取出来不经过authenticate()的User对象会报错的!!

    #验证成功返回user对象(一条用户记录),否则返回None
    user=auth.authenticate(username=user,password=pwd)

    2 、login(HttpRequest, user)  

    该函数接受一个HttpRequest对象,以及一个认证了的User对象

    此函数使用django的session框架给某个已认证的用户附加上session id等信息

    def log_in(request):
        if request.method=="POST":
            user=request.POST.get("user")
            pwd=request.POST.get("pwd")
    
            # 验证成功返回user对象(一条用户记录),否则返回None
            user=auth.authenticate(username=user,password=pwd)
            if user:
                auth.login(request,user)   #auth.login()函数相当于 session写操作
                return redirect("/index/")
    
        return render(request,"login.html")

    3 、logout(request) 注销用户  

    # 注销用户
    def log_out(request):
        auth.logout(request)
        return redirect("/login/")

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

    4 、user对象的 is_authenticated()

    要求:

    1  用户登陆后才能访问某些页面,

    2  如果用户没有登录就访问该页面的话直接跳到登录页面

    3  用户在跳转的登陆界面中完成登陆后,自动访问跳转到之前访问的地址

    方法1:

    1
    2
    3
    def my_view(request):
      if not request.user.is_authenticated():
        return redirect('%s?next=%s' % (settings.LOGIN_URL, request.path))

    方法2:

    django已经为我们设计好了一个用于此种情况的装饰器:login_requierd()

    1
    2
    3
    4
    5
    from django.contrib.auth.decorators import login_required
          
    @login_required
    def my_view(request):
      ...

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

    User对象()

    User 对象属性:username, password(必填项)password用哈希算法保存到数据库

    is_staff : 用户是否拥有网站的管理权限.

    is_active : 是否允许用户登录, 设置为``False``,可以不用删除用户来禁止 用户登录

    from django.contrib.auth.models import User
    User——>auth-user表
    request.user 返回一个对象

    2.1 、is_authenticated()

    如果是真正的 User 对象,返回值恒为 True 。 用于检查用户是否已经通过了认证。
    通过认证并不意味着用户拥有任何权限,甚至也不检查该用户是否处于激活状态,这只是表明用户成功的通过了认证。 这个方法很重要, 在后台用request.user.is_authenticated()判断用户是否已经登录,如果true则可以向前台展示request.user.name

    2.2 、创建用户

    使用 create_user 辅助函数创建用户:

    1
    2
    from django.contrib.auth.models import User
    user = User.objects.create_user(username='',password='',email='')

    2.3 、check_password(passwd)

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

    2.4 、修改密码

    使用 set_password() 来修改密码

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

    2.5 、简单示例

    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)
    修改密码

     

  • 相关阅读:
    Android开发之适配器-ListView适配器的重复数据
    Android开发之TextView的下划线添加
    Android 自定义View修炼-Android开发之自定义View开发及实例详解
    Android 开发之自定义Dialog及UI的实现
    Android开发之ContentProvider(内容提供者)
    XC文件管理器(Android应用)
    高效 告别996,开启java高效编程之门 4-1普通码农与风骚码农资源关闭PK
    高效 告别996,开启java高效编程之门 4-2垃圾回收与物理资源释放
    高效 告别996,开启java高效编程之门 3-29实战案例五:排序
    高效 告别996,开启java高效编程之门 3-28实战案例四:分组
  • 原文地址:https://www.cnblogs.com/caochao-/p/8353041.html
Copyright © 2011-2022 走看看