Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >模仿淘宝web扫码登录

模仿淘宝web扫码登录

作者头像
用户6182664
发布于 2019-09-10 07:29:18
发布于 2019-09-10 07:29:18
1.5K0
举报

#### 首页登录:

点击右上角二维码登录切换,触发js事件。

```

//切换登录

$('#J-qrcode-target').click(function(e){

e.preventDefault();

$(this).toggleClass("scan-no");

if ($(this).hasClass('qrcode-target-show')){

$(this).removeClass('qrcode-target-show').addClass('qrcode-target-hide');

$('.scan-login').show();

$('.input-login').hide();

_this.ST && clearInterval(_this.ST);

createQRcode();

$('.j_qr_invalid').hide();

} else {

$(this).removeClass('qrcode-target-hide').addClass('qrcode-target-show');

$('.scan-login').hide();

$('.input-login').show();

_this.ST && clearInterval(_this.ST);

}

});

```

切换样式,进入扫码登录页。

请求服务端接口,获取唯一二维码code,UUID。

```

//生成

var createQRcode = function(){

$.ajax({

type : "GET",

url : ctx + "/login/do_generate_qrcode.htm",

dataType : "json",

data:{},

beforeSend:function(){

},

success : function(json) {

if (json.success) {

_this.uuid = json.datas.obj;

$('#qrcode_output').empty();

try{

$('#qrcode_output').qrcode({width:160,height:160,text:_this.uuid});

}catch(e){

$('#qrcode_output').qrcode({render : "table",width:160,height:160,text:_this.uuid});

}

scanTrace();

} else {

Utils.Notice.error(json.message);

}

},

complete:function(){

}

});

```

服务端会随机生成UUID唯一码,并将空的二维码扫描信息存入缓存。缓存设置有效期为固定的两分钟,两分钟内为扫描,该缓存会定时清空。随后,将UUID串返回给前端。

```

/**

* 二维码内容生成

*/

@ResponseBody

@RequestMapping("do_generate_qrcode")

@UrlName("用户-[登录]二维码内容生成")

public JsonResult doGenerateQRCode(){

JsonResult json = new JsonResult();

String uuid = UUID.randomUUID().toString().replace("-", "") + "_"

+System.currentTimeMillis();

CacheUtils.set(UserCst.LOGIN_QRCODE_PREFIX + uuid,

UserCst.LOGIN_QRCODE_TIMEOUT, new ScanLoginDTO());

json.addDatas(ControllerCst.JSON_KEY_OBJ, uuid);

return json;

}

```

返回给前端会显示为UUID对应的二维码:

```

//扫描跟踪

var scanTrace = function(){

_this.ST = setInterval(function(){

$.ajax({

type : "POST",

url : ctx + "/login/do_qrcode_check.htm",

dataType : "json",

data:{uuid:_this.uuid},

beforeSend:function(){

},

success : function(json) {

//扫描状态 1-未扫描 2-已扫描,待确认 3-确认登录 4-取消登录

if (json.code == '2') {

$('.j_cf_tips').show();

$('.j_scan_tips').hide();

} else if (json.code == '3') {

_this.ST && clearInterval(_this.ST);

location.href = json.datas.obj;

} else if (json.code == '4' || json.code == '105') {

$('.j_qr_invalid').show();

_this.ST && clearInterval(_this.ST);

}

},

complete:function(){

}

});

},2000);

}

```

调用生成二维码的服务时,会同步调用扫描跟踪方法。该方法会定时,每两秒请求一下服务端的do_qrcode_check方法,校验扫描状态。当未扫描时,服务端缓存失效后会返回给前端,告知该二维码已失效。

