微信公众号开发之网页授权登录及code been used 解决!

首先微信公众号开发网页授权登录使用环境:

开发工具:eclipse;服务器:tomcat8,开发语言:JAVA。

我写的网页授权登录时用开发者模式自定义view类型按钮点击跳转链接的。

微信网页授权登录首先以官方微信开发文档为准,大体共分为4步:

先说第一步获取code:

code说明:code作为换取access_token的票据,每次用户授权带上的code将不一样,code只能使用一次,5扽这未被使用自动过期。

微信公众开发文档给的有获取code的链接,建议直接复制来用,然后替换其中相应的参数即可。

链接为:

https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect

其中参数说明:

这官网上都有,这里展示是想说明一下scope参数,请注意看官网上给出的demo:

请注意微信授权登录scope两种redirect_url后面跟的链接使用的协议。

这个协议使用不当可能会在项目部署到服务器上测试时在安卓和ios上出现问题。

至此,以snsapi_base为scope发起的网页授权,是用来获取进入页面的用户的openid的,并且是静默授权并自动跳转到回调页的。用户感知的就是直接进入了回调页(往往是业务页面);

以snsapi_userinfo为scope发起的网页授权,是用来获取用户的基本信息的。但这种授权需要用户手动同意,并且由于用户同意过,所以无须关注,就可在授权后获取该用户的基本信息。

参数替换完毕如果以snsapi_userinfo为scope发起的网页授权,是在PC端点击菜单会跳出提示用户同意授权登录,如果用户未关注公众号时同样也会提示,示例页面:

如果是在移动端用户关注情况下则不会出现此页面。

如果用户同意授权,页面将跳转至 redirect_uri/?code=CODE&state=STATE,若跳转错误请根据日志输出的错误码在官网上查看相应的说明,附上官网上错误返回码说明:

然后是第二步根据链接传过来的code去获取网页授权access_token:

官网上给出的链接:

https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code

这个access_token和基本的access_token不同,具体请参考官网说明,这里给出获取网页授权access_token的JAVA实现方法:

 1 /**
 2      * 获取网页授权凭证
 3      *
 4      * @param appId 公众账号的唯一标识
 5      * @param appSecret 公众账号的密钥
 6      * @param code
 7      * @return WeixinAouth2Token
 8      */
 9     public static WeixinOauth2Token getOauth2AccessToken(String appId, String appSecret, String code) {
10         WeixinOauth2Token wat = null;
11         // 拼接请求地址
12         String requestUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";
13         requestUrl = requestUrl.replace("APPID", appId);
14         requestUrl = requestUrl.replace("SECRET", appSecret);
15         requestUrl = requestUrl.replace("CODE", code);
16         // 获取网页授权凭证
17         JSONObject jsonObject = CommonUtil.httpsRequest(requestUrl, "GET", null);
18         if (null != jsonObject) {
19             try {
20                 wat = new WeixinOauth2Token();
21                 wat.setAccessToken(jsonObject.getString("access_token"));
22                 wat.setExpiresIn(jsonObject.getInt("expires_in"));
23                 wat.setRefreshToken(jsonObject.getString("refresh_token"));
24                 wat.setOpenId(jsonObject.getString("openid"));
25                 wat.setScope(jsonObject.getString("scope"));
26             } catch (Exception e) {
27                 wat = null;
28                 int errorCode = jsonObject.getInt("errcode");
29                 String errorMsg = jsonObject.getString("errmsg");
30                 log.error("获取网页授权凭证失败 errcode:{} errmsg:{}", errorCode, errorMsg);
31             }
32         }
33         return wat;
34     }

需要的参数为开发者ID(AppID),开发者密码(AppSecret),和获取到的code。正确返回json数据包为:

然后第三步,如果需要的话进行,方法和第二步类似,所需链接官网给的有。

最后一步是获取用户的信息(需要scope为snsapi_userinfo,snsapi_base只能获取到用户的openId):

所需要的请求方法:

http:GET(请使用https协议) https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN

然后替换成相应的参数,JAVA代码为:

 1     /**
 2      * 通过网页授权获取用户信息
 3      *
 4      * @param accessToken 网页授权接口调用凭证
 5      * @param openId 用户标识
 6      * @return SNSUserInfo
 7      */
 8     public static SNSUserInfo getSNSUserInfo(String accessToken, String openId) {
 9         SNSUserInfo snsUserInfo = null;
10         // 拼接请求地址
11         String requestUrl = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN";
12         requestUrl = requestUrl.replace("ACCESS_TOKEN", accessToken).replace("OPENID", openId);
13         // 通过网页授权获取用户信息
14         JSONObject jsonObject = CommonUtil.httpsRequest(requestUrl, "GET", null);
15
16         if (null != jsonObject) {
17             try {
18                 snsUserInfo = new SNSUserInfo();
19                 // 用户的标识
20                 snsUserInfo.setOpenId(jsonObject.getString("openid"));
21                 // 昵称
22                 snsUserInfo.setNickname(jsonObject.getString("nickname"));
23                 // 性别(1是男性,2是女性,0是未知)
24                 snsUserInfo.setSex(jsonObject.getInt("sex"));
25                 // 用户所在国家
26                 snsUserInfo.setCountry(jsonObject.getString("country"));
27                 // 用户所在省份
28                 snsUserInfo.setProvince(jsonObject.getString("province"));
29                 // 用户所在城市
30                 snsUserInfo.setCity(jsonObject.getString("city"));
31                 // 用户头像
32                 snsUserInfo.setHeadImgUrl(jsonObject.getString("headimgurl"));
33             } catch (Exception e) {
34                 snsUserInfo = null;
35                 int errorCode = jsonObject.getInt("errcode");
36                 String errorMsg = jsonObject.getString("errmsg");
37                 log.error("获取用户信息失败 errcode:{} errmsg:{}", errorCode, errorMsg);
38             }
39         }
40         return snsUserInfo;
41     }

上面所述皆是根据微信公众号官网以及百度所写。另外还参考一篇很不错的微信公众号开发文档,可以说是带我入的门,给个链接:

http://www.cnblogs.com/liuhongfeng/p/4846260.html

下面说一下微信网页授权登录中遇到的code  been used问题:

我在微信网页授权登录写完之后开始测试,在保证代码的正确性与准确性后,打开微信公众号,点击自己定义跳转链接的菜单,并成功进入,但是在点击刷新或者回退是会报错,错误的信息就是code  been used。

官网上给出的说明很详细,code只能被使用一次,如果显示code  been used则说明code被重复使用了。

首先说一个简单的code  been used错误的产生:

有的开发者在写网页授权登录时会出现这样的页面:

这是在微信开发公众号上没有配置安全域名,导致微信网页授权登录时会显示这样的页面,url跳转了两次,传入的code被重复使用了,遇到这种的可以现在微信开发公众号里面配置安全域名。

然后说普遍遇到的code  been used问题。

基本思路时:当我点击菜单按钮进入页面时,先去sssion缓存中去那由code获取到的openId,如果openId不存在,则证明code为首次使用,可以根据传过来的code获取相应的access_token和openId。

如果存在,则直接使用获取到的openId去获取用户的一系列信息。

我用的时springMVC,简单实现代码为:

首先在开发者定义的菜单路径上配置域名和跳转的控制器方法:

前面模糊的是自己配置的域名,后面/weixin/redirect则是要跳转的方法

跳转到的方法为:

JAVA代码:

 1 /**获取用户openId
 2      * @throws IOException */
 3     @RequestMapping(value = "/redirect", method = RequestMethod.GET)
 4     public ModelAndView repairs(ModelAndView mav, HttpServletRequest request, HttpServletResponse resp) throws IOException{
 5         String openId = (String) request.getSession().getAttribute("openId");//先从缓存中获取通过code得到的openID
 6         System.out.println(openId);//测试输出openId
 7         if(openId==null){//判断openId是否为空(判断code是否为第一次被使用)
 8             RedirectUtils.redireUrl1(request, resp);//openid为空也就是code被第一次使用时跳转方法
 9              return null;
10         }
11             mav.addObject("openId",openId);//没有被使用时
12             mav.setViewName("/weixin/repairs");//返回要跳转的视图页面
13         return mav;
14     }
RedirectUtils.redireUrl1(request, resp);为重定向跳转的路径。JAVA代码:
 1 public static void redireUrl1(HttpServletRequest request,HttpServletResponse response){
 2         System.out.println("跳转");//测试是否跳转过来了
 3         String a="";
 4         if(request.getQueryString()!=null){
 5             a="?"+request.getQueryString();
 6         }
 7         String url = Base64.getBase64(request.getRequestURL()+a);//此为链接中带的一些参数  不需要可以不用写
 8         System.out.println(request.getRequestURL()+a);
 9          String basePath = WeChatConfig.URL+"weixin/wxyz?url="+url;//redirect_uri地址
10          System.out.println(basePath);
11             String urls="https://open.weixin.qq.com/connect/oauth2/authorize?appid=" + WeChatConfig.APP_ID+
12                     "&redirect_uri=" + CommonUtil.urlEncodeUTF8(basePath)+
13                     "&response_type=code" +
14                     "&scope=snsapi_userinfo" +
15                     "&state=STATE#wechat_redirect";
16             try {
17                 response.sendRedirect(urls);//重定向执行url
18             }catch(Exception e){
19                 e.printStackTrace();
20             }
21     }

