大家都使用过三方登录 例如(QQ、微信、微博)那我就带着大家学习一下三方登录,并且我们好引入工厂模式来进行,开始吧

工厂模式

首先我们简单介绍一下工厂模式。大家都知道有一造车知名企业,在疫情期间 ,竟然开始生产口罩

是什么原因呢!就是工厂模式所带来的好处 ,就是你给我什么 ,我就给你生产什么。

工厂收到钢铁,那就开始制造汽车 。收到针线 ,就开始制造口罩。

demo事例

class Dingding:
    # 钉钉登录类
    def __repr__(self):
        return "钉钉登录"

    def geturl(self):
        return '123'


class GitEe:
    # 码云登录类
    def __repr__(self):
        return "码云登录"
    def geturl(self):
        return '456'


# 工厂类
class SimpleFactory:

    @staticmethod   # 静态方法无需实例化 直接调用
    def product_login(name):
        if name == "dingding":
            return Dingding()
        elif name == "gitee":
            return GitEe()


demo1 = SimpleFactory.product_login('dingding')
print(demo1.geturl())

代码实现

1.封装

# 解密
from django.contrib.auth.hashers import check_password, make_password
# 返回HttpResponse
from django.http import HttpResponse
# 解码
from django.utils.baseconv import base64
# 返回Response
import time
import hmac
import base64
from hashlib import sha256
import urllib
import json
import requests


class DingDing:
    # 钉钉登录类
    def __repr__(self, code):
        t = time.time()
        # 时间戳
        timestamp = str((int(round(t * 1000))))
        appSecret = 'YCoNtgYLMDKNS9096KKrnDDazZ7IgJHtGiOA7Y0YvTB8c4tn2vRBvaj_GTIvMkHQ'
        # 构造签名
        signature = base64.b64encode(
            hmac.new(appSecret.encode('utf-8'), timestamp.encode('utf-8'), digestmod=sha256).digest())
        # 请求接口,换取钉钉用户名
        payload = {'tmp_auth_code': code}
        headers = {'Content-Type': 'application/json'}
        res = requests.post('https://oapi.dingtalk.com/sns/getuserinfo_bycode?signature=' + urllib.parse.quote(
            signature.decode("utf-8")) + "&timestamp=" + timestamp + "&accessKey=dingoa2kslvfvtiaeic7wi",
                            data=json.dumps(payload), headers=headers)
        # 转换为json格式
        res_dict = json.loads(res.text)
        return res_dict

    def geturl(self):
        appid = 'dingoa2kslvfvtiaeic7wi'  # 应用中的appid
        redirect_uri = 'http://127.0.0.1:8000/user/dindin_back/'  # 钉钉返回信息的回调地址

        return {
            "dindin_url": "https://oapi.dingtalk.com/connect/qrconnect?appid=" + appid + '&response_type=code&scope=snsapi_login&state=STATE&redirect_uri=' + redirect_uri}


class GitEe:
    def __repr__(self, code):
        print(code)
        r = requests.post(
            "https://gitee.com/oauth/token?grant_type=authorization_code&code=" + code + "&client_id=bef8beab2a56f463fff62bc93bbd87072b5fc1904c6282ca7807d9523038ec52&redirect_uri=http://127.0.0.1:8000/user/gitee_back/&client_secret=b8f5cf324427f286b49276d6db87900b54c8ed49d9d21a88c65ca4e76fa6151c")
        access_token = eval(r.text).get("access_token")
        # print(access_token)
        req = requests.get("https://gitee.com/api/v5/user?access_token=" + str(access_token))
        # 转换为json格式
        res_dict = json.loads(req.text)
        return res_dict

    def geturl(self):
        return {
            "gitee_url": "https://gitee.com/oauth/authorize?client_id=bef8beab2a56f463fff62bc93bbd87072b5fc1904c6282ca7807d9523038ec52&redirect_uri=http://127.0.0.1:8000/user/gitee_back/&response_type=code"}


# 工厂类
class Plant:
    @staticmethod
    def product_login(name, code):
        # 判断是否携带code值 有则回调 没有则返回url
        if code:
            if name == "dindin_back":
                d = DingDing()
                return d.__repr__(code)
            elif name == "gitee_back":
                g = GitEe()
                return g.__repr__(code)
        else:
            if name == "dingding":
                d = DingDing
                return DingDing()
            elif name == "gitee":
                return GitEe()

# demo = Plant.product_login('gitee', '123123123')
# print(demo.geturl())

2.djang/app/views.py