```

/**

* 二维码扫描连接检查

*/

@ResponseBody

@RequestMapping("do_qrcode_check")

@UrlName("用户-[登录]二维码扫描连接检查")

public JsonResult doQRcodeCheck(@RequestParam("uuid")String uuid, HttpServletRequest request, HttpServletResponse response){

JsonResult json = new JsonResult();

if (StringUtils.isEmpty(uuid)){

json.setSysErr();

return json;

}

String key = UserCst.LOGIN_QRCODE_PREFIX + uuid;

ScanLoginDTO scanLoginDTO = CacheUtils.get(key);

if (scanLoginDTO == null){

json.setErr(UserErrs.User.SCAN_LOGIN_QR_INVALID);

return json;

}

if (scanLoginDTO.isScanLoginOK()){

SessionUserDTO session = userCheck.getUserByLoginName(scanLoginDTO.getLoginName());

if (session == null) {

json.setErr(UserErrs.User.SCAN_LOGIN_QR_INVALID);

return null;

}

String[] ticket = TicketUtils.getTicket(String.valueOf(session.getUserId()),true);

session.setToken(ticket[0]);

//刷新session

SessionManager.createSession(session.getUserId(), SessionCst.SESSION_ATTRIBUTE_USER_POJO, session);

LoginPostProcessor.addCookiesForTicket(request, response, ticket[1]);

LoginPostProcessor.addCookiesForNick(request, response, session.getNick());

String redirectUrl = WebUtils.getRoleUrl(String.valueOf(session.getRoleId()));

json.addDatas(ControllerCst.JSON_KEY_OBJ, redirectUrl);

} else if (scanLoginDTO.isCanLoginCancel()) {

CacheUtils.delete(key);

}

json.setCode(String.valueOf(scanLoginDTO.getStatus()));

return json;

}

```

服务端将扫描状态返回,告知前端该二维码使用扫描状态,当缓存到期后,会告知前端二维码已失效。

当用户在有效期内,扫描二维码时,会请求服务端接口。调用scan_request方法,将获取到的uuid,以及移动端自己的当前登录用户的loginName以及登录后的ticket传递给服务端进行记录。

```

/**

* 扫描登录请求

*

*/

@ResponseForMobile

@RequestMapping("scan_request")

@UrlName("用户-[手机登录接口]扫描登录请求")

public JsonResult scanRequest(@RequestParam(value = ControllerCst.DATA) String data) {

JsonResult json = new JsonResult();

APIParamModel<ScanLoginDTO> mode = _parse(data, new TypeReference<APIParamModel<ScanLoginDTO>>() {});

ScanLoginDTO scanLoginDTO = mode.getP();

_check(scanLoginDTO.getUuid(), "uuid");

_check(scanLoginDTO.getLoginName(), "loginName");

_check(scanLoginDTO.getTicket(), "ticket");

SessionUserDTO session = UserContext.user.get();

String key = UserCst.LOGIN_QRCODE_PREFIX + scanLoginDTO.getUuid();

ScanLoginDTO cacheScanLoginDTO = CacheUtils.get(key);

if (cacheScanLoginDTO == null || cacheScanLoginDTO.isCanLoginCancel()){

json.setErr(UserErrs.User.SCAN_LOGIN_QR_INVALID);

return json;

}

if (cacheScanLoginDTO.isScanWaitConfirm() || cacheScanLoginDTO.isScanLoginOK()) {

if (!cacheScanLoginDTO.getLoginName().equals(session.getLoginName())) {

json.setErr(UserErrs.User.SCAN_LOGIN_QR_INVALID);

return json;

}

}

CacheUtils.set(key, scanLoginDTO);

return json;

}

```

服务端会判断缓存中是否存在该UUID对应的缓存,并且确认状态是否是未确认,是否在可确认状态。校验后,会将信息放置缓存,等待用户发出确认登录请求。

当用户点击确认登录时,会给服务端发送确认登录请求。

```

/**

* 确认登录请求

*/

@ResponseForMobile

@RequestMapping("scan_confirm")

@UrlName("用户-[手机登录接口]确认登录请求")

public JsonResult scanConfirm(@RequestParam(value = ControllerCst.DATA) String data) {

JsonResult json = new JsonResult();

APIParamModel<ScanLoginDTO> mode = _parse(data, new TypeReference<APIParamModel<ScanLoginDTO>>() {});

ScanLoginDTO scanLoginDTO = mode.getP();

_check(scanLoginDTO.getUuid(), "uuid");

_check(scanLoginDTO.getStatus(), "status");

_check(scanLoginDTO.getLoginName(), "loginName");

_check(scanLoginDTO.getTicket(), "ticket");

SessionUserDTO session = UserContext.user.get();

String key = UserCst.LOGIN_QRCODE_PREFIX + scanLoginDTO.getUuid();

ScanLoginDTO cacheScanLoginDTO = CacheUtils.get(key);

if (cacheScanLoginDTO == null || cacheScanLoginDTO.isCanLoginCancel()){

json.setErr(UserErrs.User.SCAN_LOGIN_QR_INVALID);

return json;

}

if (cacheScanLoginDTO.isScanWaitConfirm() || cacheScanLoginDTO.isScanLoginOK()) {

if (!cacheScanLoginDTO.getLoginName().equals(session.getLoginName())) {

json.setErr(UserErrs.User.SCAN_LOGIN_QR_INVALID);

return json;

}

}

CacheUtils.set(key, scanLoginDTO);

return json;

}

```

