java扫码登录

这篇博文主要记录我实现扫码登录的步骤,及代码。其实之前从网上搜了很久扫码登录,copy版很多,所以回答也就那几种。

我把我自己的思路也说一下吧。如果有更好的意见或者我有不对的地方,请指出。

首先说一下我用的技术, maven构建项目,ssh ,redis, shiro, goeasy推送,ZXing二维码生成。


图有点粗糙。凑合看,我解释一下,首先我认为,session肯定是浏览器和服务器交互唯一的标识,所以我认为sessionid可以直接定位到是哪一个用户进行扫码登录,

OK,那么围绕这一点,当浏览器打开我们的网站时,我们就getsession,这样保证先给浏览器一个session对象。

接下来我将用代码展示的方式给大家展示一下流程

首先从网上扒了一个监听全局session的监听器。

public class MySessionContext {
	 private static HashMap mymap = new HashMap();

	    public static synchronized void AddSession(HttpSession session) {
	        if (session != null) {
	            mymap.put(session.getId(), session);
	        }
	    }

	    public static synchronized void DelSession(HttpSession session) {
	        if (session != null) {
	            mymap.remove(session.getId());
	        }
	    }

	    public static synchronized HttpSession getSession(String session_id) {
	        if (session_id == null)
	        return null;
	        return (HttpSession) mymap.get(session_id);
	    }
}

public class MySessionListener {
	   public void sessionCreated(HttpSessionEvent httpSessionEvent) {
		    MySessionContext.AddSession(httpSessionEvent.getSession());
		    }

		    public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
		        HttpSession session = httpSessionEvent.getSession();
		        MySessionContext.DelSession(session);
		    }
}


 <listener>
<listener-class>cn.itcast.web.action.lisener.MySessionListener</listener-class>
</listener>


这个实际上没啥必要。。。直接通过jssionid获取就可以了。当时没想到


登录Action

@Action("loginAction_login")
	public String login() throws Exception {
		Map<String, Object> session = ActionContext.getContext().getSession();
		Subject subject = SecurityUtils.getSubject();//shiro
		if(session.get(SysConstant.CURRENT_USER_INFO)!=null){//如果有session用户信息,直接走验证,说明是手机扫码的
			User user = (User) session.get(SysConstant.CURRENT_USER_INFO);
			subject.login(new UsernamePasswordToken(user.getUserName(),user.getPassword()));
		}
		
	
      if(subject.isAuthenticated()){//验证成功直接返回成功。
    	  return SUCCESS;
      }
		if(UtilFuns.isEmpty(username)){//为浏览器分配session
			HttpServletRequest request = ServletActionContext.getRequest();
			 sessID = request.getSession().getId();
		    super.push(sessID);
			request.getSession().setAttribute("ssid", sessID);
			return "login";
		}
		
		try {//登录成功赋值session
		    String md5 = Encrypt.md5(password, username);
			subject.login(new UsernamePasswordToken(username, md5));
			session.put(SysConstant.CURRENT_USER_INFO, (User)subject.getPrincipal());
		} catch (Exception e) {
			e.printStackTrace();
			request.put("errorInfo", "对不起,登录失败,用户名或密码错误!!!");
			HttpServletRequest request = ServletActionContext.getRequest();
			 sessID = request.getSession().getId();
			 super.push(sessID);//压栈
			request.getSession().setAttribute("ssid", sessID);//为了获得图片二维码时有session
			return "login";
		}
		User user =(User)subject.getPrincipal();
		
		//4.将user对象保存到session域中
		session.put(SysConstant.CURRENT_USER_INFO, user);
		//5.跳页面
		return SUCCESS;
	}
	

这里实际上页面也悄悄工作了

<script>
function changeCode(){
	$("#erweima").attr('src','${ctx}/mobile/MobileCode?t='+new Date().getTime());//选择二维码时直接去替换二维码图片
}
</script>
<script type="text/javascript" src="http://cdn.goeasy.io/goeasy.js"></script>
<script type="text/javascript">
        var goEasy = new GoEasy({
             appkey: 'BC-c9196bffff9b4fcabd70a200f95a51d2'
        });
        goEasy.subscribe({
            channel: '${sessID }',//这里绑定sessionid保证推送是指定用户
            onMessage: function(message){
            	
            	 location.reload()
            }
        });
        </script>
      
</head>



public class QRCodeUtil extends BaseAction{  
	
