WebSocket实现app扫描二维码登录
2017-08-14 14:57
567 查看
后台框架采用SpringMVC,不同的框架可根据逻辑更改即可:
【思路】- PC端生成二维码,二维码包含uuid(全局唯一标识符),且打通websocket通道,等待服务器返回登录成功信息;APP扫描二维码,获取uuid及登录信息,推送给服务端,处理后的登录信息通过websocket返回给PC端,PC端得到登录信息后保存即登录成功。APP扫描确认登录的信息可以采用ActiveMQ进行推送。
核心代码就酱......
【思路】- 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; @Autowired private WebSocketHandler webSocketHandler; @Autowired private UserService userService; @Autowired private 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 @LimitLess public 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 block e.printStackTrace(); } } /** * 描述:app确认请求处理 * @param uuid * @param host * @param userid * @author songfayuan * 2017年8月11日上午9:05:56 */ @RequestMapping("/sendCodeLoginInfo") @ResponseBody @LimitLess public 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 { @Autowired private QrCodeLoginWebSocketEndPoint endPoint; @Autowired private QrCodeLoginHandshakeInterceptor interceptor; @Override public 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: */ @Bean public 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 = LoggerFact ed3c ory.getLogger(QrCodeLoginHandshakeInterceptor.class); @Override public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception { return super.beforeHandshake(request, response, wsHandler, attributes); } @Override public 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<>(); @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { logger.info("WebSocketHandler:客户端{}上线", session.getRemoteAddress()); String uuid = generateUUID(); sessionMap.put(uuid,session); sessionMap2.put(session,uuid); } @Override protected 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; } } @Override public 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(); } @Override public 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); @Autowired private QrCodeLoginWebSocketEndPoint qrCodeLoginWebSocketEndPoint; @Override public 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); } } }
核心代码就酱......
相关文章推荐
- WebSocket实现app扫描二维码登录以及ws应用进行负载均衡?
- Android App扫描二维码功能的实现
- 实现手机扫描二维码进行登录
- 实现手机扫描二维码页面登录,类似web微信-第四篇,服务器端
- php 实现 二维码 扫描登录
- 微信扫描二维码,实现自动登录
- 扫描二维码自动登录实现原理
- 实现手机扫描二维码进行登录
- Ruby Websocket实现扫码二维码登录---GoEasy
- (转)扫描二维码,实现一键登录
- Android扫描二维码 实现 登录网页
- 二维码扫描web端实现登录
- 浅谈扫描二维码登录微信网页版与摇一摇传图的实现原理
- 实现手机扫描二维码进行登录
- 使用websocket实现手机扫描PC端二维码,移动端canvas手绘签名确定后将图片同步到PC端 扫码及时更新图片
- php 实现 二维码 扫描登录
- 仿微信的二维码登录功能:客户端登录后,通过扫描web端页面上的二维码,实现同一用户在web端的登录
- php 实现 二维码 扫描登录
- 实现手机扫描二维码页面登录,类似web微信-第三篇,手机客户端
- 实现手机扫描二维码页面登录,类似web微信-第一篇,业务分析