草庐IT

前端面试问题:扫码登录原理详解

刷题刷到手抽筋 2023-04-03 原文

一、简介

从登录的交互形式角度,登录有很多方式:账号密码登录、验证码登录、手机号一键登录、扫码登录等等。

今天我们聊一聊扫码登录的原理。

先来看两个扫码登录的场景:

1. 手机已经登录知乎,如果我们想在PC网页登录,可以使用知乎移动端扫码登录。

2. 使用微信扫码登录PC网页ProcessOn (这是一个免费作图的网站)。

从账号体系角度,这是扫码登录的两种方式:自有账户登录登录和第三方登录

我们在面试中问“请讲一讲扫码登录的原理”,通常指的是自有账户登录;而在实际业务开发中,基于微信的第三方登录是很常见的一个需求。

下面我们讨论这两种扫码登录如何实现。

二、自有账户扫码登录

前置条件: 用户手机已经登录账号(如知乎),因此有完备的用户信息。

整个登录过程中,一个关键的、串联整个过程的参数是“key”(或者叫场景id),后端、PC、移动端都是通过这个key关联到相应的信息,从而串联起整个登录过程。

扫码登录过程:

  1. 用户访问登录页面,前端向后端请求登录的二维码和key,这个key用来索引用户登录状态。
  2. 服务端生成二维码,并将key(假设是"123")保存(本地或redis),然后将二维码和参数返给前端,这里可以后端生成二维码并上传到OSS,然后返回给前端二维码的地址;也可以直接返回给前端字符串,前端自己去生成二维码:https://www.npmjs.com/package/qrcodejs
  3. 前端获取到key="123"和二维码后,就使用key开始轮询登录状态,等待用户扫码登录。(这里的轮询可以用websocket长连接代替)。
  4. 用户手机已经扫码后,移动端跳转到授权登录页(携带参数key=“123”)。
  5. 用户点击登录后,前端调用后端接口,通知后端:“"123"对应的用户是我,我已经授权PC网页登录了,我的用户信息是:XXXXX”。
  6. 后端找到"123"对应的信息,更新用户登录状态为true,并更新用户信息。前端轮询再发轮询时候,后端发现状态改变,则返回给前端登录成功,并返回登录的用户信息。
  7. 前端收到登录成功的返回,就更新登录状态,展示用户信息,停止轮询。

注意:

这里的授权登录页只是实现移动端和服务端通信的一种方式,也可以用其他方式实现通信:二维码中只包含key信息,移动客户端扫码后解析出key值,然后通过一个写死的地址来和服务端通信,这样灵活性稍差;或者二维码中包含key信息和服务端接口名,移动端扫码后通过这个接口来和服务端通信。

三、第三方扫码登录

1. 微信第三方登录介绍

以微信扫码登录为例。

很多业务方使用微信登录,利用微信账户体系快速搭建自己的用户体系。