其中Base64.getBase64为Base64加密方法,WeChatConfig.URL为你自己微信公众平台配置的安全域名,CommUtil.urlEncodeUTF8对重定向链接进行编码。

提供一下Base64方法中的加密解密方法,请先下载相应的jar包:

 1 **
 2  * Base64工具 CREATE 2016.12.14 form yjf
 3  *
 4  */
 5 public class Base64 {
 6     /**
 7      * Base64加密
 8      *
 9      */
10     @SuppressWarnings("restriction")
11     public static String getBase64(String value) {
12         byte[] bytes = null;
13         String basevalue = null;
14         try {
15             bytes = value.getBytes("utf-8");
16         } catch (UnsupportedEncodingException e) {
17             e.printStackTrace();
18         }
19         if (bytes != null) {
20             basevalue = new BASE64Encoder().encode(bytes);
21         }
22         return basevalue;
23     }
24
25     /**
26      * Base64解密
27      *
28      */
29     @SuppressWarnings("restriction")
30     public static String getFromBase64(String basevalue) {
31         byte[] bytes = null;
32         String result = null;
33         if (basevalue != null) {
34             BASE64Decoder decoder = new BASE64Decoder();
35             try {
36                 bytes = decoder.decodeBuffer(basevalue);
37                 result = new String(bytes, "utf-8");
38             } catch (Exception e) {
39                 e.printStackTrace();
40             }
41         }
42         return result;
43     }
44
45 }

然后时CommUtil.urlEncodeUTF8编码代码:

 1 /**
 2      * URL编码(utf-8)
 3      *
 4      * @param source
 5      * @return
 6      */
 7     public static String urlEncodeUTF8(String source) {
 8         String result = source;
 9         try {
10             result = java.net.URLEncoder.encode(source, "utf-8");
11         } catch (UnsupportedEncodingException e) {
12             e.printStackTrace();
13         }
14         return result;
15     }

然后方法执行response.sendRedirect(urls);跳转回wxyz方法进行获取一系列参数,代码为:

 1 @RequestMapping(value="/wxyz",method=RequestMethod.GET)
 2     public ModelAndView wxYz(ModelAndView mvc,HttpServletRequest req,HttpServletResponse response){
 3          System.out.println("微信验证");//测试是否跳转到此方法中
 4             String code=req.getParameter("code");//获取url参数中的code
 5             WeixinOauth2Token weixinOauth2Token  = AdvancedUtil.getOauth2AccessToken(WeChatConfig.APP_ID, WeChatConfig.APP_SECRET, code);
 6             if(weixinOauth2Token.getOpenId()!=null){
 7                 String openId = weixinOauth2Token.getOpenId();
 8                 req.getSession().setAttribute("openId",openId);//将获取到的openID存入session缓存中
 9                 System.out.println("openId"+openId);
10                 mvc.addObject("openId",openId);
11                 mvc.setViewName("redirect:/weixin/wxLogin");
12                 return mvc;
13             }
14             return null;
15     }

