栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

购物车案例——登录

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

购物车案例——登录

登录功能 登录流程 vue前端
  1. 在页面中点击登录,会触发对应的函数。可以在App组件中找到如下代码:
  • 登录 | 注册
  • //触发的login函数 login() { // 点击登录按钮, 通过更改vuex的showLogin值显示登录组件 this.setShowLogin(true); //从vuex中映射过来的方法 },

    通过分析可知,login方法更改了vuex中的showLogin的值,从而控制登录组件的显示。

    1. MyLogin.vue组件
    • v-model获取用户信息
    • 点击登录按钮,触发Login方法
    • 在Login方法中,使用axios的post方法提交参数,并接收响应结果
    // 点击登录触发
    Login() {
      // 通过element自定义表单校验规则,校验用户输入的用户信息
      this.$refs["ruleForm"].validate(valid => {
        //如果通过校验开始登录
        if (valid) {
          // 发送ajax
          this.$axios.post("/users/login/", {
              user: this.LoginUser.name,
              pwd: this.LoginUser.pass,
            })
            .then(res => {
              console.log("@@登录的响应:", res)
              // 200代表登录成功,其他的均为失败
              if (res.data.code == 200) {
                // res.data为后端响应的json
                // 隐藏登录组件
                this.isLogin = false;
                // 登录信息存到本地缓存
                let user = JSON.stringify(res.data.user);
                //要求后台返回的数据
                //{
                //     "code":200, 
                //     'msg': "欢迎user",
                //     "user":{
                //       userName:"xxx",
                //     },
                //}
                // 前端存储用户信息,表示登录成功
                localStorage.setItem("user", user);
                // sessionStorage.setItem("")
                // 登录信息存到vuex,控制页面欢迎信息
                this.setUser(res.data.user);
                // 弹出通知框提示登录成功信息
                this.notifySucceed(res.data.msg);
              } else {//响应不是200
                // 清空输入框的校验状态
                this.$refs["ruleForm"].resetFields();
                // 弹出通知框提示登录失败信息
                this.notifyError(res.data.msg);
              }
            })
            .catch(err => {
              console.log(err)
              return Promise.reject(err);
            });
        } else {//未通过用户校验
          return false;
        }
      });
    }
    
    django后端
    1. 路由匹配
    # /users/login/
    path("login/", Login.as_view()),
    
    1. 视图接口
    from django.contrib.auth.hashers import check_password 
    from django.contrib.auth import authenticate
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from user.models import *
    
    class Login(APIView):
        def post(self, request):
            # 1. 获取前端数据
            # 前端发送post 数据{user:xxx, pwd:xxx} 
            username = request.data.get("user")
            password = request.data.get("pwd")
    
            #2. 验证用户
            # user = authenticate(username=username,password=password)
            try:
                user = User.objects.get(username=username)
            except:
                return Response({"code":204,"msg":"用户不存在!"})
    
            # 用户存在,验证密码
            if check_password(password, user.password):
                #密码正确
                #会话保持,django后端只需要简单设置session,返回的响应会带着sessionid---->Vue代理处理cookie存储
                request.session["username"] = username
                
                return Response({"code":200, "msg":"欢迎%s"%username, 'user':{"userName":username, 'uid':user.id}})
            # 验证未通过
            res = Response({"code":204, "msg":"用户名或密码不正确!"})
            return res
    
    JWT认证

    json web token

    形式:一长串字符串,只不过字符串有特殊的规则

    完整形式如下:

    eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjpbeyJ1c2VybmFtZSI6InpoYW5nc2FuIn1dLCJpYXQiOjE2NTM0NDMyNzIsImV4cCI6MTY1MzkyNjM5OSwiYXVkIjoiIiwiaXNzIjoiIiwic3ViIjoiIn0.UIlYy4D2VrWJZhkc6KCBHbD0es4Knm-o7HrO6XVoIaQ

    eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

    eyJkYXRhIjpbeyJ1c2VybmFtZSI6InpoYW5nc2FuIn1dLCJpYXQiOjE2NTM0NDMyNzIsImV4cCI6MTY1MzkyNjM5OSwiYXVkIjoiIiwiaXNzIjoiIiwic3ViIjoiIn0

    UIlYy4D2VrWJZhkc6KCBHbD0es4Knm-o7HrO6XVoIaQ

    第一部分
    {"alg":"HS256","typ":"JWT"}
    
    # eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
    
    第二部分
    {
        "id":"编号",
        "username":"元宝",
        "age":"18",
        "balance":"0",
    }
    
    # 编码之后 = ewogICAgImlkIjoiNDEwMDAwMjAwMDAyMDIwMjEyIiwKICAgICJ1c2VybmFtZSI6InpoYW5nc2FuIiwKICAgICJhZ2UiOiIxOCIsCiAgICAiYmFsYW5jZSI6IjAiLAp9
    
    第三部分
    # 把前两部分进行整体的签名
    
    # 1. 把第一部分和第二部分编码之后的字符串用 "."拼接,生成一个新的字符串
    eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.ewogICAgImlkIjoiNDEwMDAwMjAwMDAyMDIwMjEyIiwKICAgICJ1c2VybmFtZSI6InpoYW5nc2FuIiwKICAgICJhZ2UiOiIxOCIsCiAgICAiYmFsYW5jZSI6IjAiLAp9
    
    # 2. 把新生成的字符串,通过HS256这种加密方式进行加密,加密的时候,需要提供一个加密密钥
    加密(新字符串+加密密钥)
    # 生成一个签名内容 
    # MDkzZDQ2M2JjOGVlMTJmNzQxOTNkZGJmZDYxODY3NzVmYWI4ZGY1ZDFmNmVmOWU5MzU2OTUwMDIyN2E0ZGVmZA
    
    最终的JWT
    # 第一部分.第二部分.第三部分
    eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.ewogICAgImlkIjoiNDEwMDAwMjAwMDAyMDIwMjEyIiwKICAgICJ1c2VybmFtZSI6InpoYW5nc2FuIiwKICAgICJhZ2UiOiIxOCIsCiAgICAiYmFsYW5jZSI6IjAiLAp9.MDkzZDQ2M2JjOGVlMTJmNzQxOTNkZGJmZDYxODY3NzVmYWI4ZGY1ZDFmNmVmOWU5MzU2OTUwMDIyN2E0ZGVmZA
    

    第一部分:header

    #一般固定如下
    {"alg":"HS256","typ":"JWT"}
    
    base64编码 ,并替换=号--->    "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"
    

    第二部分: payload

    {
       'id': user.id,
       'username': user.username,
       ‘exp’: time.time() + 300,  #过期时间
    }
    
    base64编码-> "eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZvaG4gRGdWV9"
    

    第一部分和第二部分, 可以被其他人使用base64解密,不建议存储敏感信息

    第三部分:
    前两部分的编码串通过 ‘.’ 连接,得到如下:

    temp = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZvaG4gRGdWV9"
    

    然后使用第一部分 声明的算法HS256进行加密,得到如下:

    import hmac
    h = hmac.new(b'key', temp.encode(), digestmod='SHA256')
    sign = base64.urlsafe_b64encode(h.digest())
    

    最后三者拼接:1.2.3

    django方案一(采用)

    自定义登录视图,使用pyjwt 自己生成 token, 此类方案支持所有的python框架

    pip install pyjwt
    

    生成token

    import datetime
    import jwt  #需要安装pip install pyjwt
    from django.conf import settings
    
    def generate_token(user):
        """
         :param user: 用户对象
         :return: 生成的token
        """
        #自己组织payload
        payload = {
            'user_id': user.id,
            'username': user.username,
            'exp': datetime.datetime.now() + datetime.timedelta(seconds=300)
        }
        # token 要自己生成: 第二部分的载荷,盐部分, 算法
        token = jwt.encode(payload=payload, key=settings.SECRET_KEY, algorithm='HS256')
        return token
    

    登录视图

    from django.contrib.auth import authenticate
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from user.models import *
    
    class Login(APIView):
        def post(self, request):
        	#获取前端数据
            username = request.data.get('user')
            password = request.data.get('pwd')
    
            user = authenticate(username=username, password=password)
    
            if user:
                token = generate_token(user)
                return Response({
                	'code':200,
                    'msg': '登录成功!',
                    'token': token,
                    'user': {
                        'userName': user.username,
                        'uid': user.id
                    }
                })
            else:
                return Response({"code":204, 'msg': '用户名或密码错误'})
    

    路由配置

    urlpatterns = [
       path('login/', Login.as_view()),
    ]
    

    Vue前端存储token

    localStorage.setItem("token", res.data.token)
    #后续的请求 携带token
    let token = localStorage.getItem("token")
    
    django方案二

    自定义登录视图,使用 djangorestframework-jwt提供的 方法生成token,此类方案只能支持django框架

    pip install djangorestframework-jwt
    

    登录视图

    from rest_framework_jwt.utils import jwt_payload_handler, jwt_encode_handler 
    from django.contrib.auth import authenticate
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from user.models import *
    
    
    class Login(APIView):
        def post(self, request):
            username = request.data.get('user')
            password = request.data.get('pwd')
    
            user = authenticate(username=username, password=password)
    
            if user:
                payload = jwt_payload_handler(user)
    			token = jwt_encode_handler(payload)
                return Response({
                	"code":200,
                    'msg': '登录成功!',
                    'token': token,
                    'user': {
                        'userName': user.username,
                        'uid': user.id
                    }
                })
            else:
                return Response({"code":200, 'msg': '用户名或密码错误!'})
    

    路由配置

    urlpatterns = [
       path('login/', Login.as_view()),
    ]
    
    WEB STORAGE

    存数据/改数据

    localStorage.setItem(“age”,“29”)

    取数据

    var age = localStorage.getItem(“age”)

    删除数据

    localStorage.removeItem(“age”)

    多方式登录

    django内置的用户认证方式只支持 用户名和密码,而实际的项目开发中,登录方式往往不止一种

    因此,需要重写用户认证类,指明新的 认证方式,添加手机号登录方式。

    django

    官方文档

    自定义身份认证类

    utils/auth.py,在项目中创建一个utils目录,自定义认证类

    from django.contrib.auth.backends import ModelBackend
    from django.contrib.auth.hashers import check_password
    from django.db.models import Q
    from user.models import User
    
    
    # 自定义 认证类,需要在 settings.py 中指明配置项
    class AuthBackend(ModelBackend):
        def authenticate(self, request, username=None, password=None, **kwargs):
            """需要继承django内置的用户认证类,并重写认证方法,可以支持多种方式进行登录"""
            try:
                user = User.objects.get(Q(username=username) | Q(mobile=username))
            except Exception as e:
                return None
            # 校验密码: 先写 需要校验的密码, 后写 加密后的密码
            if check_password(password, user.password):
                return user
            else:
                return None
    

    指明配置项

    在配置文件中,指明认证类

    # 指定用户认证引擎
    AUTHENTICATION_BACKENDS = [
        'utils.auth.AuthBackend' , # 自己定义的认证类路径
    ]
    
    退出登录 使用session会话保持的退出:

    Vue前端

    // 退出登录
    logout() {
      // 不显示退出登录框
      this.visible = false;
    
      this.$axios.post("/users/logout/").then((res) => {
        console.log("@@退出登录的响应:", res);
    
        if (res.data.code == 200) {
          // 清空本地登录信息
          // localStorage.setItem("user", "");
          localStorage.removeItem("user");
    
          // 清空vuex登录信息
          this.setUser("");
          this.notifySucceed("成功退出登录");
        }else{
          console.log("退出请求失败")
        }
      }).catch(err=>{return Promise.reject(err)})
    },
    

    django后端

    #/users/logout/
    path("logout/", Logout.as_view()),
    
    #视图接口
    class Logout(APIView):
        def post(self, request):
            print("会话保持:", request.session.items())
            #前端Vue代理会处理sessionid的存储及Cookie信息的携带
            #删除会话
            if request.session.get("username"):
                del request.session["username"]
            print("再次查看session:", request.session.items())
    
            return Response({"code":200, "msg":"ok"})
    
    使用jwt会话保持的退出:

    只需要 删除 localStorage中存储的token即可

    也可以用中间件来做会话保持 在根目录下新建middleware 文件夹->middleware.py文件
    from django.utils.deprecation import MiddlewareMixin
    import jwt
    from django.conf import settings
    
    class CheckUserMiddleware(MiddlewareMixin):
        def process_request(self, request):
            token = request.headers.get('token')
            if not token:
                request.user_info = None
            else:
                payload = jwt.decode(jwt=token, key=settings.SECRET_KEY, algorithms='HS256')
                request.user_info = payload
    
    记得在项目配置里导入自定义的中间件
    MIDDLEWARE = [
        'middleware.middleware.CheckUserMiddleware'
    ]
    
    之后在验证用户是否登录时

    就

    		try:
                user_info = request.user_info
                user = User.objects.get(id=user_info.get('id'))
            except Exception as e:
                print(e)
                return Response({
                    'code': 204,
                    'msg': '用户不存在或未登录!'
                })
    
    转载请注明:文章转载自 www.mshxw.com
    本文地址:https://www.mshxw.com/it/1030771.html
    我们一直用心在做
    关于我们 文章归档 网站地图 联系我们

    版权所有 (c)2021-2022 MSHXW.COM

    ICP备案号:晋ICP备2021003244-6号