国际惯例:先上图:

tip,用ssm做的后台。

具体思路:
1.准备一个bean(存放用户信息的类和记录是否同意登录的Boolean属性) 和 一个map,存放类型为bean(存放用户信息的类)
2.后台生成二维码信息 和 生成二维码信息的时间,返回给web端,便于前端生成二维码和记录其生成的时间 和记录二维码信息
3.后台写一个esauCode方法,供app端调用,当app端扫码把扫的二维码信息返回的后台,并用该信息作为map的key,创建一个key
4.后台写ifEsauCode方法,根据情况返回结果(0代表未扫码,1代表已经扫码,-1代表二维码信息过期),web端一直轮询该方法,判断用户是否扫码
(ps:ifEsauCode形参有二维码信息和其生成的时间,当app端扫码后,就用该信息作为key,放进map里,然后该方法判断是否存在该key,就知道是否扫码)
5.后台写makeSelection,供app调用,当用户允许或不允许登录后,就在刚才map对应的key值里的Boolean属性赋值,做是否同意登录。
6.当扫码后,web再来一个轮询调用后台写agreeOrNot方法,形参有二维码的信息,用该信息获取map对应key值,当该值里的Boolean属性为true时,说明同意登录,反之则反之。

下面为具体代码:

后台:

Step 1 :创建bean,存放用户信息的类和记录是否同意登录的Boolean属性

public class UserLoginVo implements Serializable{private static final long serialVersionUID = 1L;private Boolean agreeOrNot;    //记录用户是否同意登录private String userName;//记录用户名public Boolean getAgreeOrNot() {return agreeOrNot;}public void setAgreeOrNot(Boolean agreeOrNot) {this.agreeOrNot = agreeOrNot;}public String getUserName() {return userName;}public void setUserName(String userName) {this.userName = userName;}
}

还要一个bean,是记录二维码信息和其生成的时间,返回给web用的:

public class TokenVo implements Serializable{private static final long serialVersionUID = 1L;private String qrMessage;//二维码信息private String date;//生成时间public String getQrMessage() {return qrMessage;}public void setQrMessage(String qrMessage) {this.qrMessage = qrMessage;}public String getDate() {return date;}public void setDate(String date) {this.date = date;}}

Step 2 :声明一个map,记录用户是否扫码和是否同意登录:

private Map<String, UserLoginVo> userLoginMap=new HashMap<String, UserLoginVo>();

Step 3 :创建二维码信息,和其创建的时间

@ResponseBody@RequestMapping(value = "creatQRMessage",produces = "application/json;charset=UTF-8")public String creatQRMessage() {  //创建UUIDString uuid=UUID.randomUUID().toString().replace("-", "").toUpperCase();/*** Path.QR_SUBMIT:扫码后要提交地址(例如:"http://192.168.43.9:8080/CarTaketing/User/esauCode.do",即是要执行服务端的方法,* 这是为了方便app端扫码后是执行登录进而做自己需要的操作,若扫到其它地址,app端直接跳转到该地址)。* uuid:二维码唯一的标志符*/String qrMessage=Path.QR_SUBMIT+"?k="+uuid;//二维码信息,是一个带参数的地址//返回qrMessage 和 qrMessage 创建的时间给客户端String dateStr=String.valueOf(new Date().getTime());TokenVo tokenVo=new TokenVo();tokenVo.setQrMessage(qrMessage);tokenVo.setDate(dateStr);return JSON.toJSONString(tokenVo);}

Step 4 :web启动轮询不断执行该方法, 判断用户是否扫码,没有则返回 “0” ,扫了则返回 “1”,验证码过期了返回 "-1"

/*** 轮询 判断用户是否扫码,没有则返回 "0" ,扫了则返回 "1",验证码过期了返回 "-1"* @param qrMessage        二维码信息* @param dateStr  创建二维码信息的时间* @return*/@ResponseBody@RequestMapping(value = "ifEsauCode",produces = "application/json;charset=UTF-8")public String ifEsauCode(String qrMessage,String dateStr) {long newDate=new Date().getTime(); long date=Long.valueOf(dateStr);String result="0";if(userLoginMap.get(qrMessage)!=null) {//判断是否扫码result="1";}else if(newDate-date>=60000){//判断是否过期,过期将重新生成二维码result="-1";}return JSON.toJSONString(result);}

Step 5 :app端调用:userLoginMap添加键值对,标记该二维码已经被扫码(执行后,Step 4 就知道是否已经扫码了):

//app端调用:userLoginMap添加键值对,标记该二维码已经被扫码@ResponseBody@RequestMapping(value = "esauCode")public void esauCode(String k) {        if(k!=null) {userLoginMap.put(k, new UserLoginVo());}}

Step 6 :当扫码后,web启动轮询不断执行该方法,判断是否同意登录

/*** 判断是否同意登录* @return  返回1则同意登录,0为反之,-1则未做出选择*/@ResponseBody@RequestMapping(value = "agreeOrNot",produces = "application/json;charset=UTF-8")public String agreeOrNot(HttpServletRequest request,String qrMessage) {String result="-1";UserLoginVo uLoginVo=userLoginMap.get(qrMessage);if(uLoginVo!=null && uLoginVo.getAgreeOrNot()!=null) {if(uLoginVo.getAgreeOrNot()) {//说明app端已经同意登录User user=new User();user.setUsername(uLoginVo.getUserName());request.getSession().setAttribute("user", user);//保存用户     result = "1";}else {//不同意登录result = "0";}//清除qrMessage在userLoginMap里的信息userLoginMap.remove(qrMessage);}return JSON.toJSONString(result);}

Step 7 :app端点击同意或不同意登录后要执行

/**app端调用:* 是否同意web登录* @param request    * @param qrMessage     二维码信息* @param agreeOrNot   是否允许登录* @param user            用户信息* @return*/@ResponseBody@RequestMapping(value = "makeSelection",produces = "application/json;charset=UTF-8")public String makeSelection(String qrMessage,Boolean agreeOrNot,User user) {Message message = new Message(400,"信息异常");if(agreeOrNot!=null) {//同意登录if(agreeOrNot) {if(user!=null && userLoginMap.get(qrMessage) !=null) {//先判断app端传过来的信息是否对应User user2=iUserService.selectUserByKey(user.getUserid());if(user2.getPasord().equals(MD5Util.getMD5(user.getPasord()))) {//标记用户同意登录userLoginMap.get(qrMessage).setAgreeOrNot(true);userLoginMap.get(qrMessage).setUserName(user.getUsername());message=new Message(200,"已授权");}}//不同意}else {//标记用户不同意登录userLoginMap.get(qrMessage).setAgreeOrNot(false);message=new Message(200,"取消登录");}}return JSON.toJSONString(message);}

web端

Step 1 :引入生成二维码的插件:QRCode.js
GitHub地址

使用方法

Step 2 :body部分,有3个页面,分别为密码登录界面 和 二维码界面和 提醒用户同意登录界面(布局和样式根据自己的情况而定);
还有隐藏的存放 qrMessage 和 生成qrMessage的时间的 input 标签

     <!--  密码登录界面--><div id="loginByPassword" class="loginbox" style="margin:auto;background-color: #61abfd;height: 270px"><i class="loginheader">客&nbsp;&nbsp;运&nbsp;&nbsp;管&nbsp;&nbsp;理&nbsp;&nbsp;系&nbsp;&nbsp;统</i><ul style="margin:auto" id="dengLvUl"><li class="li1">账号:<input id="username" name="username" class="zhanghao" type="text" placeholder="请输入账号" value="${cookie.userName.value}" /></li><li class="li2">密码:<input id="pasord" name="pasord" class="mima" type="password" placeholder="请输入密码" value="${cookie.userPassword.value}" /></li><li class="li2">验证码:<input style="width: 130px;" name="code" id="code" id="yzm" type="text" class="mima" placeholder="请输入验证码" autocomplete="off" /><img id="img" style="width: 90px;margin-left: 72px" alt="" src="${ctx}/User/pict.do"><li/><li><input type="checkbox" id="isRememb" name="isRememb" style="margin-left: 20px">记住密码<button class="denglu" onclick="check()" style="margin-left: 50px" id="dengLv">登录</button><button id="erWeiMa" type="button" style="margin-left: 30px">二维码登录</button><li/></ul></div><!-- 二维码界面 --><div id="loginByCode" class="loginbox" style="margin:auto;background-color: #61abfd;height: 270px;display: none"><div style="margin-top: 10px"><!-- 存放二维码 --><div id="image" style="margin:auto;height: 200px;width:200px;"></div></div><div style="margin-top:10px;margin-left:140px"><button id="miMaDengLv" type="button" style="margin-left: 40px;display: inline">密码登录</button></div><!--存放 qrMessage 和 生成qrMessage的时间的 input 标签 --><input id="qrMessage" type="hidden"><input id="date" type="hidden"></div><!-- 提示用户确认登录界面 --><div id="sureLogin" class="loginbox" style="margin:auto;background-color: #61abfd;line-height: 200px;display: none"><p style="color:white;text-align:center" >手机请确认登录</p></div>

Step 3:script 标签 里的代码(javascript代码或js):

 //Step 1 :声明 二维码var qrcode=new QRCode(document.getElementById("image"), {width:200,height:200,colorDark:"#000000",//二维码颜色colorLight:"#ffffff",//二维码背景颜色correctLevel : QRCode.CorrectLevel.H//容错级别});//是否执行轮询(用来启动或停止轮询)var b=false;//Step 2 :点击二维码登录时,隐藏密码登录  显示扫码登录 并生成二维码$("#erWeiMa").click(function(){//隐藏密码登录显示扫码登录document.getElementById("loginByCode").style.display = "block";document.getElementById("loginByPassword").style.display = "none";//获取服务端的qrMessage 和 其生成的时间 存放好,并根据该qrMessage生成二维码$.post('${ctx}/User/creatQRMessage.do',function(data){//存放信息$("#qrMessage").val(data.qrMessage);$("#date").val(data.date);//生成二维码qrcode.makeCode(data.qrMessage);//启动轮询的方法b=true;checkQR();},"json");})//Step 3 :轮询,不断判断用户是否已经扫码function checkQR(){if(b){//true为启动轮询//获取信息var qrMessage=$("#qrMessage").val();var date=$("#date").val();//执行服务端的ifEsauCode方法,判断是否已经扫码或过期$.post('${ctx}/User/ifEsauCode.do?qrMessage='+qrMessage+"&dateStr="+date,function(data){if(data=="1"){//说明已经扫码//显示确认登录界面   隐藏扫码界面document.getElementById("sureLogin").style.display = "block";document.getElementById("loginByCode").style.display = "none";//新轮询  监听用户是否确认登录checkAgreeOrNot();           }else if(data=="-1"){//说明二维码过期,更新二维码//重新生成二维码$.post('${ctx}/User/creatQRMessage.do',function(data){//存放信息$("#qrMessage").val(data.qrMessage);$("#date").val(data.date);//生成二维码qrcode.makeCode(data.qrMessage);//启动轮询的方法checkQR();},"json");}else if(data=="0"){checkQR();}       },"json");}}//Step 4 :轮询 ,判断用户是否同意登录function checkAgreeOrNot(){var qrMessage=$("#qrMessage").val();//执行服务端agreeOrNot方法,判断是否同意登录$.post('${ctx}/User/agreeOrNot.do?qrMessage='+qrMessage,function(data){if(data=="1"){//同意登录//跳转到成功登录界面window.location.href ="${ctx}/User/toMain.do";  }else if(data=="0"){//取消登录//隐藏确认登录界面   显示扫码界面document.getElementById("loginByCode").style.display = "block";document.getElementById("sureLogin").style.display = "none";//重新启动判断是否扫码的轮询  监听是否扫码checkQR();}else if(data=="-1"){//用户为做出选择,继续轮询checkAgreeOrNot();}},"json");}//此处是点击密码登录,显示密码登录和隐藏验证码登录,不是重点$("#miMaDengLv").click(function(){document.getElementById("loginByCode").style.display = "none";document.getElementById("loginByPassword").style.display = "block";b=false;//停止轮询})

app端:

Step 1 :这里只从扫码得到的结果开始写,具体如何扫码,请看自己的扫码笔记 或 查看自己的博客 :
安卓扫码例子的地址

   @Overrideprotected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {//==扫码登录IntentResult result = IntentIntegrator.parseActivityResult(requestCode,resultCode,data);if(result!=null){//==是否扫到内容if (result.getContents()!=null){//处理扫码后要执行的方法(result.getContents()为扫到的内容)webLogin(result.getContents());}else{Toast.makeText(MainActivity.this,"取消扫码",Toast.LENGTH_LONG).show();}}else{super.onActivityResult(requestCode, resultCode, data);}

Step 2 :根据扫描的结果做相关的操作
(ps:OkHttpTool为发送网络请求的工具,具体使用请查看自己的笔记(OkHttp3 发送网络请求服务器)
或访问该地址:地址)

//执行服务端的扫码登录private void webLogin(String contents) {//扫码登录方法String url=ServiceUtil.getUserUrl("esauCode");//判断是否为自己的扫码登录方法,当二维码信息(即contents)包含url,就说明是执行扫码登录if(contents.contains(url)){//==为自己的扫码登录,告诉服务器已经扫到码了OkHttpTool.httpPost(url+"?k="+contents, null, new OkHttpTool.ResponseCallback() {@Overridepublic void onResponse(boolean isSuccess, int responseCode, String response, Exception exception) {MainActivity.this.runOnUiThread(new Runnable() {@Overridepublic void run() {if(isSuccess&&responseCode==200){//提示用户是否确认登录web端AlertDialog.Builder builder=new AlertDialog.Builder(MainActivity.this);builder.setTitle("确认登录电脑?");//确认登录builder.setPositiveButton("确认", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {makeSelection(contents,true);//确认登录要执行的方法dialog.dismiss();}});//取消登录builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {makeSelection(contents,false);//取消登录要执行的方法dialog.dismiss();}});builder.show();}else{Toast.makeText(MainActivity.this,"连接服务器失败,请检查网络或稍后重试",Toast.LENGTH_LONG).show();}}});}});}else{//==不是自己的扫码登录//判断是否是地址,是则跳转,否则,提示用户二维码的信息String value=contents.substring(0,4);if (value.equals("http")){Uri uri = Uri.parse(contents);Intent intent = new Intent(Intent.ACTION_VIEW, uri);startActivity(intent);}else{Toast.makeText(MainActivity.this,"二维码信息为:"+contents,Toast.LENGTH_LONG).show();}}}

Step 3 :确认登录或取消登录

public void makeSelection(String qrMessage,boolean b){String url=ServiceUtil.getUserUrl("makeSelection");Map<String,Object> map=new HashMap<>();map.put("qrMessage",qrMessage);map.put("agreeOrNot",b);map.put("userid",myApplication.getUserBean().getUserid());map.put("username",myApplication.getUserBean().getUsername());map.put("pasord",myApplication.getUserBean().getPasord());OkHttpTool.httpPost(url, map, new OkHttpTool.ResponseCallback() {@Overridepublic void onResponse(boolean isSuccess, int responseCode, String response, Exception exception) {MainActivity.this.runOnUiThread(new Runnable() {@Overridepublic void run() {if (isSuccess&&responseCode==200){Message message=JSON.parseObject(response,Message.class);Toast.makeText(MainActivity.this,message.getText(),Toast.LENGTH_LONG).show();}else{Toast.makeText(MainActivity.this,"连接服务器失败,请检查网络后稍后重试",Toast.LENGTH_LONG).show();}}});}});}

ok!!!打完收工

Android 扫码登录相关推荐

  1. Android 扫码登录案例

    首先不妨先看下Android:扫描二维码登陆原理: 大概总结下这个过程就是: 服务器生成全局唯一会话ID,并返回二维码.过期时间: 用户扫描二维码,提交改会话ID,用户基本信息到服务器: PC端在过期 ...

  2. 用Android和node.js实现扫码登录

    实现思路 step 1: 网页端提供二维码 step 2: 手机端登录,并保存token,手机扫码后向网页端发送token step 3: 网页端通过jstoken解析token,向后端服务器获取用户 ...

  3. Android集成微信SDK扫码登录功能

    最近做一个android项目,需求是登录页面加入微信二维码扫码登录入口(类似于PC端扫一扫登录),用户打开微信APP,扫描二维码,点击登录即可.当时也看了官网的相关介绍,确实踩了不少坑,写这个博客记录 ...

  4. Spring Boot 实现扫码登录,这种方式太香了!!

    作者 | 93年颈椎病人 来源 | https://blog.csdn.net/q826qq1878/article/details/91041679 最近有个项目涉及到websocket实现扫码登录 ...

  5. 钉钉扫码登录第三方_在钉钉发布公司重要文件,真的安全吗?

    钉钉以疫情在家办公为契机,加上"幸运地"被教育部"选中",在2月5日,钉钉下载量首次超过微信,跃居苹果App Store排行榜第一,并打破App Store记录 ...

  6. 基于SpringBoot+webSocket实现扫码登录功能

    作者:93年颈椎病人 blog.csdn.net/q826qq1878/article/details/91041679 最近单位又有一个新Java项目. 涉及到扫码登录.之前项目使用的是 ajax轮 ...

  7. thymeltesys-基于Spring Boot Oauth2的扫码登录框架

    thymeltesys thymelte是一个基于Spring Boot Oauth2的扫码登录框架,使用PostgreSQL存储数据,之后会慢慢支持其他关系型数据库.即使你不使用整个框架,只使用其中 ...

  8. 二维码扫码登录的原理

    二维码登录的本质 二维码登录本质上也是一种登录认证方式.既然是登录认证,要做的也就两件事情! 告诉系统我是谁 向系统证明我是谁 比如账号密码登录,账号就是告诉系统我是谁, 密码就是向系统证明我是谁; ...

  9. 解决云服务器上go-cqhttp扫码登录QQ失败问题

    解决云服务器上go-cqhttp扫码登录QQ失败问题 搭建环境 go-cqhttp:v1.0.0-rc1 nonebot:V1.9.1 python 3.9.12 CentOs 7.6 本篇文章仅仅分 ...

最新文章

  1. 了解Framework层对一名Android工程师的工作有什么帮助吗?
  2. Python多进程编程-进程间共享 对象
  3. Access处理DISTINCT的Bug?
  4. c++ 命名空间 using namespace std 是什么意思?
  5. 日期相减计算年_函数 | Excel有个“秘密”函数,计算年龄工龄特方便
  6. c语言for循环说课稿,C语言FOR循环说课稿.docx
  7. 明天就要离开上海了!
  8. [译]Hour 7 Teach.Yourself.WPF.in.24.Hours
  9. RabbitMQ消息幂等性问题
  10. Android逆向笔记-Unity3D逆向一般思路(静态分析)
  11. STM32工作笔记0015---STEMWIN在STM32F1开发板上的移植
  12. IDC机房建设方案参考资料
  13. html编辑字体的英文解释,html的字体名字(英文)
  14. 世界上最伟大的音乐、最经典的名曲都在这里!!!
  15. Image Tampering Detection via Semantic Segmentation Network
  16. Kafka - which is larger than the maximum request size you have configured with the max.request
  17. 有道云笔记同步IT笔试面试资源
  18. 智安网络丨德勤发布2021九大技术趋势,零信任安全成为主流
  19. 《人类简史》这本烧脑书风靡全球的秘密是什么?
  20. mysql导出gkb_mysql高效导入导出工具之mydumper

热门文章

  1. 鸿蒙负责人王成录被曝已离职:华为技术元老,1998年哈工大博士毕业后加入
  2. java引_JAVA中的引用
  3. 实战篇-OpenSSL之TripleDES加密算法-ECB模式
  4. 斯特林数 java实现_斯特林数 - BILL666 - 博客园
  5. 开源许可违反:案例说明(Apache License 2.0)
  6. 小闫陪你入门 Java (三)
  7. 用python画小鸭_python中的鸭子类型(协议)和接口
  8. 基于心电芯片 KS1081的微小穿戴心电方案
  9. 40Gbit/s QSFP光模块的软件实现(硕士学位论文)错误指出
  10. android工程文件assts,应用程序基础androiddevelopers英文翻译本科论文.docx