微信支持网页授权( 官方开发文档 开放平台扫码登录官方开发文档)、公众平台扫码登录(涉及的主要接口有: 获取access_token 生成带参二维码 接收扫码事件

我们今天讨论公众平台扫码登录,下文的微信扫码登录特指公众号扫码登录

2. 微信公众号扫码登录

微信扫码登录和基本的扫码登录的原理基本类似,但是由于手机登录的是微信,而PC登录的是业务方,属于第三方登录,需要微信服务器和业务服务器通信,因此多了一些交互过程。

从业务角度,最大的区别是,使用微信账号登录,而不是业务方自己的账号登录。

从系统结构角度,最大的区别是,生成二维码和登录过程都是微信服务器完成,业务服务器从微信服务器获取到二维码、业务服务器从微信服务器接收到登录(扫码)的事件;另外,微信扫码登录时候,业务的用户体系是通过微信的用户信息建立的,因此还需要登录注册过程(登录注册过程,即,如果发现用户已经注册过,则返回登录成功,并返回用户信息,如果发现用户未注册过,则将用户信息保存(相当于注册操作),然后返回给用户登录成功 + 用户信息。简单描述为:已注册 ? 登录 : 注册 + 登录)。

和自有扫码登录类似,微信扫码登录前提是用户已经在手机端登录了微信。

另外业务服务器需要进行一系列的配置,才能和微信服务器进行通信。下面说明业务服务器需要进行哪些配置。

接入微信扫码登录的准备工作

接入微信主要就是要让业务服务器可以和微信服务器能够正常通信,但是微信服务器并不是随便可以通信的,需要进行配置,这样微信服务器才能认为和你的业务服务器通信是安全合法的。

通信主要有两个方面:一个是业务服务器请求微信服务器,另一个是微信服务器向业务服务器发送事件。

前者需要配置ip白名单,只有在白名单中的机器才会被微信服务器接收,否则都被认为是非法请求而拒绝。后者需要配置你的服务器地址,并进行验证,这样当有和你的公众号相关的事件发生,就会通过这个配置的服务器地址进行推送。

更具体地,需要做的准备工作有:

  1. 权限:认证的服务号,订阅号和未认证的服务号都没有获取带参二维码接口的权限,因此无法实现扫码登录。
  2. 开通微信公众号开发者(在微信公众号后台的基本配置中开启)
  3. 配置公众号服务地址并验证(在微信公众号后台的基本配置中配置并验证),这个地址也是后面接收扫码事件的。
  4. 配置公众号的ip白名单(serverless实例运行时候ip不固定,可以通过代理方式保证固定ip(例如阿里云文档给出的解决方案:https://help.aliyun.com/document_detail/91244.html),也可以把微信后端接口放在云服务器上)。
  5. 实现access_token刷新模块,调用微信的任何接口都需要access_token:获取access_token

微信扫码登录和自有账户扫码登录的区别

最关键的区别有两点:

  1. 业务服务器不是自己生成二维码,而是从微信服务器中获取带参二维码,然后给前端。
  2. 由于使用微信客户端扫码,业务服务器没法直接接收移动端的扫码事件,而是接收微信服务器发来的扫码事件。

简单地说,微信扫码登录过程的二维码生成和扫码都是在微信服务器,业务服务器只是做个中转工作,并记录事件信息用来进行登录。

微信公众号扫码登录步骤

微信扫码登录过程:

  1. 用户访问登录页面,前端向后端请求登录的二维码和key,这个key用来索引用户登录状态。
  2. 业务服务器向微信请求带参二维码(生成带参二维码),这个参数是自定义的(假设是"123"),微信中称为“场景值”。注意请求时候需要带上access_token。
  3. 业务服务端收到二维码,和“场景值”key=“123”,保存场景值后,一起返回给前端。
  4. 前端获取到key="123"和二维码后,就使用key开始轮询登录状态,等待用户扫码登录
  5. 用户手机使用扫码后,移动端跳转到二维码对应的地址(形式是:http://weixin.qq.com/q/02qRGxU8sRell1czRONycA),这个地址带有场景值信息:123。
  6. 微信客户端解析地址后会和微信服务器通信,告知微信服务器:“这个场景值123,我已经授权登录”。
  7. 如果用户已经关注公众号,微信会推送一个扫码事件给业务服务器,如果用户未关注公众号,会跳转到公众号详情,用户点击关注后,推送关注后的用户扫码事件给业务服务器。扫码事件文档:接收扫码事件
  8. 业务服务器收到事件时候,找到"123",根据用户信息走登录注册流程,然后更新用户登录状态为true,并更新用户信息。前端再发轮询时候,后端发现状态改变,则返回给前端登录成功,并返回登录的用户信息。
  9. 前端收到登录成功的返回,就更新登录状态,展示用户信息,停止轮询。

简而言之,业务服务器从微信服务器请求带参二维码,返回给PC网页,用户使用微信扫码后,如果用户已经关注过公众号,微信服务器会给业务服务器推送一个已关注的扫码事件,如果用户未关注公众号,扫码后会跳转到公众号详情页,用户点击关注后,微信服务器会给业务服务器推送一个关注后的用户扫码事件,这两种事件都会携带用户信息,业务服务器根据事件中的数据进行登录注册的业务逻辑。

四、总结

扫码登录实际上就是把移动端的登录状态同步到PC端,这个同步过程需要服务器进行校验和传递数据。扫码过程其实就是把PC的信息同步给移动端,从而能够让整个数据链路串联起来,如果PC展示一个url,移动端手动输入,也是可以实现的,但扫码的操作更便捷和安全。

有关前端面试问题:扫码登录原理详解的更多相关文章

  1. ruby - 使用 Ruby 和 Mechanize 登录网站 - 2

    我需要从站点抓取数据,但它需要我先登录。我一直在使用hpricot成功地抓取其他网站,但我是使用mechanize的新手,我真的对如何使用它感到困惑。我看到这个例子经常被引用:require'rubygems'require'mechanize'a=Mechanize.newa.get('http://rubyforge.org/')do|page|#Clicktheloginlinklogin_page=a.click(page.link_with(:text=>/LogIn/))#Submittheloginformmy_page=login_page.form_with(:act

  2. 物联网MQTT协议详解 - 2

    一、什么是MQTT协议MessageQueuingTelemetryTransport:消息队列遥测传输协议。是一种基于客户端-服务端的发布/订阅模式。与HTTP一样,基于TCP/IP协议之上的通讯协议,提供有序、无损、双向连接,由IBM(蓝色巨人)发布。原理:(1)MQTT协议身份和消息格式有三种身份:发布者(Publish)、代理(Broker)(服务器)、订阅者(Subscribe)。其中,消息的发布者和订阅者都是客户端,消息代理是服务器,消息发布者可以同时是订阅者。MQTT传输的消息分为:主题(Topic)和负载(payload)两部分Topic,可以理解为消息的类型,订阅者订阅(Su

  3. Tcl脚本入门笔记详解(一) - 2

    TCL脚本语言简介•TCL(ToolCommandLanguage)是一种解释执行的脚本语言(ScriptingLanguage),它提供了通用的编程能力:支持变量、过程和控制结构;同时TCL还拥有一个功能强大的固有的核心命令集。TCL经常被用于快速原型开发,脚本编程,GUI和测试等方面。•实际上包含了两个部分:一个语言和一个库。首先,Tcl是一种简单的脚本语言,主要使用于发布命令给一些互交程序如文本编辑器、调试器和shell。由于TCL的解释器是用C\C++语言的过程库实现的,因此在某种意义上我们又可以把TCL看作C库,这个库中有丰富的用于扩展TCL命令的C\C++过程和函数,所以,Tcl是

  4. ruby-on-rails - 使用用户或管理员模型和 Basecamp 样式子域设计登录 - 2

    我为Devise用户和管理员提供了不同的模型。我也在使用Basecamp风格的子域。除了我需要能够以用户或管理员身份进行身份验证的一些Controller和操作外,一切都运行良好。目前我有authenticate_user!在我的application_controller.rb中设置,对于那些只有管理员才能访问的Controller和操作,我使用skip_before_filter跳过它。不幸的是,我不能简单地指定每个Controller的身份验证要求,因为我仍然需要一些Controller和操作才能被用户或管理员访问。我尝试了一些方法都无济于事。看来,如果我移动authentica

  5. ruby - 如何使用 omniauth/oauth 对每秒登录数进行基准测试? ( ruby +rspec) - 2

    我想用一个(自己的)omniauth提供商来衡量每秒可以登录多少次。我需要了解此omniauth/oauth请求的性能如何,以及此身份验证是否具有可扩展性?到目前为止我得到了什么:defperformance_auth(user_count=10)bm=Benchmark.realtimedouser_count.timesdo|n|forkdoclick_on'Logout'omniauth_config_mock(:provider=>"foo",:uid=>n,:email=>"foo#{n}@example.net")visit"/account/auth/foo/"enden

  6. ruby - 如何使用 Ruby 和 eventmachine 登录? - 2

    我正在使用Ruby和Eventmachine库编写一个应用程序。我真的很喜欢非阻塞I/O和事件驱动系统的想法,我遇到的问题是日志记录。我正在使用Ruby的标准记录器库。并不是说日志记录需要永远,但它似乎不应该阻塞,但它确实阻塞了。是否有某个库将Ruby的标准记录器实现扩展为非阻塞的,或者我应该只调用EM::defer进行日志记录调用?有没有办法让eventmachine已经为我做这件事? 最佳答案 我最终将记录器包装在一个启动线程并具有FIFO队列的单例类中。日志记录会将日志信息转储到队列中,线程只是循环,从队列中拉出内容并使用真正

  7. ruby-on-rails - 尝试登录和使用 heroku 时无法识别 ruby​​.exe - 2

    当尝试创建一个heroku应用程序并通过git推送到它时,我收到以下错误:$herokucreate'"C:\ProgramFiles\ruby-1.9.2\bin\ruby.exe"isnotrecognizedasaninternalorexternalcommand,operableprogramorbatchfile.但是,$ruby-vruby1.9.3p125[i386-mingw32]我已经检查了PATH环境,它肯定包含“C:\ProgramFiles(x86)\ruby-1.9.2\bin”。同样有趣的是,当导航到该目录时,它实际上并不包含名为ruby​​.exe的文件

  8. ruby-on-rails - 使用 Ruby on Rails 设计 - 强制用户在首次登录时更改密码 - 2

    我有一个运行Devise的RoR应用程序(Rails4.2、Ruby2.2.0)。我已对其进行设置,以便管理员用户(标识我添加到用户模型的“is_admin”bool值)能够创建新的用户帐户,为他们提供生成的密码和确认电子邮件。这一切都正常工作。我还添加了datetime列pass_changed,当用户更改密码时应该更新它,然后检查created_at以确保自帐户创建以来密码已更改。如果两个日期相同,则用户将被重定向到密码更改表单。我编写了一个程序来检查用户是否更改了密码并将其放在我的application_controller.rb中:defcheck_changed_pass@u

  9. ruby-on-rails - 如何使 ActiveRecord::Schema.define 不登录到标准输出? - 2

    我在文档中看不到这个,但我认为这是一个已解决的问题。我在Rails之外使用ActiveRecord,我的脚本加载了从另一个应用程序转储的schema.rb。我想加载此模式而不将迁移输出转储到标准输出,但替换ActiveRecord::Base.logger不会关闭它。我应该覆盖什么来阻止噪音? 最佳答案 技巧显然在ActiveRecord::Migration中:ActiveRecord::Migration.verbose=false这使得迁移不会将信息输出到$stdout。有一个名为.suppress_messages的便捷包装

  10. Win10 / 11新电脑最简单跳过联网激活和使用本地账户登录方法 - 2

    跳过联网激活:OOBE界面直接按Ctrl+Shift+F3进入审核模式。这样就可以直接进入系统进行一些硬件测试等,而不用联网激活导致新机无法退货。需要注意的是,在审核模式下进行的一些操作都会保留,并不会在退出后自动还原!安装的软件在正常开机进系统后还会看见!如果电脑确实没连互联网又不想强行跳过OOBE(网上很多教程会叫你直接结束OOBE进程,但这是不推荐的,因为一些厂商自带优化程序和系统初始化设置在后面都会应用,对于笔记本跳过的话你会发现驱动和内置应用都没有装上。其实这部分脚本就在系统盘的Recovery隐藏文件夹下),可以参考以下方式:https://www.landiannews.com/

随机推荐