其中AdvancedUtil.getOauth2AccessToken方法时获取网页授权access_token 方法,代码为:

 1 /**
 2      * 获取网页授权凭证
 3      *
 4      * @param appId 公众账号的唯一标识
 5      * @param appSecret 公众账号的密钥
 6      * @param code
 7      * @return WeixinAouth2Token
 8      */
 9     public static WeixinOauth2Token getOauth2AccessToken(String appId, String appSecret, String code) {
10         WeixinOauth2Token wat = null;
11         // 拼接请求地址
12         String requestUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";
13         requestUrl = requestUrl.replace("APPID", appId);
14         requestUrl = requestUrl.replace("SECRET", appSecret);
15         requestUrl = requestUrl.replace("CODE", code);
16         // 获取网页授权凭证
17         JSONObject jsonObject = CommonUtil.httpsRequest(requestUrl, "GET", null);
18         if (null != jsonObject) {
19             try {
20                 wat = new WeixinOauth2Token();
21                 wat.setAccessToken(jsonObject.getString("access_token"));
22                 wat.setExpiresIn(jsonObject.getInt("expires_in"));
23                 wat.setRefreshToken(jsonObject.getString("refresh_token"));
24                 wat.setOpenId(jsonObject.getString("openid"));
25                 wat.setScope(jsonObject.getString("scope"));
26             } catch (Exception e) {
27                 wat = null;
28                 int errorCode = jsonObject.getInt("errcode");
29                 String errorMsg = jsonObject.getString("errmsg");
30                 log.error("获取网页授权凭证失败 errcode:{} errmsg:{}", errorCode, errorMsg);
31             }
32         }
33         return wat;
34     }

使用此方法替换上相应的参数即可。因为微信授权登录会跳转两次链接,所以当获取成功则跳转到wxLogin方法中进行验证:

 1 String bassPath1 = WeChatConfig.URL+"weixin/wxyz";//定义的路径
 2     @RequestMapping(value="wxLogin1",method=RequestMethod.GET)
 3     public ModelAndView wxLogin(HttpServletRequest request,HttpServletResponse response){
 4         String openId = (String) request.getSession().getAttribute("openId");//先从缓存中去拿openId
 5
 6         if(openId==null){//如果没有的话
 7             String url="https://open.weixin.qq.com/connect/oauth2/authorize?appid=" +  WeChatConfig.APP_ID +
 8                         "&redirect_uri=" + CommonUtil.urlEncodeUTF8(bassPath1)+
 9                         "&response_type=code" +
10                         "&scope=snsapi_userinfo" +
11                         "&state=STATE#wechat_redirect";
12             try {
13                 response.sendRedirect(url);
14             } catch (IOException e) {
15                 e.printStackTrace();
16             }
17
18         }else{
19
20             return new ModelAndView("weixin/repairs");//返回页面
21         }
22         return null;
23     }

至此,打开所需要的页面,无论时第一次进入还是刷新 都不会出现code been used这种情况了,至少本人测试没有出现过。

原文地址:https://www.cnblogs.com/ka-bu-qi-nuo/p/8920395.html

时间: 2024-10-10 14:30:51

微信公众号开发之网页授权登录及code been used 解决!的相关文章

C#微信公众号开发之网页授权oauth2.0获取用户基本信息(二)

C#微信公众号开发之网页授权oauth2.0获取用户基本信息(一) 中讲解了如果通过微信授权2.0snsapi_base获取已经关注用户的基本信息,然而很多情况下我们经常需要获取非关注用户的信息,方法如下: 第一步和之前讲的一样:获取code,但是scope使用方法是snsapi_userinfo; 第二步,根据code获取openid和access_token(此处的access_token是通过网页授权code换取的不是我们之前讲的全局的票据),代码: 1 /// <summary> 2

微信公众号开发系列-网页授权获取用户基本信息

OAuth2.0网页授权这个也是在做微信公众平台用到最多的,可以利用授权接口对自己平台内用户进行绑定,实现用户扫描码和微信分享.微信签到.微信商城购物等: 1.高级接口OAuth2.0网页授权设置 a.进入高级接口列表-OAuth2.0-点击修改设置授权域名,域名可以上一级域名和二级域名 b.填写要设置授权域名,我这里用的的是二级域名 体授权Url规则见下面详细描述,主要摘自微信公众平台开发文档,点击进入 2.网页授权获取用户基本信息说明 如果用户在微信中(Web微信除外)访问公众号的第三方网页

微信公众号开发之网页授权(获取用户信息)