# 工厂模式  三方登录
class PlantLoginAPIView(APIView):
    permission_classes = (AllowAny,)

    # 获取三方登录 url地址
    def post(self, request):
        why = request.data.get("why")
        url = plant_login.Plant.product_login(why, None)
        return Response(url.geturl())

    # 回调地址 获取用户详细信息
    def get(self, request):
        code = request.GET.get("code")
        # 可以用很多方法实现  查找 包含 都可
        # 获取当前url地址 切分后为  ['','user','***_back','']
        details = plant_login.Plant.product_login(request.path_info.split('/')[2], code)
        return Response({"msg": "ok", "details": details})

3.djang/app/urls.py

from django.urls import path
from .views import *

urlpatterns = [
    path('url/', PlantLoginAPIView.as_view()),  # gitee__钉钉 三方登录地址

]

vue发送

<template>
  <div>

    <center><h1>用户登录</h1></center>

    <a-form-item label="用户名" v-bind="formlayout">
      <a-input ref="userNameInput" v-model="username" placeholder="Basic usage">
        <a-icon slot="prefix" type="user"/>
        <a-tooltip slot="suffix" title="Extra information">
          <a-icon type="info-circle" style="color: rgba(0,0,0,.45)"/>
        </a-tooltip>
      </a-input>

    </a-form-item>
    <a-form-item label="密码" v-bind="formlayout">
      <a-input prefix="*" suffix="" v-model="password"/>
    </a-form-item>
    <a-form-item label="验证码" v-bind="formlayout">
      <a-input v-model="verification" @blur="isVerification"/>
      <span v-if="isverification">验证码错误</span>
      <a-button type="primary" @click="clickVerification">点击发送验证码</a-button>
    </a-form-item>

    <a-form-item v-bind="buttonlayout">
      <a-button type="primary" @click="submit">登录</a-button>
      <img style="margin-left:20px;cursor:pointer;" @click="dingding" src="三方登录-工厂模式-钉钉gitee.assets/F05F658D6F.png"/>
      <img style="margin-left:20px;cursor:pointer;" @click="gitee" src="三方登录-工厂模式-钉钉gitee.assets/c9C1ED39B9.png"/>
      <h1>Facebook社交登录</h1>

      <div class="fb-login-button" data-size="large" data-button-type="continue_with" data-layout="default"
           data-auto-logout-link="false"
           data-onlogin="login" data-use-continue-as="false" data-width=""></div>

    </a-form-item>

  </div>
</template>

<script type="text/javascript">

import {postgitee, getisVerification, getVerification, postDinDin, postLogin} from "../http/apis";

export default {

  data() {
    return {
      selected: "",
      startdate: "",
      uid: "",
      username: "",
      password: "",
      verification: "",
      isverification: false,
      //表单样式
      formlayout: {
        //标签
        labelCol: {
          xs: {span: 24},
          sm: {span: 8}
        },
        //文本框
        wrapperCol: {
          xs: {span: 24},
          sm: {span: 3}
        }
      },
      //按钮样式
      buttonlayout: {
        //按钮
        wrapperCol: {
          xs: {
            span: 24,
            offset: 0
          },
          sm: {span: 16, offset: 8}
        }
      }
    }

  },
  //自定义方法
  methods: {
    facebook() {
      // crossorigin="anonymous" src="三方登录-工厂模式-钉钉gitee.assets/9bFE8eBF1Ats=1" nonce="BBgy4tba"
      FB.login(function (response) {
        console.log(response);
      });
    },

    gitee() {
      postgitee({why: "gitee"}).then(res => {
        console.log(res)
        window.open(res.gitee_url)
      })
    },
    //判断验证码
    isVerification() {

      getisVerification({verification: this.verification, uid: this.uid}).then(res => {
        console.log(res)
        if (res.code == 200) {
          this.isverification = false
        } else {
          this.isverification = true
        }
      }).catch(err => {
        console.log(err)
      })

    },
    //发送钉钉验证码
    clickVerification() {
      getVerification().then(res => {
        console.log(res)
        this.uid = res.uid
      }).catch(err => {
        console.log(err)
      })
    },
    //钉钉登录
    dingding: function () {
      postDinDin({why: "dingding"}).then(res => {
        console.log(res)
        //打开新窗口跳转到此地址
        window.open(res.dindin_url)
      })
      // window.location.href = "http://localhost:8000/dingding_url/";

    },
    submit: function () {
      // let just = true;
      // just = this.isVerification() & just;
      if (this.isverification === false) {
        let params = {
          username: this.username,
          password: this.password,
        }
        //登录
        postLogin(params).then(res => {
          console.log(res)
          if (res.token) {
            localStorage.setItem("token", res.token)
            localStorage.setItem("username", res.username)
            localStorage.setItem("id", res.id)
          } else {
            alert("登录失败")
          }
        }).catch(err => {
          console.log(err)
        })
      }
};


</script>

<style type="text/css">


</style>