	@Action(value="MobileCode")
	public void getcode(){//生成二维码
		HttpServletResponse response;
		String urls;
		Hashtable<EncodeHintType, String> hints;
		BitMatrix matrix;
		try {
			response = (HttpServletResponse)
					ActionContext.getContext().get(org.apache.struts2.StrutsStatics.HTTP_RESPONSE);
			 Jedis jedis =new Jedis("192.168.123.101");
				HttpServletRequest request = ServletActionContext.getRequest();
				String sessID = (String) session.get("ssid");
				String id = request.getSession().getId();
				MySessionContext.AddSession(request.getSession());
			 String key = Encrypt.md5(UUID.randomUUID().toString(), "cao");
			jedis.set(key, sessID, "NX", "EX", 1800);
			 
			urls = "http://192.168.123.96:8080/test/mobileAutoLog?parms="+key;//这是手机端扫码的结果
			hints = new Hashtable<EncodeHintType, String>();  
  
			hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");  
  
			matrix = null;
			   matrix = new MultiFormatWriter().encode(urls,  
	                    BarcodeFormat.QR_CODE, 300, 300, hints);  
			   MatrixToImageWriter.writeToStream(matrix, "jpg", response.getOutputStream());
		} catch (Exception e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}  
  
        
  
    }  


然后假装扫码成功

我不得不插一段安卓代码了。。。

public void ineedLogin(View v){//扫码成功
		SharedPreferences sharedPreferences = getSharedPreferences("userinfo", 1);
		token = sharedPreferences.getString("username", "");
		
       
		try {
			GetDataFromService();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	private void GetDataFromService() throws   Exception{
		RequestParams params = new RequestParams(result+"&username="+token);//去访问浏览器发过来的请求,并且拼接上用户的用户名。
		x.http().post(params, new Callback.CacheCallback<String>() {

			@Override
			public boolean onCache(String result) {
				return false;
			}

			@Override
			public void onSuccess(String result) {

			}

			@Override
			public void onError(Throwable ex, boolean isOnCallback) {

			}

			@Override
			public void onCancelled(CancelledException cex) {

			}

			@Override
			public void onFinished() {

			}
		});

其实我这里选了一个比较low的。。我为了省事,安卓直接拼了username过去。。还用了个Xutils...搞得重写了很多方法。。别笑我。。哈哈哈哈

好了我们再来看扫码成功的action

Jedis jedis =new Jedis("192.168.123.101");
		 String jedisParms = jedis.get(parms);
		
		 if(jedisParms!=null&&!jedisParms.equals("")){//去看redis是否有手机端传过来这个码,
			 List<User> find = userService.find(new Specification<User>() {
				
				@Override
				public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
				
					return cb.equal(root.get("userName").as(String.class),username);
				}
			});
			 User u1 = find.iterator().next();//拿到用户信息
			
			 HttpSession session = MySessionContext.getSession(jedisParms);//拿到session
			 session.setAttribute(SysConstant.CURRENT_USER_INFO, u1);
			 
			
			
	final String APP_KEY="BC-c9196bffff9b4fcabd70a200f95a51d2";
	 
        GoEasy goEasy =new GoEasy(APP_KEY);
       goEasy.publish(jedisParms,"heh" ); //直接推送前端
     
			return NONE;
		 }else{
			 System.out.println("验证失败");
			 
		 }
	} catch (Exception e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
	return "error";
}

前端收到推送之后会刷新页面,并且session里面已经有值,那么会走登录验证的方法,session有值的方法。

我们再来看shiro,这里当时我有点懵,因为shiro实际上我用的不是很熟悉,就知道它运行的流程,当时不知道怎么才能让他验证通过,所以走了很多次shiro的登录方法,如果有别的好办法!也希望大家告诉我!!!

protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg0) throws AuthenticationException {
		Map<String, Object> session = ActionContext.getContext().getSession();
		User object = (User) session.get(SysConstant.CURRENT_USER_INFO);
		if(object!=null){//手机
			final String username = object.getUserName();
			List<User> findUser = userService.find(new Specification<User>() {

				@Override
				public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
					// TODO Auto-generated method stub
					return cb.equal(root.get("userName").as(String.class), username);
				}
			});
			return new SimpleAuthenticationInfo(findUser,findUser.get(0).getPassword(),this.getName());
		}else{//电脑
		 
		UsernamePasswordToken  userNamePassword=(UsernamePasswordToken) arg0;
		final String username = userNamePassword.getUsername();
		List<User> findUser = userService.find(new Specification<User>() {

			@Override
			public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
				// TODO Auto-generated method stub
				return cb.equal(root.get("userName").as(String.class), username);
			}
		});
		if(findUser!=null && findUser.size()!=0){
			
			return new SimpleAuthenticationInfo(findUser,findUser.get(0).getPassword(),this.getName());
		}
		}
		return null;
	}


因为之前没有加扫码登录时,我HashMd5是在这个密码比较器里加的,加了扫码之后,页面出过来明文我就直接加密了。所以密码比较器里面,直接比较就可以了


	public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
		UsernamePasswordToken uToken =(UsernamePasswordToken) token;
		String en =new String(uToken.getPassword());
		return equals(en, info.getCredentials());
	}


到此java扫码登录完成!

如果各位有别的好思路,希望也分享给我。

  • 6
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LawsonJin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值