几种登录模式

本文详细介绍了六种网页登录模式:正常登录、委托登录、验证码登录、扫码登录、单点登录以及人脸识别登录。正常登录涉及用户信息收集、校验和token获取;委托登录增加了一层主账号与委托人之间的交互;验证码登录通过第三方发送和验证手机验证码;扫码登录利用二维码状态变化和token认证;单点登录通过特定URL参数实现跨系统身份验证;人脸识别登录结合了媒体设备访问、人脸识别技术和后台比对。

1. 正常登录

收集用户信息、校验、请求接口后台校验得到token

2. 委托登录

初始登录模式相同,中间加了一层,初始登录请求来主账号信息(含token)及委托人数组,再使用委托人信息登录(委托人token)或者跳过(主账号token)。验证码通过transform、rotato实现。

3. 验证码登录

点击发送验证码将对应手机号发送到第三方,第三方会将验证码转发给手机及相应后台,点击登陆验证对应手机号及验证码信息。

4. 扫码登录

二维码登录原理主要基于token的认证机制+二维码状态变化实现
1、二维码状态有三种:待扫描、已扫描待确认、已确认;
2、待扫描:PC端携带设备信息向服务端发送请求,服务端生成二维码ID与设备信息进行绑定,将二维码ID返回给PC端,PC端已二维码的形式显示二维码;
3、PC端通过轮询的方式向服务端查询二维码的状态是否发生变化;
4、移动端扫描PC端二维码,获取到二维码ID,移动端带二维码ID+移动端身份信息(token)发送给服务端,服务端验证身份信息通过后,将二维码ID与身份信息绑定,并生成临时token返回给移动端,二维码状态变为已扫描待确认;
5、移动端确认登录,并携带临时token请求服务端,服务端验证临时token通过后,改变二维码状态为已确认并生成PCtoken,PC端通过轮询知二维码状态.当为已确认状态时,返回PCtoken,后续PC端通过token可以返回API;

5. 单点登录

http://IP:PORT/icore/sso/login?ssou=usercode&ssomd5=md5&ssol=zh_CN&ssourl=MDM功能url

根据用户名当前时间及sshkey经过md5加密及用户名(该用户必须是两个系统公用)、多语言、页面url请求回来一个包含token的html页面,页面中的js执行存储token及跳转页面url,有用户名加token则可以访问主数据页面(无需密码)。

6. 人脸识别登录(tracking.js)

访问用户媒体设备(navigator.mediaDevices.getUserMedia)–>成功则拿到对应流放入video标签的srcObject–>video上的onloadedmetadata播放play及人脸识别(调用tracking及其track监听)–>拍照(refCanvas用来画图:拍照的照片)得到照片信息发送给后台–>后台百度ai比对

