公众号扫码登录网站

微信公众号扫码登录的流程为:1、接入公众号;2、获取accessToken;3、生成带 Ticket 二维码;4、接收事件推送、回复文本消息;5、校验是否扫描完成。

1.接入公众号:具体的操作方法请参考官网:

链接:[https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Access_Overview.html](https://link.segmentfault.com/?enc=yFxuCBpi%2FOztIpDbK4OLGg%3D%3D.IQNzJ0bJGjMnpQC1rmC2ztRdfRlgwcF3Pk0Ezzqgz7xGq2tBMUOoXxp3ua4ltxT0QfKgZdqvNougH24U59vRLkbHEXgeJwArpQaAiCbxBJcnfXl83tcy5PrEXB%2BiQvcm)

配置自己的url(接口回调地址):
例如: http://ww.wyz.com/wx/auth/check

另请注意,微信公众号接口必须以http://或https://开头,分别支持80端口和443端口。
微信回调到自己系统的时候ip 是不确定的,请不要限制访问(例如不允许外省访问的限制)

2.获取accessToken:

链接:[https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Get_access_token.html](https://link.segmentfault.com/?enc=kjJspzxIQZF0tx3B2jOq9g%3D%3D.0ApPvb1IgNirD4pJ6UpM13mMJ1zWfLWjNDgMwHq9U7YNK8Ggl3zY%2FXiMOGGg6kNAQqhN235Jokahp8jhwNfi5SoFE%2FCRHDPF5UbpWzXuDjRmq0sPeCNh5b44HtK89oKk)
public class getAccessTokenUtils{
          // 令牌自定义标识
    @Value("${token.header}")
    private String header;

    // 令牌秘钥
    @Value("${token.secret}")
    private String secret;

    private static String appId = "wx1796034498cf195a";

    private static String appSecret = "d5bf2b3d40220deebffc27819ed37334";

    // 获取access_token地址
    private static String tokenUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
    @Resource
    private RedisCache redisCache;


    public String getAccessToken() {
        String accessToken = "";
        if (redisCache.getCacheObject("wx_access_token") == null) {
            String url = tokenUrl.replace("APPID", appId).replace("APPSECRET", appSecret);
            HttpRequest get = HttpUtil.createGet(url);
            HttpResponse execute = get.execute();
            String body = execute.body();
            if (body != null && !"".equals(body)) {
                try {
                    JSONObject obj = JSON.parseObject(body);
                    if (obj.get("access_token") != null) {
                        accessToken = obj.get("access_token").toString();
                        redisCache.setCacheObject("wx_access_token", accessToken, Integer.parseInt(obj.get("expires_in").toString()), TimeUnit.SECONDS);
                    }
                } catch (Exception e) {
                    System.out.println("获取token失败:" + body);
                }
            }
        } else {
            accessToken = redisCache.getCacheObject("wx_access_token");
        }
        return accessToken;
    }
}

3.生成带 Ticket 二维码

链接:[https://developers.weixin.qq.com/doc/offiaccount/Account_Management/Generating_a_Parametric_QR_Code.html](https://link.segmentfault.com/?enc=2mV2OtsEXPVf%2FKtIOQYxUg%3D%3D.7VbgDgPk3mxHArpMm8Dnqsuy0CKNMdbk56%2B3s2KLmf%2FjLrKQvvHRrzLD%2FLYxRXRFqqKYcJ%2FMFJIjOZvLAOFlYSTXcvfxAPSDg62eVUym5ULit%2BjeO8UYb1rZAwWELGjpAgZ0rUL%2F%2BgKo6wx6CxcQRQ%3D%3D)
 public String createQrCode() {
        String qrcodeImg = "";
        String wx_qrcode_img = redisCache.getCacheObject("wx_qrcode_img");
        if (StringUtil.isNotEmpty(wx_qrcode_img)) {
            qrcodeImg = wx_qrcode_img;
        } else {
            String accessToken = getAccessTokenUtils.getAccessToken();
            if (StringUtil.isNotEmpty(accessToken)) {
                String url = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=" + accessToken;
                String param = "{\"action_name\": \"QR_LIMIT_SCENE\", \"action_info\": {\"scene\": {\"scene_id\": 123}}}";
                String result = HttpUtils.sendPost(url, param);
                JSONObject jsonObject = JSON.parseObject(result);
                String ticket = jsonObject.get("ticket").toString();
                try {
                    ticket = URLEncoder.encode(ticket, "utf-8");
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
                qrcodeImg = String.format("https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=%s", ticket);
                redisCache.setCacheObject("wx_qrcode_img", qrcodeImg, 365, TimeUnit.DAYS);
            }
        }
        return qrcodeImg;
    }

4.接收事件推送、回复文本消息

接受推送事件:
链接:[https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Receiving_event_pushes.html](https://link.segmentfault.com/?enc=VlDq4%2FG8BAkeGa%2FTea6aoA%3D%3D.Dmc61JZQbJzyaxX8B%2BJZd%2BWGjKStKy%2BX%2BsQM0WFkQ9lhY9Qy7qFGcR0nJsYjvn4EONG1lh8IcbPS0K7MVzmp0DmucCu2qFYkTMLNGd4uAzufuvjopMivGWQ5ZFj6oCqTxFstHM%2BOvdGmmBaZ3bANKVOxiO3R3Dt4NNeqspSxPogq1UyibXmTt6gWm96I78UYTcjKNDsqgZs96W1FmkWmK%2BaYmMCdHVhFs8WpECGYuyXtIpBCAbGi1WtHp4FXrk5M)

设置回复文本消息:[https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Passive_user_reply_message.html](https://link.segmentfault.com/?enc=yknR0ZA19HdA2lU%2BR%2F56hg%3D%3D.GtfKr%2Bq%2BzhVEwbyweCjgoUFzppp4LvE0KfKsZKd2rBhkybZt5l0hrmzAx0FJpNraAPbWxJqx4f%2FFcCkxF005ICNru29V7jx9L0ejp7LP0DmaQWF%2Fyr4%2BBmm85wxGnv5trFJdJM6VeeMEjl%2Bu766o6w%3D%3D)

当前端获取到二维码的链接以后,进行访问将会得到二维码,用户打开微信扫描二维码后,微信将会回调我们一开始配置好的那个回调地址(http://ww.wyz.com/wx/auth/check

以下是实现代码:

/**
 * 公众号扫码登录回调接口
 */
@Slf4j
@RestController
@RequestMapping("/wx/auth")
public class WeixinServerController {

    @Autowired
    private WeixinUserService weixinUserService;

    @Resource
    private SysUserMapper sysUserMapper;

    @Value("${weixin.token}")
    private String token;

    /**
     * 接收事件推送
     *
     * @param request
     * @return
     */
    @GetMapping(value = "/check")
    public String weixinCheck(HttpServletRequest request) {
        log.info("微信回调开始(get)");
        String signature = request.getParameter("signature");
        String timestamp = request.getParameter("timestamp");
        String nonce = request.getParameter("nonce");
        String echostr = request.getParameter("echostr");

        if (StringUtils.isEmpty(signature) || StringUtils.isEmpty(timestamp) || StringUtils.isEmpty(nonce)) {
            return "";
        }
        weixinUserService.checkSignature(signature, timestamp, nonce);
        return echostr;
    }


    /**
     * 接收事件推送:在用户扫码后微信服务端会回调改接口
     *
     * @param requestBody
     * @param signature   微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。
     * @param timestamp   时间戳
     * @param nonce       随机字符串
     * @return
     */
    @PostMapping(value = "/check")
    public String weixinMsg(@RequestBody String requestBody, @RequestParam("signature") String signature,
                            @RequestParam("timestamp") String timestamp, @RequestParam("nonce") String nonce) {
        log.info("微信回调开始(post)");
        log.info("requestBody:{}", requestBody);
        log.info("signature:{}", signature);
        log.info("timestamp:{}", timestamp);
        log.info("nonce:{}", nonce);
        String strs = "签名验证失败"; 
        String[] arr = new String[]{token, timestamp, nonce};
        Arrays.sort(arr);
        StringBuilder content = new StringBuilder();
        for (String str : arr) {
            content.append(str);
        }
        String tmpStr = DigestUtils.sha1Hex(content.toString());
        if (tmpStr.equals(signature)) {
            log.info("签名验证成功");
            ReceiveMessage receiveMessage = WeixinMsgUtil.msgToReceiveMessage(requestBody);
            // 扫码登录
            if (WeixinMsgUtil.isScanQrCode(receiveMessage)) {
                log.info("扫码登录事件");
                return handleScanLogin(receiveMessage);
            }
            // 关注
            if (WeixinMsgUtil.isEventAndSubscribe(receiveMessage)) {
                log.info("关注事件");
                return receiveMessage.getReplyTextMsg("欢迎关注公众号");
            } else {
                log.info("取关事件");
                //取关
                String openId = receiveMessage.getFromUserName();
                SysUser user = new SysUser();
                user.setOpenid(openId);
                List<SysUser> sysUsers = sysUserMapper.selectUserList(user);
                if (CollectionUtils.isNotEmpty(sysUsers)) {
                    for (SysUser sysUser : sysUsers) {
                        sysUserMapper.updateOpenIdByPhone(sysUser.getPhonenumber());
                    }
                }

            }
            strs  =  receiveMessage.getReplyTextMsg("收到(自动回复)");
        }
        //设置回复文本消息
        return strs;
    }
    /**
     *回复文本消息
     *
     * @param receiveMessage
     * @return
     */
    private String handleScanLogin(ReceiveMessage receiveMessage) {
        String qrCodeTicket = WeixinMsgUtil.getQrCodeTicket(receiveMessage);
        if (WeixinQrCodeCacheUtil.get(qrCodeTicket) == null) {
            String openId = receiveMessage.getFromUserName();
            WeixinQrCodeCacheUtil.put(qrCodeTicket, openId);
            log.info("openId:{},ticket:{}设置成功",openId,qrCodeTicket);
        }
        //判断该用户在系统中是否存在
        if (sysUserMapper.selectByOpenid(receiveMessage.getFromUserName()) == null) {
            log.info("已关注为绑定手机号");
            //todo 返回自己业务需要的文字
            return receiveMessage.getReplyTextMsg("欢迎关注公众号!");
        } else {
            log.info("已登录成功");
           //todo 返回自己业务需要的文字
            return receiveMessage.getReplyTextMsg("你已成功登录!");
        }
    }

}

5.校验是否扫描完成

扫码以后,前端得一直轮询该方法,直到能够获取到token


    /**
     * 校验是否扫描完成 (获取二维码 /qrcode)
     * 完成,返回 token
     * 未完成,返回 check faild
     *
     * @param ticket
     * @return
     */
    @GetMapping(value = "/user/login/qrcode")
    public AjaxResult userLogin(String ticket) {
        // todo 扫码成功后的逻辑
        String openId = WeixinQrCodeCacheUtil.get(ticket);
            // todo  生成令牌
            String token ="自己的token";
            HashMap<Object, Object> temp = new HashMap<>();
            temp.put("token", token);
            ajax.put("data", temp);
            return ajax;
        }
        log.info("登录失败,ticket:{}", ticket);
        return AjaxResult.success("");
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,295评论 6 512
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,928评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,682评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,209评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,237评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,965评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,586评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,487评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,016评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,136评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,271评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,948评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,619评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,139评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,252评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,598评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,267评论 2 358

推荐阅读更多精彩内容