java实现微信第三方登录流程源码详解,所遇到的坑

简介: java实现微信第三方登录流程源码详解,所遇到的坑

昨天在写一个手机版的web项目,要在微信客户端使用微信第三方登录,想着也没啥,看看就看看吧,但是可恶的微信官方文档给我画了很大的一个坑,特此记录

二次更新,说明一下我这个是用我微信网页授权,就是在微信客户端点开链接或菜单能弹出微信授权登录框的功能!

前期准备工作我就不多说了,无非就是公众平台账号,填写相关资料耐心等待审核就好。

这里要注意一点的是,网站应用创建好之后的授权回调域填写顶级域名就好,之前我一直写的二级域名,测试的时候回调总是过不来,后来回来看文档,微信说的就是,该域名下的所有页面都 可以回调

创建好网站应用之后我们来看微信提供的接口文档

微信开放平台第三方登录接口文档地址

第一步:请求CODE

根据官方文档,请求code这里要按照响应的参数进行拼接,参数就按照官方提供的,需要注意的是appid是你用哪个公众号登录就用哪个公众号的appid,这里不是开放平台的网站应用appid


然后另一个坑,redirect_uri,一定要用urlEncode对链接进行处理,这个链接是用户打开这个链接同意登录之后会跳转的地址,我们要跳转到后台对回调的信息就行处理,所以就要回调到我们域名下的controller控制器方法中,并且一定是要外网可访问。比如:www.test.com/callback

把链接进行Encode处理,这里提供一个 encode在线解码工具


拼接好路径之后再微信客户端打开就应该会显示某某公众号的授权登录页面了,如果报错那就是路径没有拼接正确


请求code的控制器如下所示:

参数是我自己的,换成你的参数就好

    @RequestMapping("/getCode")
    public void getCode(HttpServletRequest request, HttpServletResponse response) throws IOException {
        //拼接url
        StringBuilder url = new StringBuilder();
        url.append("https://open.weixin.qq.com/connect/oauth2/authorize?");
        //微信开放平台的appid
        url.append("appid=" + WeixinConfig.appId);
        //转码
        try {
          //回调地址 ,回调地址要进行Encode转码
            String redirect_uri = URLEncoder.encode(WeixinConfig.REDIRECT_URI, "utf-8");
            System.out.println("redirect_uri==" + redirect_uri);
            url.append("&redirect_uri=" + redirect_uri);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        url.append("&response_type=code");
        url.append("&scope=snsapi_userinfo");
        url.append("&state=" + request.getSession().getId());
        url.append("#wechat_redirect");
        System.out.println("url===" + url.toString());
//        return "redirect:" + url.toString();
        String s = url.toString();
        response.sendRedirect(s);
    }

返回说明


用户允许授权后,将会重定向到redirect_uri的网址上,并且带上code和state参数


第二步:通过code换取网页授权access_token


第三步:刷新access_token(如果需要)


第四步:拉取用户信息(需scope为 snsapi_userinfo)


这三步我们应该在上面授权回调方法中调用,起初我在想每一个方法都要返回一个json,那么是不是我要三个控制器方法才行?,怎样才能在一个控制器里调用三个方法呢?


感谢大神提供的发送GET请求的工具类:

public static JSONObject doGetJson(String url) throws Exception, IOException {
        JSONObject jsonObject = null;
        //初始化httpClient
        DefaultHttpClient client = new DefaultHttpClient();
        //用Get方式进行提交
        HttpGet httpGet = new HttpGet(url);
        //发送请求
        HttpResponse response = client.execute(httpGet);
        //获取数据
        HttpEntity entity = response.getEntity();
        //格式转换
        if (entity != null) {
            String result = EntityUtils.toString(entity, "UTF-8");
            jsonObject = JSONObject.fromObject(result);
        }
        //释放链接
        httpGet.releaseConnection();
        return jsonObject;
    }

最后附上我的授权回调方法:

  /**
     * 微信 授权登录回调
     **/
    @RequestMapping("/callback")
    public void callback(String code, String state, HttpServletRequest request, HttpServletResponse response) throws Exception {
        System.out.println("====" + code + "===" + state + "====");
        logger.debug("code===" + code);
        logger.debug("state===" + state);
        if (StringUtils.isNotEmpty(code)) {
            logger.debug("sssssssss====" + code);
            StringBuilder url = new StringBuilder();
            url.append("https://api.weixin.qq.com/sns/oauth2/access_token?");
            //微信公众平台的AK和SK
            url.append("appid=" + WeixinConfig.appId);
            url.append("&secret=" + WeixinConfig.appSecret);
            //这是微信回调给你的code
            url.append("&code=" + code);
            url.append("&grant_type=authorization_code");
            System.out.println("url.toString()===" + url.toString());
            logger.debug("url.toString()===" + url.toString());
            JSONObject jsonObject = AuthUtil.doGetJson(url.toString());
            logger.debug("jsonObject================"+jsonObject);
            //解析jsonStr的字符串
            //1.获取微信用户的openid
            String openid = jsonObject.getString("openid");
            //2.获取获取access_token
            String access_token = jsonObject.getString("access_token");
            logger.debug("openid===" + openid);
            logger.debug("access_token===" + access_token);
            String infoUrl = "https://api.weixin.qq.com/sns/userinfo?access_token=" + access_token + "&openid=" + openid
                    + "&lang=zh_CN";
            logger.debug("infoUrl===" + infoUrl);
            //3.获取微信用户信息
            JSONObject userInfo = AuthUtil.doGetJson(infoUrl);
            logger.debug("userInfo======================"+userInfo);
            //至此拿到了微信用户的所有信息,剩下的就是业务逻辑处理部分了
            //保存openid和access_token到session
            if (openid==null){
                logger.debug("-------------------------微信授权回调,获取用户信息失败!=============================");
                response.sendRedirect("http://m.huerdai.net/html/Program-error.html");
                return;
            }
            request.getSession().setAttribute("openid", openid);
            request.getSession().setAttribute("access_token", access_token);
            logger.debug("openid===" + openid);
            logger.debug("access_token===" + access_token);
            String sessionid = getRequest().getSession().getId();
            //去数据库查询有没有这个 openid
            CustomerInfo customerInfoServiceOne = iCustomerInfoService.getOne(new QueryWrapper<CustomerInfo>().eq("openid", openid));
            //如果没有这一个用户,则创建
            if (customerInfoServiceOne == null) {
                CustomerInfo customerInfo = new CustomerInfo();
                //省略实体set方法
                boolean save = registerService.register(customerInfo);
                if (save) {
                    logger.debug("首次认证:http://m.huerdai.net");
                    redisTemplate.opsForValue().set(sessionid, customerInfoServiceOne.getCustomerId());
//                    response.sendRedirect("http://m.huerdai.net/index.html");
                    response.sendRedirect("http://m.huerdai.net/html/bind-tel.html");
                    return;
                } else {
                    logger.debug("认证失败!");
                    response.sendRedirect("http://m.huerdai.net/error.html");
                    return;
                }
            } else {
                //已经授权过,没有绑定手机号,也是直接跳转到首页
                redisTemplate.opsForValue().set(sessionid, customerInfoServiceOne.getCustomerId());
                if (customerInfoServiceOne.getMobilePhone() == null) {
                    logger.debug("已经授权过,没有绑定手机号,也是直接跳转到首页");
                    //并且将用户信息存到Redis中
//                    response.sendRedirect("http://m.huerdai.net/index.html");
                    response.sendRedirect("http://m.huerdai.net/html/bind-tel.html");
                    return;
                } else {
                    //已经授权过,并且已经绑定手机号
                    logger.debug("有openid的跳转http://m.huerdai.net222222");
                    response.sendRedirect("http://m.huerdai.net/index.html");
                    return;
                }
            }
        } else {
            logger.debug("code获取失败!====" + code);
            // return new ModelAndView("redirect:http://m.huerdai.net/error.html");
            response.sendRedirect("http://m.huerdai.net/error.html");
        }
    }

到这里就微信登录并且获取用户信息就算完成了,


然后我遇到一个问题就是用户首次登录进来的时候会报openid找不到异常,第二次进来就好了,也没有其他报错信息,期待有大佬路过指正问题原因,感激不尽!


这之间其他的一些问题异常和容易碰到的坑以后有时间再总结!

目录
相关文章
|
3天前
|
数据采集 人工智能 Java
Java产科专科电子病历系统源码
产科专科电子病历系统,全结构化设计,实现产科专科电子病历与院内HIS、LIS、PACS信息系统、区域妇幼信息平台的三级互联互通,系统由门诊系统、住院系统、数据统计模块三部分组成,它管理了孕妇从怀孕开始到生产结束42天一系列医院保健服务信息。
14 4
|
9天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
33 2
|
13天前
|
人工智能 监控 数据可视化
Java智慧工地信息管理平台源码 智慧工地信息化解决方案SaaS源码 支持二次开发
智慧工地系统是依托物联网、互联网、AI、可视化建立的大数据管理平台,是一种全新的管理模式,能够实现劳务管理、安全施工、绿色施工的智能化和互联网化。围绕施工现场管理的人、机、料、法、环五大维度,以及施工过程管理的进度、质量、安全三大体系为基础应用,实现全面高效的工程管理需求,满足工地多角色、多视角的有效监管,实现工程建设管理的降本增效,为监管平台提供数据支撑。
32 3
|
19天前
|
运维 自然语言处理 供应链
Java云HIS医院管理系统源码 病案管理、医保业务、门诊、住院、电子病历编辑器
通过门诊的申请,或者直接住院登记,通过”护士工作站“分配患者,完成后,进入医生患者列表,医生对应开具”长期医嘱“和”临时医嘱“,并在电子病历中,记录病情。病人出院时,停止长期医嘱,开具出院医嘱。进入出院审核,审核医嘱与住院通过后,病人结清缴费,完成出院。
55 3
|
21天前
|
小程序 前端开发 算法
|
26天前
|
Java API 开发者
Java如何实现企业微信审批流程
大家好,我是V哥。本文分享如何在企业微信中实现审批流程,通过调用企业微信的开放API完成。主要内容包括获取Access Token、创建审批模板、发起审批流程和查询审批结果。提供了一个Java示例代码,帮助开发者快速上手。希望对你有帮助,关注V哥爱编程,编码路上同行。
|
24天前
|
JavaScript Java 项目管理
Java毕设学习 基于SpringBoot + Vue 的医院管理系统 持续给大家寻找Java毕设学习项目(附源码)
基于SpringBoot + Vue的医院管理系统,涵盖医院、患者、挂号、药物、检查、病床、排班管理和数据分析等功能。开发工具为IDEA和HBuilder X,环境需配置jdk8、Node.js14、MySQL8。文末提供源码下载链接。
|
27天前
|
移动开发 前端开发 JavaScript
java家政系统成品源码的关键特点和技术应用
家政系统成品源码是已开发完成的家政服务管理软件,支持用户注册、登录、管理个人资料,家政人员信息管理,服务项目分类,订单与预约管理,支付集成,评价与反馈,地图定位等功能。适用于各种规模的家政服务公司,采用uniapp、SpringBoot、MySQL等技术栈,确保高效管理和优质用户体验。
|
1月前
|
JSON 小程序 JavaScript
uni-app开发微信小程序的报错[渲染层错误]排查及解决
uni-app开发微信小程序的报错[渲染层错误]排查及解决
524 7
|
1月前
|
小程序 JavaScript 前端开发
uni-app开发微信小程序:四大解决方案,轻松应对主包与vendor.js过大打包难题
uni-app开发微信小程序:四大解决方案,轻松应对主包与vendor.js过大打包难题
639 1
下一篇
无影云桌面