服务端会根据用户发送的参数,校验二维码登录缓存是否存在,以及校验移动端当前session中的登录名是否与传递的登录名参数是否一致,避免移动端恶意攻击,违规登录别人的账号。一切确认好以后,将缓存中的uuid回应的扫码信息绑定至缓存中。

随后前端定时每两秒会请求的js会发送请求,确认用户登录的状态。

```

//扫描跟踪

var scanTrace = function(){

_this.ST = setInterval(function(){

$.ajax({

type : "POST",

url : ctx + "/login/do_qrcode_check.htm",

dataType : "json",

data:{uuid:_this.uuid},

beforeSend:function(){

},

success : function(json) {

//扫描状态 1-未扫描 2-已扫描,待确认 3-确认登录 4-取消登录

if (json.code == '2') {

$('.j_cf_tips').show();

$('.j_scan_tips').hide();

} else if (json.code == '3') {

_this.ST && clearInterval(_this.ST);

location.href = json.datas.obj;

} else if (json.code == '4' || json.code == '105') {

$('.j_qr_invalid').show();

_this.ST && clearInterval(_this.ST);

}

},

complete:function(){

}

});

},2000);

}

```

服务端执行连接检查接口,当登录状态完成正常以后,会获取用户登录信息ticket,设置token,以及为用户创建session.根据用户session中的roleID,返回用户登录成功后应该跳转的页面。

```

/**

* 二维码扫描连接检查

*/

@ResponseBody

@RequestMapping("do_qrcode_check")

@UrlName("用户-[登录]二维码扫描连接检查")

public JsonResult doQRcodeCheck(@RequestParam("uuid")String uuid, HttpServletRequest request, HttpServletResponse response){

JsonResult json = new JsonResult();

if (StringUtils.isEmpty(uuid)){

json.setSysErr();

return json;

}

String key = UserCst.LOGIN_QRCODE_PREFIX + uuid;

ScanLoginDTO scanLoginDTO = CacheUtils.get(key);

if (scanLoginDTO == null){

json.setErr(UserErrs.User.SCAN_LOGIN_QR_INVALID);

return json;

}

if (scanLoginDTO.isScanLoginOK()){

SessionUserDTO session = userCheck.getUserByLoginName(scanLoginDTO.getLoginName());

if (session == null) {

json.setErr(UserErrs.User.SCAN_LOGIN_QR_INVALID);

return null;

}

String[] ticket = TicketUtils.getTicket(String.valueOf(session.getUserId()),true);

session.setToken(ticket[0]);

//刷新session

SessionManager.createSession(session.getUserId(), SessionCst.SESSION_ATTRIBUTE_USER_POJO, session);

LoginPostProcessor.addCookiesForTicket(request, response, ticket[1]);

LoginPostProcessor.addCookiesForNick(request, response, session.getNick());

String redirectUrl = WebUtils.getRoleUrl(String.valueOf(session.getRoleId()));

json.addDatas(ControllerCst.JSON_KEY_OBJ, redirectUrl);

} else if (scanLoginDTO.isCanLoginCancel()) {

CacheUtils.delete(key);

}

json.setCode(String.valueOf(scanLoginDTO.getStatus()));

return json;

}

```

密码显示与隐藏:

//显示密码

