Java 实现微信扫码登录方法(提供前端及后端核心代码)

发布时间:2023年12月26日

思路

1、Vue前端页面获取一个公众号的二维码,不是普通二维号,是带有场景值的

2、java后端接收前端的请求,生成一个带时效性的二维码链接返回给前端

3、公众号平台配置服务器接口地址

4、接收到关注或扫码请求并相应处理

5、前端轮询状态,如果检查到验证通过进到下一页面

前端页面

vue代码

    wxlogin() {
        this.$showLoading();
        getTempQrCode(this.token).then((res) => {
            console.log("res==========",res);
            this.$closeLoading();
            this.imageUrl = objToStr(res.data.message);
            this.loginType='wx'
            setTimeout(() => {
                this.check();               
            }, 1000);
        }) 
    },

java代码

@RequestMapping(value = "/getTempQrCode", method = RequestMethod.GET)
public Result<?> getTempQrCode(@RequestParam(name = "scene_str", required = true) String sceneStr) {

        WeixinHelper.setAppId(appid);
        WeixinHelper.setSecret(secret);
        String result = WeixinHelper.createTempQrCode(WeixinHelper.getAccessToken(), sceneStr);
        return Result.ok(result);
}


public static String createTempQrCode(String access_token, String scene_str) {
        String url = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=" + access_token;
        Map<String, Object> data = new HashMap<>();
        data.put("expire_seconds", 604800);
        data.put("action_name", "QR_STR_SCENE");
        Map<String, Object> action_info = new HashMap<>();
        Map<String, Object> scene = new HashMap<>();
        scene.put("scene_str", scene_str);
        action_info.put("scene", scene);
        data.put("action_info", action_info);
        String json = HttpUtil.createPost(url)
                .header("Content-Type", "application/json")
                .body(JSONUtil.toJsonStr(data))
                .execute().body();
        System.out.println("json = " + json);
        String qrcode = (String) JSONUtil.getByPath(JSONUtil.parse(json), "ticket");
        return "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=" + qrcode;
    }



public static String getAccessToken() {
        accessToken = getNewAccessToken();
        return accessToken;
}


