码迷,mobileinhere.cn
首页 > 微信 > 详细

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

时间:2018-04-23 18:35:34      阅读:1709      评论:0      收藏:0      [点我收藏+]

标签:tps   etc   user   utf8编码   简单的   duti   conf   exce   简单   

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

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

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

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

技术分享图片

先说第一步获取code:

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

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

链接为:

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:

官网上给出的链接:

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 = "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协议) 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 = "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     }

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

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="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 = "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="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这种情况了,至少本人测试没有出现过。

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

标签:tps   etc   user   utf8编码   简单的   duti   conf   exce   简单   

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

(0)
(0)
   
举报
评论 一句话评论(0
0条  
登录后才能评论!
2014 mobileinhere.cn 版权所有 京icp备13008772号-2
华人娱乐注册