【详解】springboot 微信授权网页登录获取用户信息

3 篇文章 0 订阅
1 篇文章 0 订阅

(一)准备阶段

1、先看看官方给的文档

2、准备一个域名服务器资源,因为微信公众号和微信回调都需要域名

3、准备一个微信测试公众号

(二)代码阶段

1、先给上面提供一个checkToken方法

2、编写微信授权方法和获取用户信息方法

(一)准备阶段

1、先看看官方给的文档

【官方文档地址】

根据官方文档,主要流程如下:

(1)引导用户进入授权页面同意授权,获取code 

(2)通过code换取网页授权access_token(与基础支持中的access_token不同) 

(3)刷新access_token(如果有需要)

(3)通过网页授权access_token和openid获取用户基本信息

2、准备一个域名服务器资源,因为微信公众号和微信回调都需要域名

本人没有域名,为了本地开发方便,使用了一个内网穿刺工具ngrok(免费使用)

【ngrok下载地址】

自己下载下来,双击ngrok.exe运行,然后输入命令,例如:ngrok http localhost:8087,8087为自己项目设置的端口号

其中 http://7ca0c439f61c.ngrok.io 为此次生成的域名。

注意:每次生成域名不一样如果关闭窗口,域名失效,要重新生成,每次在线的持续时间为8小时,时间过了可关闭窗口再次打开重新生成域名

3、准备一个微信测试公众号

【微信测试公众平台地址】

直接用微信扫描登录

该页面往下拉

可以使用自己的微信直接扫描关注即可

页面再往下拉

点击修改,填入上面生成的域名,然后确定

页面往上拉,在页面开始的地方有个输入URL和Token的地方(这一步没有也可以)

token可以随意填写,url为域名下你的项目地址,例如:

 http://7ca0c439f61c.ngrok.io/checkToken  (使用自己的域名)

前提是你的本地项目和域名生成器都在运行,先别着急点提交,因为项目要提供checkToken方法

(二)代码阶段

1、先给上面提供一个checkToken方法

    /**
     * 用于给微信验证token
     * @param request
     * @param response
     * @return
     * @throws IOException
     * */
    @RequestMapping("/checkToken")
    public String checkToken(HttpServletRequest request,HttpServletResponse response) throws IOException {
        // 微信加密签名
        String signature = request.getParameter("signature");
        // 时间戳
        String timestamp = request.getParameter("timestamp");
        // 随机数
        String nonce = request.getParameter("nonce");
        // 随机字符串
        String echostr = request.getParameter("echostr");
        if (SignUtil.checkSignature(signature, timestamp, nonce)) {
            System.out.println("校验token成功");
            return echostr;
        }else{
            System.out.println("校验token不成功");
            return  null;
        }
    }

上述方法用到的SignUtil工具类

/**
 * 验证微信token
 */
public class SignUtil {
    private static String token = "45j5IoDekLAT";//填你自己的,和公众号填写要一致
    public static boolean checkSignature(String signature, String timestamp, String nonce) {
        String[] paramArr = new String[] { token, timestamp, nonce };
        Arrays.sort(paramArr);
        String content = paramArr[0].concat(paramArr[1]).concat(paramArr[2]);
        String ciphertext = null;
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-1");
            byte[] digest = md.digest(content.toString().getBytes());
            ciphertext = byteToStr(digest);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return ciphertext != null ? ciphertext.equals(signature.toUpperCase()) : false;
    }

    private static String byteToStr(byte[] byteArray) {
        String strDigest = "";
        for (int i = 0; i < byteArray.length; i++) {
            strDigest += byteToHexStr(byteArray[i]);
        }
        return strDigest;
    }

    private static String byteToHexStr(byte mByte) {
        char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
        char[] tempArr = new char[2];
        tempArr[0] = Digit[(mByte >>> 4) & 0X0F];
        tempArr[1] = Digit[mByte & 0X0F];
        String s = new String(tempArr);
        return s;
    }

}

在确保域名生成工具和项目成功运行的前提下,可以点击准备阶段最后一步提交按钮

2、编写微信授权方法和获取用户信息方法

