后台框架采用SpringMVC,不同的框架可根据逻辑更改即可:

【思路】- PC端生成二维码,二维码包含uuid(全局唯一标识符),且打通websocket通道,等待服务器返回登录成功信息;APP扫描二维码,获取uuid及登录信息,推送给服务端,处理后的登录信息通过websocket返回给PC端,PC端得到登录信息后保存即登录成功。APP扫描确认登录的信息可以采用ActiveMQ进行推送。

生成二维码部分引入依赖文件

     <dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.1.0</version></dependency><dependency>  <groupId>com.google.zxing</groupId>  <artifactId>javase</artifactId>  <version>3.1.0</version>  </dependency> 

二维码登录后台控制层Controller

/*** 项目名称:dream_user* 项目包名:org.fore.user.controller* 创建时间:2017年8月8日下午5:29:41* 创建者:Administrator-宋发元* 创建地点:杭州*/
package org.fore.user.controller;import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.fore.model.user.UserAccount;
import org.fore.model.user.UserModel;
import org.fore.user.qrcode.websocket.WebSocketHandler;
import org.fore.user.service.UserAccountService;
import org.fore.user.service.UserService;
import org.fore.utils.jms.JmsSender;
import org.fore.utils.mvc.TokenUtil;
import org.fore.utils.mvc.annotation.LimitLess;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;import com.alibaba.fastjson.JSONObject;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;/*** 描述:控制层* @author songfayuan* 2017年8月8日下午5:29:41*/
@Controller
@RequestMapping("/qrcodelogin")
public class QrCodeLoginController {private Logger logger = LoggerFactory.getLogger(QrCodeLoginController.class);public static int defaultWidthAndHeight=260;@Autowiredprivate WebSocketHandler webSocketHandler;@Autowiredprivate UserService userService;@Autowiredprivate UserAccountService userAccountService;@Autowired@Qualifier(value = "qrCodeLoginSender")private JmsSender jmsSender;/*** 描述:PC获取二维码* @param uuid* @param request* @param response* @throws ServletException* @throws IOException* @author songfayuan* 2017年8月11日上午9:04:43*/@RequestMapping("/getLoginQrCode")@ResponseBody@LimitLesspublic void getLoginQrCode(String uuid, HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {//生成参数//String uuid = generateUUID();String host = request.getHeader("Host");JSONObject data = new JSONObject();data.put("code", 200);data.put("msg", "获取二维码成功");data.put("uuid", uuid);data.put("host", host);logger.info("【二维码内容】:{}",data);//生成二维码Map<EncodeHintType, Object>  hints=new HashMap<EncodeHintType, Object>();// 指定纠错等级  hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L);  // 指定编码格式  hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");  hints.put(EncodeHintType.MARGIN, 1);try {BitMatrix bitMatrix = new MultiFormatWriter().encode(data.toString(),BarcodeFormat.QR_CODE, defaultWidthAndHeight, defaultWidthAndHeight, hints);OutputStream out = response.getOutputStream();MatrixToImageWriter.writeToStream(bitMatrix, "png", out);//输出二维码out.flush();out.close();} catch (WriterException e) {// TODO Auto-generated catch blocke.printStackTrace();}}/*** 描述:app确认请求处理* @param uuid* @param host* @param userid* @author songfayuan* 2017年8月11日上午9:05:56*/@RequestMapping("/sendCodeLoginInfo")@ResponseBody@LimitLesspublic void sendCodeLoginInfo(String uuid, String host, Integer userid) {// 注册成功后 或 登录,需要同步账户信息,获取用户基本信息UserAccount account = userAccountService.findCurrentUserAccount(userid);userAccountService.syncAccount(account);UserModel userModel = userService.findUserById(userid);userModel = changeUserForShow(userModel);JSONObject token = TokenUtil.generateTokenByQrCodeLogin(userid, host);JSONObject object = new JSONObject();object.put("code", 10086);object.put("uuid", uuid);object.put("userinfo", userModel);object.put("token", token);object.put("msg", "登录成功");//this.webSocketHandler.forwardQrCode(object.toString());jmsSender.sendMessage(object.toString()); //采用ActiveMQ进行推送,也可以直接注入websocket进行发送}//处理用户登录信息private UserModel changeUserForShow(UserModel userModel) {UserModel user = new UserModel();user.setId(userModel.getId());user.setUserName(userModel.getUserName());user.setUserSex(userModel.getUserSex());user.setUserPortrait(userModel.getUserPortrait());return user;}/*** 描述:唯一标识符* @return* @author songfayuan* 2017年8月11日上午9:06:12*/public static String generateUUID() {String uuid = UUID.randomUUID().toString();uuid = uuid.replace("-", "");Long currentTime = System.currentTimeMillis();String currentDate = String.valueOf(currentTime);return uuid + currentDate;}}

websocket实现(本案例采用Spring自带的websocket)

package org.fore.sms.qrcode.websocket;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
import org.springframework.web.socket.server.standard.ServletServerContainerFactoryBean;@Configuration
@EnableWebMvc
@EnableWebSocket
public class QrCodeLoginWebSocketConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer {@Autowiredprivate QrCodeLoginWebSocketEndPoint endPoint;@Autowiredprivate QrCodeLoginHandshakeInterceptor interceptor;@Overridepublic void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {registry.addHandler(endPoint, "/qrcodelogin.do").addInterceptors(interceptor).setAllowedOrigins("*");
//       registry.addHandler(endPoint,
//       "/sockjs.do").addInterceptors(interceptor).setAllowedOrigins("*")
//       .withSockJS();}/*** Each underlying WebSocket engine exposes configuration properties that* control runtime characteristics such as the size of message buffer sizes,* idle timeout, and others.*//*** For Tomcat, WildFly, and GlassFish add a* ServletServerContainerFactoryBean to your WebSocket Java config:*/@Beanpublic ServletServerContainerFactoryBean createWebSocketContainer() {ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();container.setMaxTextMessageBufferSize(8192);container.setMaxBinaryMessageBufferSize(8192);return container;}/*** For Jetty, you’ll need to supply a pre-configured Jetty* WebSocketServerFactory and plug that into Spring’s* DefaultHandshakeHandler through your WebSocket Java config:*/// @Bean// public DefaultHandshakeHandler handshakeHandler() {//// WebSocketPolicy policy = new WebSocketPolicy(WebSocketBehavior.SERVER);// policy.setInputBufferSize(8192); /* 设置消息缓冲大小 */// policy.setIdleTimeout(600000); /* 10分钟read不到数据的话,则断开该客户端 *///// return new DefaultHandshakeHandler(new JettyRequestUpgradeStrategy(new// WebSocketServerFactory(policy)));// }}
package org.fore.sms.qrcode.websocket;import java.util.Map;import javax.servlet.http.HttpServletRequest;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;@Component
public class QrCodeLoginHandshakeInterceptor extends HttpSessionHandshakeInterceptor {private Logger logger = LoggerFactory.getLogger(QrCodeLoginHandshakeInterceptor.class);@Overridepublic boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,Map<String, Object> attributes) throws Exception {return super.beforeHandshake(request, response, wsHandler, attributes);}@Overridepublic void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,Exception ex) {super.afterHandshake(request, response, wsHandler, ex);}
}
package org.fore.sms.qrcode.websocket;import java.io.IOException;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.fore.model.quota.tcp.ReqCode;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;@Component
public class QrCodeLoginWebSocketEndPoint extends TextWebSocketHandler {private Logger logger = LoggerFactory.getLogger(QrCodeLoginWebSocketEndPoint.class);private static Map<String, WebSocketSession> sessionMap = new ConcurrentHashMap<>();private static Map<WebSocketSession,String > sessionMap2 = new ConcurrentHashMap<>();@Overridepublic void afterConnectionEstablished(WebSocketSession session) throws Exception {logger.info("WebSocketHandler:客户端{}上线", session.getRemoteAddress());String uuid = generateUUID();sessionMap.put(uuid,session);sessionMap2.put(session,uuid);}@Overrideprotected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {String msg = message.getPayload();String ipAddress = session.getRemoteAddress().toString();JSONObject requestData = JSON.parseObject(msg);Integer code = requestData.getInteger("code");JSONObject result = new JSONObject();String uuid    = sessionMap2.get(session);result.put("code", 200);result.put("uuid", uuid);switch (code) {case ReqCode.REQ_QR_CODE:logger.info("WebSocketHandler:客户端{}发送消息{}...", ipAddress, msg);if(session.isOpen())session.sendMessage(new TextMessage(result.toString()));logger.info("WebSocketHandler:客户端{}发送消息{}完成", ipAddress, msg);break;default:break;}}@Overridepublic void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {String ipAddress = session.getRemoteAddress().toString();logger.info("WebSocketHandler:客户端{}下线", ipAddress);logger.info("WebSocketHandler:删除客户端{}的session...", ipAddress);logger.info("WebSocketHandler:删除sessionMap的客户端{}连接...", ipAddress);String uuid = sessionMap2.get(session);sessionMap.remove(uuid);sessionMap2.remove(session);logger.info("WebSocketHandler:删除sessionMap的客户端{}连接完成", ipAddress);logger.info("WebSocketHandler:删除WebSocket客户端{}连接...", ipAddress);
//      logger.info("{}", sessionMap);sessionMap.remove(session);
//      logger.info("{}", sessionMap);logger.info("WebSocketHandler:删除WebSocket客户端{}连接完成", ipAddress);logger.info("WebSocketHandler:删除客户端{}的session完成", ipAddress);if(session.isOpen())session.close();}@Overridepublic void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {logger.info("WebSocketHandler:客户端{}异常", session.getRemoteAddress(), exception);}//发送消息public void sendMessage(String userInfo) throws Exception {JSONObject json = JSONObject.parseObject(userInfo);String uuid = json.getString("uuid");WebSocketSession session = sessionMap.get(uuid);if (session == null) {logger.info("app发送给PC的登录信息:{}参数不正确!",userInfo);}else {logger.info("app发送给PC的登录信息:{}",userInfo);session.sendMessage(new TextMessage(userInfo));}}//唯一标识符public static String generateUUID() {String uuid = UUID.randomUUID().toString();uuid = uuid.replace("-", "");Long currentTime = System.currentTimeMillis();String currentDate = String.valueOf(currentTime);return uuid + currentDate;}
}

JMS实现

package org.fore.sms.qrcode.jms;import org.fore.utils.jms.Listener;
import org.fore.sms.qrcode.websocket.QrCodeLoginWebSocketEndPoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import com.alibaba.fastjson.JSONObject;@Component
public class QrCodeLoginListener implements Listener {private Logger logger = LoggerFactory.getLogger(QrCodeLoginListener.class);@Autowiredprivate QrCodeLoginWebSocketEndPoint qrCodeLoginWebSocketEndPoint;@Overridepublic void onMessage(String message) {logger.info("app确认登录信息:接收app推送的确定PC登录消息{}", message);JSONObject object = JSONObject.parseObject(message);try {qrCodeLoginWebSocketEndPoint.sendMessage(object.toJSONString());} catch (Exception e) {logger.info("app确认登录信息:接收app推送的确定PC登录消息异常", e);}}}

核心代码就酱......

转载于:https://www.cnblogs.com/songfayuan/articles/7357880.html

WebSocket实现app扫描二维码登录相关推荐

  1. vue websocket 公众号扫描二维码登录PC端

    首先使用的是websocket进行消息的传递,当我们在pc端请求到二维码图片后,打开微信扫一扫,扫描二维码后,就可以在websocket里接收到扫描消息,然后进行自己的业务逻辑处理,具体代码如下: w ...

  2. 浅谈扫描二维码登录微信网页版与摇一摇传图的实现原理

    前言:简单体验了下微信网页版通过二维码登录和摇一摇传图功能,从技术角度看,网上专家吹捧的 [隔空取物]其实并不神秘,我先简单分析一下. 1. 微信移动端扫描二维码登录(C-S-C模式) CSC模式为: ...

  3. 随机字符串解决大问题之腾讯网如何实现手机扫描二维码登录qq功能的

    随机字符串解决大问题之腾讯网如何实现手机扫描二维码登录qq功能的 腾讯网(www.qq.com)有一个扫码登录功能很有意思, 点击首页一键登录按钮,就会展现一个二维码,用手机qq扫描此二维码就可以使当 ...

  4. App 扫描二维码登陆网站

    App 扫描二维码登陆网站 +-----------+-----------+-----------+ | App | Web | Server | +-----------+-----------+ ...

  5. 百度网盘PC端扫描二维码登录时无法加载二维码问题解决方法

    问题: 今天在PC端扫描登录百度网盘时,二维码无法加载出来,具体情况如图: 解决方法: 1.打开IE浏览器 2.打开工具 3.打开Internet选项 4.打开高级选项,重置IE设置 5.点击确定,打 ...

  6. 图示扫描二维码登录原理

    想要了解手机端扫描二维码登录原理,首先我们要了解二维码和token认证机制两个内容,接下来我们将用图示的方法来直观感受这个面试时候的paper tiger. (第一次用visio画图,用熟练之后就感觉 ...

  7. 电脑版和手机版QQ都要手机版QQ扫描二维码登录?

    是的,电脑版和手机版 QQ 都需要使用手机版 QQ 扫描二维码登录.这是因为扫描二维码登录是 QQ 的安全认证方式之一.

  8. Teams App 扫描二维码

    上篇文章我们讲了如何在app的manifest里设置设备的权限,这篇文章我们来实际操作开发一个可以扫描二维码的teams app. 首先,我们先到app studio里,创建一个teams app,然 ...

  9. 微信扫描二维码登录第三方平台

    嗯...... 最近做了一个微信扫码登陆第三方平台功能,说下步骤就行,反正原理你们网上直接百度,我这里写了,估计也没几个人有耐心看 第一步 生成一个链接 https://open.weixin.qq. ...

最新文章

  1. 基于 Webpack 3 的 React 工程项目脚手架
  2. 在URL地址栏中显示ico
  3. 初识Vue,写的一些小练习
  4. 物料主数据(SAP屠夫)
  5. ibatis多参数的问题
  6. 复制 和 粘帖 的方法(特别在linux中),备忘
  7. gatling系列教程(翻译)-第三节(快速开始)
  8. 【Python 10】汇率兑换3.0(while循环)
  9. 排序算法-快速排序(入门)
  10. qt qtableview插入进度条_Qt之QSqlTableModel的使用
  11. CCNA--路由器常用命令
  12. python爬虫,爬取猫眼电影top100
  13. java中model的意思_开发中model,entity和pojo的区别
  14. 架构学习——业务架构图
  15. PPT如何压缩?PPT文件压缩的方法有哪些
  16. (五)Excel函数应用之查询与引用函数
  17. Ubuntu 各版本号和名称对照
  18. AxGlyph矢量绘图软件
  19. nowcoder contest#115 江西财经大学第一届程序设计竞赛 G 小Q的口袋校园 记忆化搜索 DP
  20. Linux、Qt等安装镜像下载--清华大学开源软件镜像站

热门文章

  1. MSCI推出新的开放分析平台MSCI Beon
  2. 浏览器省流量功能手札
  3. 零日漏洞指什么?如何有效应对?
  4. mysql里字典是什么意思_解析MySQL数据字典中的一些疑问
  5. Maven添加Jar包到本地仓库(阿里sdk-alipay-java)
  6. jupyter lab 的使用
  7. 知识图谱嵌入模型之TransE算法
  8. 池化层-Pooling(CNN卷积神经网络)
  9. 2022爱分析· 数据智能厂商全景报告
  10. RANSAC 直线拟合