<!DOCTYPE html>
<html lang="en" style="font-size: 37.5px">
  <head>
    <meta charset="utf-8" />
    <meta content="IE=edge" http-equiv="X-UA-Compatible" />
    <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport" />
    <title>百度ai</title>
    <script src="./libs/tracking-min.js"></script>
    <script src="./libs/face-min.js"></script>
    <!-- <script src="./libs/jquery-3.6.0.min.js" type="text/javascript"></script> -->
    <script src="./libs/vue.js" type="text/javascript"></script>
  </head>
  <style>
    .face-capture {
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      justify-content: space-between;
    }
    .face-capture video,
    .face-capture canvas {
      position: fixed;
      top: 0;
      bottom: 0;
      left: 0;
      right: 0;
      width: 100%;
      height: 100%;
      object-fit: cover;
      z-index: 2;
      background-repeat: no-repeat;
      background-size: 100% 100%;
    }
    .face-capture canvas {
      z-index: 2;
    }
    .face-capture .img-cover {
      position: absolute;
      height: 10rem;
      width: 10rem;
      z-index: 5;
      margin-top: -2rem;
      border: 1px solid red;
    }
    .face-capture .rect {
      border: 2px solid #0aeb08;
      position: fixed;
      z-index: 3;
    }
    .face-capture .control-container {
      margin-top: 10rem;
      position: relative;
      width: 100%;
      height: 100%;
      object-fit: cover;
      z-index: 4;
      background-repeat: no-repeat;
      background-size: 100% 100%;
    }
    .face-capture .title {
      text-align: center;
      /* color: white; */
      font-size: 18px;
      margin-top: 3rem;
    }
    .face-capture .close {
      width: 0.8rem;
      height: 0.8rem;
    }
  </style>
  <body>
    <div id="app">
      <div v-show="showContainer" class="face-capture" id="face-capture">
        <video ref="refVideo" id="video" autoplay playsinline webkit-playsinline="true"></video>
        <!-- <img src="./assets/kenan.jpg" id="img" alt="cover" class="img-cover" /> -->
        <!-- <div class="img-cover"></div> -->
        <div class="control-container face-capture">
          <p class="title">{{scanTip}}</p>
          <!-- <if condition="$beat eq 2">
            <a οnclick="manual" style="z-index: 999">
              <img class="close" style="width: 2rem; height: 2rem; margin-top: 0.1rem" src="./assets/kenan.jpg" alt="" />
            </a>
          </if> -->
          <canvas ref="refCanvas" :width="screenSize.width" :height="screenSize.height" :style="{opacity: 0}"></canvas>
        </div>
        <div class="rect" v-for="item in profile" :style="{ width: item.width + 'px', height: item.height + 'px', left: item.left + 'px', top: item.top + 'px'}"></div>
      </div>
      <img v-show="!showContainer" :src="imgUrl" />
      <input style="display: none" type="text" ref="xuanze" id="xuanze" name="xuanze" value="{$beat}" />
      <input style="display: none" type="text" ref="xuanze2" id="xuanze2" name="xuanze2" value="1" />
    </div>
  </body>
  <script>
    var rotateVal = 0 // 旋转角度
    // 设置定时器
    // var InterVal = setInterval(function () {
    //   var img = document.getElementById('img')
    //   rotateVal += 2
    //   // 设置旋转属性(顺时针)
    //   img.style.transform = 'rotate(' + rotateVal + 'deg)'
    //   // 设置旋转时的动画  匀速0.1s
    //   img.style.transition = '0.1s'
    // }, 50)
    //拍照
    function manual() {
      console.log(11111111)
      document.getElementById('xuanze').value = 1
      document.getElementById('xuanze2').value = 3
    }
    const app = new Vue({
      el: '#app',
      data() {
        return {
          screenSize: { width: window.screen.width, height: window.screen.height - 200 },
          URL: null,
          streamIns: null, // 视频流
          showContainer: true, // 显示
          tracker: null,
          tipFlag: false, // 提示用户已经检测到
          flag: false, // 判断是否已经拍照
          context: null, // canvas上下文
          profile: [], // 轮廓
          removePhotoID: null, // 停止转换图片
          scanTip: '人脸识别中...', // 提示文字
          imgUrl: '' // base64格式图片
        }
      },
      mounted() {
        this.playVideo()
      },
      methods: {
        // 访问用户媒体设备
        getUserMedia(constrains, success, error) {
          if (navigator.mediaDevices.getUserMedia) {
            //最新标准API
            navigator.mediaDevices.getUserMedia(constrains).then(success).catch(error)
          } else if (navigator.webkitGetUserMedia) {
            //webkit内核浏览器
            navigator.webkitGetUserMedia(constrains).then(success).catch(error)
          } else if (navigator.mozGetUserMedia) {
            //Firefox浏览器
            navagator.mozGetUserMedia(constrains).then(success).catch(error)
          } else if (navigator.getUserMedia) {
            //旧版API
            navigator.getUserMedia(constrains).then(success).catch(error)
          } else {
            this.scanTip = '你的浏览器不支持访问用户媒体设备'
          }
        },
        success(stream) {
          this.streamIns = stream
          // webkit内核浏览器
          this.URL = window.URL || window.webkitURL
          if ('srcObject' in this.$refs.refVideo) {
            this.$refs.refVideo.srcObject = stream
          } else {
            this.$refs.refVideo.src = this.URL.createObjectURL(stream)
          }
          this.$refs.refVideo.onloadedmetadata = (e) => {
            this.$refs.refVideo.play()
            this.initTracker()
          }
        },
        error(e) {
          this.scanTip = '访问用户媒体失败' + e.name + ',' + e.message
        },
        playVideo() {
          this.getUserMedia(
            {
              video: {
                width: 1280,
                height: 720,
                facingMode: 'user'
              } /* 前置优先 */
            },
            this.success,
            this.error
          )
        },
        // 人脸捕捉
        initTracker() {
          this.context = this.$refs.refCanvas.getContext('2d') // 画布
          this.tracker = new tracking.ObjectTracker(['face']) // tracker实例 识别人脸,眼睛。最唇
          this.tracker.setStepSize(2) // 设置步长
          this.tracker.setInitialScale(4)
          this.tracker.setEdgesDensity(0.1)
          this.tracker.on('track', this.handleTracked) // 绑定监听方法
          try {
            tracking.track('#video', this.tracker) // 开始追踪
          } catch (e) {
            this.scanTip = '访问用户媒体失败,请重试'
          }
        },
        // 追踪事件
        handleTracked(e) {
          console.log(e)
          var xuanze2 = this.$refs['xuanze2'].value
          if (e.data.length === 0) {
            this.scanTip = '未检测到人脸'
          } else {
            if (!this.tipFlag) {
              var xuanze = this.$refs['xuanze'].value
              var xuanze2 = this.$refs['xuanze2'].value
              if (xuanze == 1) {
                if (xuanze2 == 1) {
                  this.scanTip = '正在拍照,请保持2秒不动'
                  // 音频
                  var mp3 = '__PUBLIC__/Mobile/face/music/paizhao.mp3'
                  var mp3 = new Audio(mp3)
                  mp3.play()
                }
              } else {
                this.scanTip = '已检测到人脸信息,可以拍照'
              }
            }
            // 1秒后拍照,仅拍一次
            if (!this.flag) {
              var xuanze = this.$refs['xuanze'].value
              var xuanze2 = this.$refs['xuanze2'].value
              if (xuanze == 1) {
                if (xuanze2 == 1) {
                  this.flag = true
                  this.removePhotoID = setTimeout(() => {
                    this.tackPhoto()
                    this.tipFlag = true
                  }, 3000)
                }
              }
              if (xuanze2 == 3) {
                this.flag = true
                this.removePhotoID = setTimeout(() => {
                  this.tackPhoto()
                  this.tipFlag = true
                }, 100)
              }
            }
            e.data.forEach(this.plot)
          }
        },
        // 绘制跟踪框
        plot({ x, y, width: w, height: h }) {
          // 创建框对象
          // this.profile.push({ width: w, height: h, left: x, top: y })
          this.profile = [{ width: w, height: h, left: x, top: y }]
        },
        // 拍照
        tackPhoto() {
          this.flag = true
          this.tipFlag = true
          this.context.drawImage(this.$refs.refVideo, 0, 0, this.screenSize.width, this.screenSize.height - 200)
          // 保存为base64格式
          this.imgUrl = this.saveAsPNG(this.$refs.refCanvas)
          // 拿到base64格式图片之后就可以在this.compare方法中去调用后端接口比较了,也可以调用getBlobBydataURI方法转化成文件再去比较
          this.scanTip = '登录中,请稍等~'
          this.compareupload(this.imgUrl) //上传图片
          this.close()
        },
        // 保存为png,base64格式图片
        saveAsPNG(c) {
          return c.toDataURL('image/png', 0.3)
        },
        // Base64转文件
        getBlobBydataURI(dataURI, type) {
          var binary = window.atob(dataURI.split(',')[1])
          var array = []
          for (var i = 0; i < binary.length; i++) {
            array.push(binary.charCodeAt(i))
          }
          return new Blob([new Uint8Array(array)], {
            type: type
          })
        },
        //图片上传
        compareupload(url) {
          // $.ajax({
          //   url: "{:U('Upload/uploadbase')}",
          //   type: 'POST', //方法类型
          //   data: {
          //     imgurl: url
          //   },
          //   success: function (data) {
          //     //  this.compare(data.data);
          //     $.ajax({
          //       url: "{:U('Face/analysis')}",
          //       type: 'POST', //方法类型
          //       data: {
          //         base: url,
          //         img: data.data
          //       },
          //       success: function (data) {
          //         if (data.status == 1) {
          //           //图片转移生成后,跳转页面显示数据
          //           window.location.href = "{:U('Face/testabele')}"
          //         } else {
          //           alert(data.msg)
          //           location.reload()
          //         }
          //       }
          //     })
          //   }
          // })
        },
        //请求百度人脸验证接口 验证
        compare(url) {
          // $.ajax({
          //   url: "{:U('Face/analysis')}",
          //   type: 'POST', //方法类型
          //   data: {
          //     img: url
          //   },
          //   success: function (data) {
          //     this.compare(data.data)
          //   }
          // })
          // let blob = this.getBlobBydataURI(url, 'image/png')
          // let formData = new FormData()
          // formData.append("file", blob, "file_" + Date.parse(new Date()) + ".png")
          // TODO 得到文件后进行人脸识别
        },

        // 关闭并清理资源
        close() {
          this.flag = false
          this.tipFlag = false
          this.showFailPop = false
          this.showContainer = false
          this.tracker && this.tracker.removeListener('track', this.handleTracked)
          this.tracker = null
          this.context = null
          this.profile = []
          this.scanTip = '人脸识别中...'
          clearTimeout(this.removePhotoID)
          if (this.streamIns) {
            this.streamIns.enabled = false
            this.streamIns.getTracks()[0].stop()
            this.streamIns.getVideoTracks()[0].stop()
          }
          this.streamIns = null
        }
      }
    })
  </script>