```

$("#eye").click(function(e){

e.preventDefault();

var type = $(this).siblings("input").get(0).getAttribute("type");

var pwd = $(this).siblings("input").get(0)

if(type == "password"){

$("#eye span").removeClass("focuse").addClass("focus-out");

pwd.setAttribute("type","text")

}else{

$("#eye span").removeClass("focus-out").addClass("focuse")

pwd.setAttribute("type","password")

}

});

```

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-09-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Java程序员那些事 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
阿里面试官:分别说说微信和淘宝扫码登录背后的实现原理?
扫码登录这个功能,最早应该是微信的PC端开始搞,虽然有点反人类的功能(不扫码也没别的方式登录),但不得不说还是很酷的。
乔戈里
2020/02/25
2.6K0
徒手撸一个扫码登录示例工程
不知道是不是微信的原因,现在出现扫码登录的场景越来越多了,作为一个有追求、有理想新四好码农,当然得紧跟时代的潮流,得徒手撸一个以儆效尤
一灰灰blog
2020/04/24
6251
徒手撸一个扫码登录示例工程
网站提示用微信扫码登录,他们是怎么实现的?
作为一个技术码农,在使用社区、论坛或者各类AI服务的时,经常会看到这样一个提示:“使用微信公众号扫码登录”。那因为这种的登录方式除了登录,还可以让用户沉淀到公众号上,以后还能接收到公众号推广,可谓是一举两得。那它是怎么做的呢?🤔
小傅哥
2024/02/26
4.6K0
网站提示用微信扫码登录,他们是怎么实现的?
扫码登录技术原理
首先用户打开网站的登录页面的时候,向浏览器的服务器发送获取登录二维码的请求。服务器收到请求后,随机生成一个uuid,将这个id作为key值存入redis服务器,同时设置一个过期时间,再过期后,用户登录二维码需要进行刷新重新获取。
2020/02/12
5K0
扫码登录的实现方案
开发工具:MacOS、IDEA 技术栈:JDK1.8、SpringBoot、Thymeleaf、websocket、ZXing、jjwt
每天学Java
2020/06/02
2K0
知乎登陆[通俗易懂]
因为学年综合实践准备的一部分需要爬取知乎全站,所以为了方便,自动登陆是很有必要的。而由于许多学习爬虫的各友,都爱拿知乎练手——其实我倒非然,这算是第一次对知乎“开战”,是客观因素导致的必然——以至于知乎加强了反扒机制
全栈程序员站长
2022/09/20
1.8K0
知乎登陆[通俗易懂]
Python爬虫之模拟登录wechat
不知何时,微信已经成为我们不可缺少的一部分了,我们的社交圈、关注的新闻或是公众号、还有个人信息或是隐私都被绑定在了一起。既然它这么重要,如果我们可以利用爬虫模拟登录,是不是就意味着我们可以获取这些信息,甚至可以根据需要来对它们进行有效的查看和管理。是的,没错,这完全可以。本篇博主将会给大家分享一下如何模拟登录网页版的微信,并展示模拟登录后获取的好友列表信息。
Python数据科学
2018/08/06
10.6K1
Python爬虫之模拟登录wechat
如果使用 Python3(Flask)
我们可以看到产生二维码的图片的URL为https://login.weixin.qq.com/qrcode/wbO9FUkKHg==,但是需要后面的一个参数wbO9FUkKHg==,这个随机码是怎么产生的呢,我们再继续寻找。
py3study
2020/01/06
5410
微信扫码登录网站实现案例(无需授权)
最近因业务需要,需要给网站增加一个扫描公众号二维码登录网站的功能,通过扫码登录,一来用户登录网站不需再输入账号密码,提升了用户体验,二来也可以作为公众号吸粉的一个渠道。
小诸葛
2020/04/14
2.6K1
微信扫码登录网站实现案例(无需授权)
微信公众号开发之推广支持
前几篇文章详细介绍了微信App支付、公众号支付、微信红包、微信刷卡以及支付宝支付,今天来聊聊 推广支持之生成带参数的二维码、长链接转短链接
Javen
2018/08/21
2.2K0
微信公众号开发之推广支持
golang实现微信聊天机器人
▪ 获取UUID ▪ 根据UUID获取二维码 ▪ 显示二维码 ▪ 扫码登陆 ▪ 初始化微信信息 ▪ 打开状态同步通知 ▪ 获取通讯录 ▪ 发送信息 ▪ 同步信息 ▪ 获取自动回复内容
李海彬
2018/07/26
4K0
golang实现微信聊天机器人
【Redis版】spring boot高性能实现二维码扫码登录(中)
  本打算用CountDownLatch来实现,但有个问题我没有考虑,就是当用户APP没有扫二维码的时候,线程会阻塞5分钟,这反而造成性能的下降。好吧,现在回归传统方式:前端ajax每隔1秒或2秒发一次请求,去查询后端的登录状态。
