Android 扫码登录

国际惯例:先上图:
在这里插入图片描述

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() {	
		
		//创建UUID
		String 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 :这里只从扫码得到的结果开始写,具体如何扫码,请看自己的扫码笔记 或 查看自己的博客 :
安卓扫码例子的地址

   @Override
    protected 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 :根据扫描的结果做相关的操作

//执行服务端的扫码登录
    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() {
                @Override
                public void onResponse(boolean isSuccess, int responseCode, String response, Exception exception) {
                    MainActivity.this.runOnUiThread(new Runnable() {
                        @Override
                        public void run() {

                            if(isSuccess&&responseCode==200){
                                //提示用户是否确认登录web端
                                AlertDialog.Builder builder=new AlertDialog.Builder(MainActivity.this);
                                builder.setTitle("确认登录电脑?");

                                //确认登录
                                builder.setPositiveButton("确认", new DialogInterface.OnClickListener() {
                                    @Override
                                    public void onClick(DialogInterface dialog, int which) {
                                        makeSelection(contents,true);//确认登录要执行的方法
                                        dialog.dismiss();
                                    }
                                });

                                //取消登录
                                builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
                                    @Override
                                    public 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() {
            @Override
            public void onResponse(boolean isSuccess, int responseCode, String response, Exception exception) {
                MainActivity.this.runOnUiThread(new Runnable() {
                    @Override
                    public 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!!!打完收工

猜你喜欢

转载自blog.csdn.net/weixin_44619313/article/details/107621751
今日推荐