/**
     * 公众号微信登录授权
     */
    @RequestMapping("/wxLogin")
    public void wxLogin(HttpServletResponse response) throws IOException {
        //这个url的域名必须在公众号中进行注册验证,这个地址是成功后的回调地址
        String backUrl = "http://7ca0c439f61c.ngrok.io/callback";//使用自己的域名
        // 第一步:用户同意授权,获取code
        //请求地址  snsapi_base   snsapi_userinfo
        String url = "https://open.weixin.qq.com/connect/oauth2/authorize" +
                "?appid=" + HttpClientUtil.APPID +
                "&redirect_uri=" + URLEncoder.encode(backUrl,"utf-8") +
                "&response_type=code" +
                "&scope=snsapi_userinfo" +
                "&state=STATE#wechat_redirect";
        logger.info("forward重定向地址{" + url + "}");
        //必须重定向,否则不能成功
        response.sendRedirect(url);
    }

    /**
     * 公众号微信登录授权回调函数
     */
    @RequestMapping("/callback")
    public UserLoginRes callback(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        UserLoginRes userLoginRes = new UserLoginRes();
        try{
            WXUserInfoReq weixinUserInfo = new WXUserInfoReq();
            /*start 获取微信用户基本信息*/
            String code = req.getParameter("code");
            //第二步:通过code换取网页授权access_token
            String url = "https://api.weixin.qq.com/sns/oauth2/access_token?"
                    + "appid=" + HttpClientUtil.APPID
                    + "&secret=" + HttpClientUtil.APPSECRET
                    + "&code=" + code
                    + "&grant_type=authorization_code";
            System.out.println(url);

            String result = HttpClientUtil.doGet(url);
            JSONObject jsonObject = JSON.parseObject(result);

            /*
         {   "access_token":"ACCESS_TOKEN",
            "expires_in":7200,
            "refresh_token":"REFRESH_TOKEN",
            "openid":"OPENID",
            "scope":"SCOPE" 
           }
         */
              String openid = jsonObject.getString("openid");
              String access_token = jsonObject.getString("access_token");

            //第三步验证access_token是否失效;
            String chickUrl = "https://api.weixin.qq.com/sns/auth?access_token="
                    + access_token + "&openid=" + openid;
            String resultInfo = HttpClientUtil.doGet(chickUrl);
            JSONObject chickuserInfo = JSON.parseObject(resultInfo);
            System.out.println(chickuserInfo.toString());
            if (!"0".equals(chickuserInfo.getString("errcode"))) {
                String refreshInfo1 = HttpClientUtil.doGet(chickUrl);
                JSONObject refreshInfo = JSON.parseObject(refreshInfo1);
             /*
              { "access_token":"ACCESS_TOKEN",
                "expires_in":7200,
                "refresh_token":"REFRESH_TOKEN",
                "openid":"OPENID",
                "scope":"SCOPE" }
             */
                access_token = refreshInfo.getString("access_token");
            }

            // 第四步:拉取用户信息
            String infoUrl = "https://api.weixin.qq.com/sns/userinfo?access_token=" + access_token
                    + "&openid=" + openid
                    + "&lang=zh_CN";
            JSONObject userInfo = JSON.parseObject(HttpClientUtil.doGet(infoUrl));
            /*
         {  "openid":" OPENID",
            "nickname": NICKNAME,
            "sex":"1",
            "province":"PROVINCE"
            "city":"CITY",
            "country":"COUNTRY",
            "headimgurl": "http://wx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/46",
            "privilege":[ "PRIVILEGE1" "PRIVILEGE2"     ],
            "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
           }
         */
            System.out.println(userInfo.getString("openid") + ":" + userInfo.getString("nickname") +":" + userInfo.getString("sex"));
        }catch (Exception e){
            e.printStackTrace();
            userLoginRes.setResult("NO");
            userLoginRes.setRtnErrId("ERROR");
            userLoginRes.setRtnErrMsg(e.getMessage());
        }
        return userLoginRes;
    }

使用到的HttpClientUtil工具类

public class HttpClientUtil {
    //appid、secret为自己公众号平台的appid和secret
    public static final String APPID="xxxxxxx";
    public static final String APPSECRET ="xxxxxxx"; 