BUG弄潮儿
2020/06/15
7930
【Redis版】spring boot高性能实现二维码扫码登录(中)
基于若依框架扩展微信扫码登录功能-扫码登录实现
PC 端点击微信登录时生成一个 uuid 存入 redis 并弹出一个二维码,二维码地址(附带了生成的 uuid)是移动端的网页,微信扫码后打开的是配置好的网页授权链接,通过网页授权的方式获取 code 拿到用户 openid 后存入redis中,PC 端通过轮询方式根据生成的 uuid 查询用户 openid 进行登录。
薛定喵君
2024/10/07
1.4K0
App扫码登录Web端功能实现
后端通过下载页面URL与随机生成的UUID拼接成一个字符串,利用hutool工具包的生成二维码方法生成一个二维码。
用户8889406
2023/03/05
1.5K0
App扫码登录Web端功能实现
Unity & 微信公众号 - 实现扫码关注登录
功能需求:登录时呈现公众号二维码,用户扫描二维码后,点击关注,事件响应给程序,实现登录,若已经关注,自动进入会话,事件同样响应给程序,实现登录。
CoderZ
2022/08/29
3K0
Unity & 微信公众号 - 实现扫码关注登录
当面试官突然提到第三方登录时,我不禁微笑了~ 探秘WeChat公众号扫码关注登录!
当面试官突然提到第三方登录时,我不禁微笑了~ 探秘WeChat公众号扫码关注登录!,来整一个.
杨不易呀
2023/09/19
9220
当面试官突然提到第三方登录时,我不禁微笑了~ 探秘WeChat公众号扫码关注登录!
二维码劫持原理及恶意行为分析
之前看过其他的二维码登陆劫持漏洞,有的地方写的不是很详细,花了不少时间去研究二维码的原理,才弄懂漏洞。为了照顾更多入门新手,以本人的理解重新总结一遍,二维码登陆原理不是这里的主题,不过有必要熟悉一下流程。
FB客服
2019/05/15
2.5K0
二维码劫持原理及恶意行为分析
Spring学习笔记(二十三)——实现网站微信扫码登录获取微信用户信息Demo
微信扫码登录是指微信OAuth3.0授权登录让微信用户使用微信身份安全登录第三方应用或网站,在微信用户授权登录已接入微信OAuth3.0的第三方应用后,第三方可以获取到用户的接口调用凭证(access_token),通过access_token可以进行微信开放平台授权关系接口调用,从而可实现获取微信用户基本开放信息和帮助用户实现基础开放功能等。
不愿意做鱼的小鲸鱼
2022/09/26
2.5K0
Spring学习笔记(二十三)——实现网站微信扫码登录获取微信用户信息Demo
【单服务器版】spring boot高性能实现二维码扫码登录(上)
  目前网页的主流登录方式是通过手机扫码二维码登录。我看了网上很多关于扫码登录博客后,发现基本思路大致是:打开网页,生成uuid,然后长连接请求后端并等待登录认证相应结果,而后端每个几百毫秒会循环查询数据库或redis,当查询到登录信息后则响应长连接的请求。
BUG弄潮儿
2020/06/15
2.5K0
【单服务器版】spring boot高性能实现二维码扫码登录(上)
微信公众平台开发教程(六)获取个性二维码
在进行推广时,我们可以告诉对方,我们的微信公众账号是什么,客户可以去搜索,然后关注。二维码给我们提供了极大的便捷,只要简单一扫描,即可关注。
Java架构师必看
2021/05/19
5650
推荐阅读
相关推荐
阿里面试官:分别说说微信和淘宝扫码登录背后的实现原理?
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档