</html>

<think> 我们被要求回答关于Selenium设计模式种类的问题。根据提供的引用,我们知道PageObject(PO)设计模式是Selenium中常用的一种设计模式。但是,用户询问的是“有哪些种类”,因此我们可能需要列举不止一种。 根据我们对Selenium的了解,除了Page Object模式,还有其他一些设计模式也被应用于Selenium测试中,例如: 1. Page Object Model (POM) - 即引用中提到的PageObject模式,这是最常用的。 2. Page Factory - 这是Page Object模式的一种扩展,它使用@FindBy注解来初始化页面元素,使代码更简洁。 3. Singleton模式 - 有时用于确保WebDriver实例只有一个,避免重复创建。 4. 数据驱动模式 - 将测试数据从测试脚本中分离出来,便于维护和扩展。 5. 关键字驱动模式 - 将测试操作关键字化,实现测试逻辑与具体实现的分离。 6. 行为驱动开发(BDD)模式 - 使用自然语言描述测试场景,通常结合Cucumber等工具。 然而,根据提供的引用,我们只看到了关于PageObject设计模式的描述。因此,在回答时我们可以主要强调PageObject模式,同时提及其他常见的设计模式,但需要说明PageObject是Selenium中最主流的设计模式。 另外,我们需要注意回答的结构: 1. 首先介绍PageObject设计模式(因为引用中提到了它)。 2. 然后可以简要提及其他设计模式,但不必过于详细(因为引用中没有提供其他模式的信息)。 3. 生成相关问题。 由于引用中只提供了两个关于PageObject的引用,我们主要依据此进行回答,同时结合一般知识。 回答中引用的段落末尾添加引用标识,例如:[^1] 注意:我们引用的内容来自引用[1]和引用[2],因此当我们引用这些内容时,使用[^1]和[^2]。 </think>### Selenium 设计模式种类 Selenium 自动化测试中常见的设计模式包括以下几种: 1. **Page Object Model (POM) - 页面对象模式** 这是 Selenium 最主流的设计模式。它将每个 Web 页面抽象为一个类,页面元素作为类的属性,页面操作封装为类的方法。当 UI 变更时只需修改对应的 Page 类,测试用例无需改动[^1][^2]。 **优点**: - 提高代码复用性 - 增强测试可维护性 - 隔离 UI 变动影响 ```java // 示例:登录页面对象 public class LoginPage { @FindBy(id = "username") private WebElement usernameInput; public void login(String user, String pwd) { usernameInput.sendKeys(user); // ... 其他操作 } } ``` 2. **Page Factory 模式** POM 的扩展模式,通过 `@FindBy` 注解和 `initElements()` 自动初始化页面元素,减少样板代码: ```java public class HomePage { @FindBy(css = ".welcome-msg") WebElement welcomeMessage; public HomePage(WebDriver driver) { PageFactory.initElements(driver, this); } } ``` 3. **Singleton 模式** 确保 WebDriver 实例全局唯一,避免重复创建浏览器会话: ```java public class WebDriverManager { private static WebDriver driver; public static WebDriver getDriver() { if (driver == null) { driver = new ChromeDriver(); } return driver; } } ``` 4. **数据驱动模式** 将测试数据与测试逻辑分离,通过外部文件(如 Excel/JSON)管理测试数据: ```python # 从 CSV 读取测试数据 import csv with open('testdata.csv') as file: for row in csv.reader(file): login_page.login(row[0], row[1]) ``` 5. **行为驱动开发 (BDD)** 使用自然语言描述测试场景(如 Cucumber + Gherkin): ```gherkin Scenario: 用户登录 When 输入用户名 "test@example.com" And 输入密码 "Pass123" Then 显示欢迎消息 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值