public static String getNewAccessToken() {
        String access_token = "";
        String grant_type = "client_credential";//获取access_token填写client_credential
        String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=" + grant_type + "&appid=" + appId + "&secret=" + secret;
        try {
            URL urlGet = new URL(url);
            HttpURLConnection http = (HttpURLConnection) urlGet.openConnection();
            http.setRequestMethod("GET"); // 必须是get方式请求
            http.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            http.setDoOutput(true);
            http.setDoInput(true);
            System.setProperty("sun.net.client.defaultConnectTimeout", "30000");// 连接超时30秒
            System.setProperty("sun.net.client.defaultReadTimeout", "30000"); // 读取超时30秒
            http.connect();
            InputStream is = http.getInputStream();
            int size = is.available();
            byte[] jsonBytes = new byte[size];
            is.read(jsonBytes);
            String message = new String(jsonBytes, "UTF-8");
            JSONObject demoJson = JSONObject.parseObject(message);
            System.out.println("JSON字符串:" + demoJson);
            access_token = demoJson.getString("access_token");
            is.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return access_token;
}




公众号配置

java提供消息接收接口代码,有两个,一个get(公众平台网址验证的时候用),一个post(消息事件触发时用)

/*
     * @param signature 微信加密签名,signature结合了开发者填写的 token 参数和请求中的 timestamp 参数、nonce参数。
     * @param timestamp 时间戳
     * @param nonce     这是个随机数
     * @param echostr   随机字符串,验证成功后原样返回
     */
    @GetMapping("/wx/event")
    public void get(@RequestParam(required = false) String signature,
                    @RequestParam(required = false) String timestamp,
                    @RequestParam(required = false) String nonce,
                    @RequestParam(required = false) String echostr,
                    HttpServletResponse response) throws IOException {
        System.out.println("接受事件===" + echostr);
        response.setCharacterEncoding("UTF-8");
        response.getWriter().write(echostr);
        response.getWriter().flush();
        response.getWriter().close();
    }

    //处理微信推送事件
    @PostMapping("/wx/event")
    public void post(final HttpServletRequest request, HttpServletResponse response) {

        System.out.println("接受事件");
        try {
            // 微信加密签名
            final String signature = request.getParameter("signature");
            // 时间戳
            final String timestamp = request.getParameter("timestamp");
            // 随机数
            final String nonce = request.getParameter("nonce");
            // 随机字符串
            final String echostr = request.getParameter("echostr");
            //将xml文件转成易处理的map(下方贴出)
            final Map<String, String> map = oConvertUtils.parseXml(request);
            //开发者微信号
            final String toUserName = map.get("ToUserName");
            //OpenId
            final String fromUserName = map.get("FromUserName");
            //消息创建时间 (整型)
            final String createTime = map.get("CreateTime");
            //消息类型,event
            final String msgType = map.get("MsgType");
            //事件类型
            final String event = map.get("Event");

            String scene_str = "";
            String msg = "";
            if ("event".equals(msgType)) {
                if (event.equals("subscribe")) {
                    final String ticket = map.get("Ticket");
                    if (ticket != null) {
                        scene_str = map.get("EventKey").replace("qrscene_", "");
                    }
                    msg = getXmlReturnMsg(fromUserName, toUserName, (new Date()).getTime(), "欢迎您使用量子文档");
                }
                //注:事件类型为SCAN即已关注
                else if (event.equals("SCAN")) {
                    final String ticket = map.get("Ticket");
                    if (ticket != null) {
                        scene_str = map.get("EventKey");
                    }
                    msg = getXmlReturnMsg(fromUserName, toUserName, (new Date()).getTime(), "您刚刚扫码登录了量子文档");

                }
            }
            System.out.println("event:" + event);
            System.out.println("场景值:" + scene_str);
            System.out.println("openId:" + fromUserName);
            System.out.println("ToUserName:" + toUserName);

            // 如果scene_str 不为空代表用户已经扫描并且关注了公众号
            if (oConvertUtils.isNotEmpty(scene_str)) {
                QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>();
                queryWrapper.eq("open_id", fromUserName);
                SysUser sysUser = sysUserService.getOne(queryWrapper, false);
                if (sysUser == null) {
                    sysUser = new SysUser();
                    sysUser.setOpenId(fromUserName);
                    sysUser.setUsername(fromUserName);
                    sysUser.setRealname(null);
                    String salt = oConvertUtils.randomGen(8);
                    String passwordEncode = PasswordUtil.encrypt(fromUserName, salt, salt);
                    sysUser.setSalt(salt);
                    sysUser.setMemberLevelId("1");
                    sysUser.setPassword(passwordEncode);
                    sysUser.setStatus(1);
                    sysUser.setDelFlag(CommonConstant.DEL_FLAG_0);
                    sysUserService.save(sysUser);
                    LzMessage message = new LzMessage();
                    message.setMsgDate(new Date());
                    message.setContent("欢迎您使用量子文档");
                    message.setFileId(null);
                    message.setIsRead(0);
                    message.setDelFlag(0);
                    message.setMsgType(3);
                    message.setFromUserId("001");
                    message.setFromUserName("小量子");
                    message.setToUserId(sysUser.getId());
                    lzMessageService.save(message);
                }
                // 将微信公众号用户ID缓存到redis中,标记用户已经扫码完成,执行登录逻辑。
                redisUtil.set(scene_str, fromUserName, 60);
            }
            System.out.println("打印消息体=========");
            System.out.println(msg);
            System.out.println("=========");

            response.setCharacterEncoding("UTF-8");
            PrintWriter out = response.getWriter();
            out.print(msg);
            out.flush();
            out.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

vue前端轮询

check() {
        if (this.loginType!='wx') return false;       
        checkScanState(this.token).then((res) => {
            console.log(res);
            console.log("check....");
            if (res.data.success == true) {
                sessionStorage.setItem('token', res.data.result.token)
                sessionStorage.setItem('userId', res.data.result.userInfo.id)
                sessionStorage.setItem('userName', res.data.result.userInfo.username)
                sessionStorage.setItem('realname', res.data.result.userInfo.realname)
                sessionStorage.setItem('sex', res.data.result.userInfo.sex)
                sessionStorage.setItem('memberLevelName', res.data.result.memberLevel.name)
                sessionStorage.setItem('maxFileCount', res.data.result.memberLevel.maxFileCount)
                this.loginType = "";
                if (objToStr(res.data.result.userInfo.realname) == "") {
                    this.$showInputBox({
                        caption: "输入您的姓名",
                        inputValue: '',
                        callback: (data) => {
                            updateRealname(res.data.result.userInfo.id, data).then((res) => {
                                sessionStorage.setItem('realname', data)
                                this.$closeInputBox();    
                            })
                        }
                    })
                }
                this.$router.push({
                    path: '/person' ,
                })
            } else {               
                setTimeout(() => {
                    this.check();               
                }, 1000);
            }
        })           
    },

后端接受前端查状态的轮询请求

@ApiOperation("检查扫码状态")
	@GetMapping("/checkScanState")
	public Result<JSONObject> wechatLogin(@RequestParam(name = "scene_str", required = true) String sceneStr) {
		Result<JSONObject> result = new Result<JSONObject>();
		Object openId = redisUtil.get(sceneStr);
		if (openId == null) {
			result.error500("未登入");
			return result;
		}

		QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>();
		queryWrapper.eq("open_id", openId);
		SysUser sysUser = sysUserService.getOne(queryWrapper, false);
		if (sysUser != null) {

			String syspassword = sysUser.getPassword();
			String username = sysUser.getUsername();
			// 生成token
			String token = JwtUtil.sign(username, syspassword);
			redisUtil.del(CommonConstant.PREFIX_USER_TOKEN + token);
			//清空用户登录Shiro权限缓存
			redisUtil.del(CommonConstant.PREFIX_USER_SHIRO_CACHE + sysUser.getId());
			//清空用户的缓存信息(包括部门信息),例如sys:cache:user::<username>
			redisUtil.del(String.format("%s::%s", CacheConstant.SYS_USERS_CACHE, sysUser.getUsername()));

			result = sysUserService.checkUserIsEffective(sysUser);
			if(!result.isSuccess()) {
				return result;
			}
			//用户信息
			userInfo(sysUser, result);
			//添加日志
			sysBaseAPI.addLog("用户名: " + sysUser.getUsername() + ",登录成功!", CommonConstant.LOG_TYPE_1, null);
		}
		return result;
	}



	/**
	 * 用户信息
	 *
	 * @param sysUser
	 * @param result
	 * @return
	 */
	private Result<JSONObject> userInfo(SysUser sysUser, Result<JSONObject> result) {
		String syspassword = sysUser.getPassword();
		String username = sysUser.getUsername();
		// 生成token
		String token = JwtUtil.sign(username, syspassword);
        // 设置token缓存有效时间
		redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token);
		redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME*2 / 1000);

		// 获取用户部门信息
		JSONObject obj = new JSONObject();
		List<SysDepart> departs = sysDepartService.queryUserDeparts(sysUser.getId());
		obj.put("departs", departs);
		if (departs == null || departs.size() == 0) {
			obj.put("multi_depart", 0);
		} else if (departs.size() == 1) {
			sysUserService.updateUserDepart(username, departs.get(0).getOrgCode());
			obj.put("multi_depart", 1);
		} else {
			obj.put("multi_depart", 2);
		}
		obj.put("token", token);
		obj.put("userInfo", sysUser);
		obj.put("sysAllDictItems", sysDictService.queryAllDictItems());
		obj.put("memberLevel", lzMemberLevelService.getById(sysUser.getMemberLevelId()));
		result.setResult(obj);
		result.success("登录成功");
		return result;
	}

文章来源:https://blog.csdn.net/gdgztt/article/details/135214374
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。