    public static String doGet(String url, Map<String, String> param) {
        // 创建Httpclient对象
        CloseableHttpClient httpclient = HttpClients.createDefault();

        String resultString = "";
        CloseableHttpResponse response = null;
        HttpGet httpGet = null;
        try {
            // 创建uri
            URIBuilder builder = new URIBuilder(url);
            if (param != null) {
                for (String key : param.keySet()) {
                    builder.addParameter(key, param.get(key));
                }
            }
            URI uri = builder.build();
            // 创建http GET请求
            httpGet = new HttpGet(uri);
            httpGet.setHeader("Host", "api.weixin.qq.com");
            httpGet.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko");
            httpGet.setHeader("Accept", "text/html, application/xhtml+xml, */*");
            httpGet.setHeader("Accept-Encoding", "gzip, deflate, br");
            httpGet.setHeader("Connection", "keep-alive");
            httpGet.setHeader("Accept-Language", "zh-CN");
            httpGet.setHeader("Cache-Control", "no-cache");

            // 执行请求
            response = httpclient.execute(httpGet);
            // 判断返回状态是否为200
            if (response.getStatusLine().getStatusCode() == 200) {
                resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
                httpGet.releaseConnection();
                httpclient.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return resultString;
    }

    public static String doGet(String url) {
        return doGet(url, null);
    }

    public static String doPost(String url, Map<String, String> param) {
        // 创建Httpclient对象
        CloseableHttpClient httpClient = HttpClients.createDefault();
        CloseableHttpResponse response = null;
        String resultString = "";
        try {
            // 创建Http Post请求
            HttpPost httpPost = new HttpPost(url);
            // 创建参数列表
            if (param != null) {
                List<NameValuePair> paramList = new ArrayList<>();
                for (String key : param.keySet()) {
                    paramList.add(new BasicNameValuePair(key, param.get(key)));
                }
                // 模拟表单
                UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList);
                httpPost.setEntity(entity);
            }
            // 执行http请求
            response = httpClient.execute(httpPost);
            resultString = EntityUtils.toString(response.getEntity(), "utf-8");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                response.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return resultString;
    }

    public static String doPost(String url) {
        return doPost(url, null);
    }

    public static String doPostJson(String url, String json) {
        // 创建Httpclient对象
        CloseableHttpClient httpClient = HttpClients.createDefault();
        CloseableHttpResponse response = null;
        String resultString = "";
        try {
            // 创建Http Post请求
            HttpPost httpPost = new HttpPost(url);
            // 创建请求内容
            StringEntity entity = new StringEntity(json, ContentType.APPLICATION_JSON);
            httpPost.setEntity(entity);
            // 执行http请求
            response = httpClient.execute(httpPost);
            resultString = EntityUtils.toString(response.getEntity(), "utf-8");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                response.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return resultString;
    }

    public static String doGetStr(String httpurl) {
        HttpURLConnection connection = null;
        InputStream is = null;
        BufferedReader br = null;
        String result = null;// 返回结果字符串
        try {
            // 创建远程url连接对象
            URL url = new URL(httpurl);
            // 通过远程url连接对象打开一个连接,强转成httpURLConnection类
            connection = (HttpURLConnection) url.openConnection();
            // 设置连接方式:get
            connection.setRequestMethod("GET");
            // 设置连接主机服务器的超时时间:15000毫秒
            connection.setConnectTimeout(15000);
            // 设置读取远程返回的数据时间:60000毫秒
            connection.setReadTimeout(60000);
            //设置请求头
            connection.setRequestProperty("Host", "api.weixin.qq.com");
            connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko");
            connection.setRequestProperty("Accept", "text/html, application/xhtml+xml, */*");
            connection.setRequestProperty("Accept-Encoding", "gzip, deflate, br");
            connection.setRequestProperty("Connection", "keep-alive");
            connection.setRequestProperty("Accept-Language", "zh-CN");
            connection.setRequestProperty("Cache-Control", "no-cache");

            // 发送请求
            connection.connect();
            // 通过connection连接,获取输入流
            if (connection.getResponseCode() == 200) {
                is = connection.getInputStream();
                // 封装输入流is,并指定字符集
                br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
                // 存放数据
                StringBuffer sbf = new StringBuffer();
                String temp = null;
                while ((temp = br.readLine()) != null) {
                    sbf.append(temp);
                    sbf.append("\r\n");
                }
                result = sbf.toString();
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 关闭资源
            if (null != br) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (null != is) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            connection.disconnect();// 关闭远程连接
        }
        return result;
    }

}

微信客户端直接访问 http://7ca0c439f61c.ngrok.io/wxlogin  即可(使用自己的域名)

欢迎提出你的意见

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

在水一fang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值