这次暑假留在学校参与工作室的项目,对微信公众号比较感兴趣,所以参与这方面的学习研究. 昨天完成了关于网页授权,获取用户信息方面的功能,所以乘热打铁,写上一篇.实现本篇涉及的 功能,还需要完成一些基础.在写完这篇博客后,我会尽快补上. -------------------------废话不多说直入正题 需要的工具: 微信公众号(可以申请,但做开发的,可以申请测试号,申请详细不多说了) 服务器(可以自行购买,我使用的是新浪的sae.) 编辑器(随意,不做推荐) 微信公众号开发文档(地址) ----

微信公众号开发之网页授权认证获取用户的详细信息,实现自动登陆

原创声明:本文转来源本人另一博客[http://blog.csdn.net/liaohaojian/article/details/70175835]绝非他人处转载 从接触公众号到现在,开发维护了2个公众号,开发过程中遇到很多问题,现在把部分模块功能在这备案一下,做个总结也希望能给其他人帮助 工欲善其事,必先利其器,先看看开发公众号需要准备或了解什么 web开发工具:官方提供的开发工具,使用自己的微信号来调试微信网页授权.调试.检验页面的 JS-SDK 相关功能与权限,模拟大部分 SDK 的输入

C#微信公众号开发之网页授权oauth2.0获取用户基本信息

咨询 请加 QQ::QQ群: 在微信里面,非认证的公众号账号,只能通过在微信回复菜单单击等事件获取openid,但是认证的公众账号(之前认证的订阅号是不可以的,现在新开放了)可以直接在微信打开的链接中获取用户的基本信息包括openid.这里用一种比较简单的获取用户信息的网页授权的方式.注意:这中方式只可以获取关注用户的信息,非关注用户是不可以获取的. 一.获取Code  假设我们需要网页授权的页面的地址为redirect_uri 需要获取Code的话我们第一步是跳转到授权地址,我们第一步便是获取

微信公众号开发及时获取当前用户Openid及注意事项

目录 (一)微信公众号开发之VS远程调试 (二)微信公众号开发之基础梳理 (三)微信公众号开发之自动消息回复和自定义菜单 (四)微信公众号开发之网页授权获取用户基本信息 (五)微信公众号开发之网页中及时获取当前用户Openid及注意事项 前言 这篇主要是承接上篇的网页授权获取用户基本信息的后文,也是对第一种静默授权之后,用户点击公众号内链接时,如何再次取得当前用户的OpenId的大致讲解和一些注意事项. 看过上一篇的小伙伴都知道,我们在用户关注的时候就已经将该用户的基本信息存入数据库中,那么如果

微信公众号开发系列-获取微信OpenID

在微信开发时候在做消息接口交互的时候须要使用带微信加密ID(OpenId),下面讲讲述2中类型方式获取微信OpenID.接收事件推送方式和网页授权获取用户基本信息方式获取. 1.通过接收被动消息方式获取OpenId(接收事件推送方式).下面事件中都能够获取到OpenID 关注/取消关注事件 用户在关注与取消关注公众号时.微信会把这个事件推送到开发人员填写的URL.方便开发人员给用户下发欢迎消息或者做帐号的解绑. 微信server在五秒内收不到响应会断掉连接,而且又一次发起请求,总共重试三次 关于

PHP微信公众号开发常用功能

最近学习了关于微信公众号开发的相关知识,为了帮助自己更好的理解,在此重新再梳理一遍 更多关于微信公众号开发的功能可以参考微信公众平台的开发技术文档 完成开发者配置 第一步,需要在微信公众平台配置我们的服务器  在接口的文件需要写入以下代码以完成验证: class Wxapi { public function __construct() { $this->index(); } public function index() { $echostr = isset($_GET['echostr'])

微信公众号开发简单的网页授权登陆获取用户基本信息

由于业务需要,近期在做微信公众号开发,其中一个模块是微信用户点击个人中心访问可以得到次微信用户的头像昵称国家省份等基本信息. 但由于业务需求,这块功能暂时用不上了,但这功能的实现毕竟是自己花费几天时间搞出来的,觉得以后会用的上,暂且记录一下实现过程. 首先:获取用户信息的过程属于微信网页授权登陆,再做这一块之前请先阅读微信开发文档以熟悉基本的开发过程: https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842 微信开发文档