玩玩微信公众号Java版之六:微信网页授权

我们经常会访问一些网站,用微信登录的时候需要用到授权,那么微信网页授权是怎么一回事呢,一起来看看吧!

参考官方文档:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842

官方的文档有很详细的说明,这里就主要分析重要的几点:

第一,网页授权分类及说明:

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

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

第二,网页授权流程分为四步:

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

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

3、如果需要,开发者可以刷新网页授权access_token,避免过期

4、通过网页授权access_token和openid获取用户基本信息(支持UnionID机制)

了解到网页授权的这些知识,下面就开始去实现吧~

开始的准备工作:在接口配置中,设置对应的回调域名,地址:“开发 - 接口权限 - 网页服务 - 网页帐号 - 网页授权获取用户基本信息”的配置选项

由于我的是个人,因此使用测试账号的配置:

配置好了,就可以进行开发了,首先来看一下具体的流程:

其实很多功能点,前面已经实现过,只用改一下调用地址和参数即可。

首先,调用的定义链接:https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect

链接中需要使用urlEncode对链接进行处理,可以在工具类中添加一个转码方法:

 1     /**
 2      * 对URL地址进行EnCode处理
 3      * @param url
 4      * @return
 5      */
 6     public static String urlEnCode(String url)
 7     {
 8         String enCodedUrl = "";
 9
10         try
11         {
12             enCodedUrl = URLEncoder.encode(url, "utf-8");
13         }
14         catch (UnsupportedEncodingException e)
15         {
16             // TODO Auto-generated catch block
17             e.printStackTrace();
18             System.out.println("转码失败!");
19         }
20
21         return enCodedUrl;
22     }

另外将其他参数补充完整,可以得到一个访问链接。

在这里,可以结合之前学的菜单的处理,可以定义一个菜单进行专门的授权验证,这里需要改造上一节学到的点,具体如下:

 1     /**
 2      * 定义菜单属性
 3      * @return
 4      */
 5     private Menu getMenu()
 6     {
 7         Menu menu = new Menu();
 8
 9         // 建3个导航菜单
10         LevelMenu tLevelMenuOne = new LevelMenu();
11         tLevelMenuOne.setName("Damon");
12         LevelMenu tLevelMenuTwo = new LevelMenu();
13         tLevelMenuTwo.setName("Panou");
14         LevelMenu tLevelMenuThree = new LevelMenu();
15         tLevelMenuThree.setName("Papaw");
16
17         // 第一个导航菜单的子菜单
18         SubMenuButton tSubMenuButton_oneone = new SubMenuButton();
19         tSubMenuButton_oneone.setType(SysCon.WECHAT_MENU_TYPE_VIEW);
20         tSubMenuButton_oneone.setName("网页授权");
21         tSubMenuButton_oneone.setKey("11");
22         tSubMenuButton_oneone.setUrl(getAuthorUrl());
23
24         SubMenuButton tSubMenuButton_onetwo = new SubMenuButton();
25         tSubMenuButton_onetwo.setType(SysCon.WECHAT_MENU_TYPE_CLICK);
26         tSubMenuButton_onetwo.setName("swimming");
27         tSubMenuButton_onetwo.setKey("12");
28
29         // 加入导航菜单
30         tLevelMenuOne.setSub_button(new SubMenuButton[]
31         { tSubMenuButton_oneone, tSubMenuButton_onetwo });
32
33         // 第二 个导航菜单的子菜单
34         SubMenuButton tSubMenuButton_twoone = new SubMenuButton();
35         tSubMenuButton_twoone.setType(SysCon.WECHAT_MENU_TYPE_CLICK);
36         tSubMenuButton_twoone.setName("watching TV");
37         tSubMenuButton_twoone.setKey("21");
38
39         SubMenuButton tSubMenuButton_twotwo = new SubMenuButton();
40         tSubMenuButton_twotwo.setType(SysCon.WECHAT_MENU_TYPE_CLICK);
41         tSubMenuButton_twotwo.setName("play games");
42         tSubMenuButton_twotwo.setKey("22");
43
44         SubMenuButton tSubMenuButton_twothree = new SubMenuButton();
45         tSubMenuButton_twothree.setType(SysCon.WECHAT_MENU_TYPE_CLICK);
46         tSubMenuButton_twothree.setName("shopping");
47         tSubMenuButton_twothree.setKey("23");
48
49         // 加入导航菜单
50         tLevelMenuTwo.setSub_button(new SubMenuButton[]
51         { tSubMenuButton_twoone, tSubMenuButton_twotwo, tSubMenuButton_twothree });
52
53         // 第三个导航菜单的子菜单
54         SubMenuButton tSubMenuButton_threeone = new SubMenuButton();
55         tSubMenuButton_threeone.setType(SysCon.WECHAT_MENU_TYPE_CLICK);
56         tSubMenuButton_threeone.setName("cring");
57         tSubMenuButton_threeone.setKey("31");
58
59         SubMenuButton tSubMenuButton_threetwo = new SubMenuButton();
60         tSubMenuButton_threetwo.setType(SysCon.WECHAT_MENU_TYPE_CLICK);
61         tSubMenuButton_threetwo.setName("laughing");
62         tSubMenuButton_threetwo.setKey("32");
63
64         // 加入导航菜单
65         tLevelMenuThree.setSub_button(new SubMenuButton[]
66         { tSubMenuButton_threeone, tSubMenuButton_threetwo });
67
68         menu.setButton(new MenuButton[]
69         { tLevelMenuOne, tLevelMenuTwo, tLevelMenuThree });
70
71         return menu;
72
73     }
74
75     /**
76      * 获取微信网页授权页面链接
77      * @return
78      */
79     private String getAuthorUrl()
80     {
81         String uri = "http://damonhouse.iok.la/Servlet/WeChatAuthorService";
82
83         uri = WeChatUtil.urlEnCode(uri);
84
85         String authorUrl = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect";
86
87         authorUrl = authorUrl.replace("APPID", "appid").replace("REDIRECT_URI", uri).replace("SCOPE", "snsapi_userinfo");
88
89         return authorUrl;
90     }

先看一下具体效果:

点击会弹出一个授权的页面(由于我已经授权过,所以这里会自动登录)

这个时候后台还没有对应的处理,我们需要进行返回页面的处理,这里定义对应的service类,在doGet方法中进行处理:

 1 /**
 2  * 微信授权接口类
 3  * @author Damon
 4  */
 5 public class WeChatAuthorService extends HttpServlet
 6 {
 7
 8     @Override
 9     protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
10     {
11         // TODO Auto-generated method stub
12         System.out.println("授权成功,进行返回处理!");
13         req.setCharacterEncoding("utf-8");
14         resp.setCharacterEncoding("utf-8");
15
16         String code = req.getParameter("code");
17
18         String state = req.getParameter("state");
19
20         System.out.println("code :" + code + " and stat :" + state);
21
22         // 业务处理,获取授权用户信息
23         WeChatAuthorBL tWeChatAuthorBL = new WeChatAuthorBL();
24         AuthorUserInfo tAuthorUserInfo = tWeChatAuthorBL.getAuthorData(code, state);
25
26         req.setAttribute("nickname", tAuthorUserInfo.getNickname());
27         // 获取信息成功,回写成功页面
28         req.getRequestDispatcher("../wechat/authorsucc.jsp").forward(req, resp);
29
30     }
31
32     @Override
33     protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
34     {
35         // TODO Auto-generated method stub
36         super.doPost(req, resp);
37     }
38
39
40 }

可以从授权中获取到 code 和state(可自定义用与此处校验), 然后就是通过code来进行获取授权的用户信息:

从前面分析可知,需要先获取授权的acces_token,然后才能获取到授权的用户信息,那么结合前面2节内容,先定义2个实体类:

1、用户授权Token类

 1 /**
 2  * 用户授权Token
 3  * @author Damon
 4  */
 5 public class AuthorToken
 6 {
 7     // 网页授权接口调用凭证,注意:此access_token与基础支持的access_token不同
 8     private String access_token = "";
 9
10     // access_token接口调用凭证超时时间,单位(秒)
11     private int expires_in = 0;
12
13     // 用户刷新access_token ="";
14     private String refresh_token = "";
15
16     // 用户唯一标识,请注意,在未关注公众号时,用户访问公众号的网页,也会产生一个用户和公众号唯一的OpenID
17     private String openid = "";
18
19     // 用户授权的作用域,使用逗号(,)分隔
20     private String scope = "";
21
22     public String getAccess_token()
23     {
24         return access_token;
25     }
26
27     public void setAccess_token(String access_token)
28     {
29         this.access_token = access_token;
30     }
31
32     public int getExpires_in()
33     {
34         return expires_in;
35     }
36
37     public void setExpires_in(int expires_in)
38     {
39         this.expires_in = expires_in;
40     }
41
42     public String getRefresh_token()
43     {
44         return refresh_token;
45     }
46
47     public void setRefresh_token(String refresh_token)
48     {
49         this.refresh_token = refresh_token;
50     }
51
52     public String getOpenid()
53     {
54         return openid;
55     }
56
57     public void setOpenid(String openid)
58     {
59         this.openid = openid;
60     }
61
62     public String getScope()
63     {
64         return scope;
65     }
66
67     public void setScope(String scope)
68     {
69         this.scope = scope;
70     }
71
72 }

2、授权用户信息类

  1 /**
  2  * 通过网页授权获取的用户信息
  3  * @author Damon
  4  */
  5 public class AuthorUserInfo
  6 {
  7     // 用户的唯一标识
  8     private String openid = "";
  9
 10     // 用户昵称
 11     private String nickname = "";
 12
 13     // 用户的性别,值为1时是男性,值为2时是女性,值为0时是未知
 14     private String sex = "";
 15
 16     // 用户个人资料填写的省份
 17     private String province = "";
 18
 19     // 普通用户个人资料填写的城市
 20     private String city = "";
 21
 22     // 国家,如中国为CN
 23     private String country = "";
 24
 25     // 用户头像,最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像),用户没有头像时该项为空。若用户更换头像,原有头像URL将失效。
 26     private String headimgurl = "";
 27
 28     // 用户特权信息,json 数组,如微信沃卡用户为(chinaunicom)
 29     private List<String> privilege = new ArrayList<String>();
 30
 31     // 只有在用户将公众号绑定到微信开放平台帐号后,才会出现该字段。
 32     private String unionid = "";
 33
 34     public String getOpenid()
 35     {
 36         return openid;
 37     }
 38
 39     public void setOpenid(String openid)
 40     {
 41         this.openid = openid;
 42     }
 43
 44     public String getNickname()
 45     {
 46         return nickname;
 47     }
 48
 49     public void setNickname(String nickname)
 50     {
 51         this.nickname = nickname;
 52     }
 53
 54     public String getSex()
 55     {
 56         return sex;
 57     }
 58
 59     public void setSex(String sex)
 60     {
 61         this.sex = sex;
 62     }
 63
 64     public String getProvince()
 65     {
 66         return province;
 67     }
 68
 69     public void setProvince(String province)
 70     {
 71         this.province = province;
 72     }
 73
 74     public String getCity()
 75     {
 76         return city;
 77     }
 78
 79     public void setCity(String city)
 80     {
 81         this.city = city;
 82     }
 83
 84     public String getCountry()
 85     {
 86         return country;
 87     }
 88
 89     public void setCountry(String country)
 90     {
 91         this.country = country;
 92     }
 93
 94     public String getHeadimgurl()
 95     {
 96         return headimgurl;
 97     }
 98
 99     public void setHeadimgurl(String headimgurl)
100     {
101         this.headimgurl = headimgurl;
102     }
103
104     public List<String> getPrivilege()
105     {
106         return privilege;
107     }
108
109     public void setPrivilege(List<String> privilege)
110     {
111         this.privilege = privilege;
112     }
113
114     public String getUnionid()
115     {
116         return unionid;
117     }
118
119     public void setUnionid(String unionid)
120     {
121         this.unionid = unionid;
122     }
123
124 }

下一步,就是通过调用接口来实现我们的功能了~

  1     /**
  2      * 获取授权用户
  3      * @param code
  4      * @param state
  5      * @return
  6      */
  7     public AuthorUserInfo getAuthorData(String code, String state)
  8     {
  9
 10         // 1、通过code获取授权的authortoken
 11         AuthorToken tAuthorToken = getAuthorToken("appid", "appsecret", code);
 12
 13         // 2、通过获取的 access_token和 openid 获取用户信息
 14         AuthorUserInfo tAuthorUserInfo = getAuthorUserInfo(tAuthorToken.getAccess_token(), tAuthorToken.getOpenid());
 15
 16         return tAuthorUserInfo;
 17     }
 18
 19
 20     /**
 21      * 获取授权的access_token
 22      * @param appid
 23      * @param appsceret
 24      * @param code
 25      * @return
 26      */
 27     private AuthorToken getAuthorToken(String appid, String appsceret, String code)
 28     {
 29
 30         String path = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code ";
 31
 32         path = path.replace("APPID", appid).replace("SECRET", appsceret).replace("CODE", code);
 33
 34         AuthorToken tAuthorToken = new AuthorToken();
 35
 36         try
 37         {
 38             String strResp = WeChatUtil.doHttpsGet(path, "");
 39
 40             System.out.println(strResp);
 41
 42             // 解析获取的token信息
 43             Map<String, Object> tMap = WeChatUtil.jsonToMap(strResp);
 44
 45             System.out.println(tMap.toString());
 46
 47             // 封装 authortoken
 48
 49             tAuthorToken.setAccess_token((String) tMap.get("access_token"));
 50             tAuthorToken.setExpires_in(Integer.parseInt((String) tMap.get("expires_in")));
 51             tAuthorToken.setOpenid((String) tMap.get("openid"));
 52             tAuthorToken.setScope((String) tMap.get("scope"));
 53             tAuthorToken.setRefresh_token((String) tMap.get("refresh_token"));
 54
 55         }
 56         catch (HttpException e)
 57         {
 58             // TODO Auto-generated catch block
 59             e.printStackTrace();
 60         }
 61         catch (IOException e)
 62         {
 63             // TODO Auto-generated catch block
 64             e.printStackTrace();
 65         }
 66
 67         return tAuthorToken;
 68     }
 69
 70
 71     /**
 72      * 通过授权的access_token及用户的openid来拉取用户信息
 73      * @param access_token
 74      * @param openid
 75      * @return
 76      */
 77     private AuthorUserInfo getAuthorUserInfo(String access_token, String openid)
 78     {
 79         String path = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN";
 80
 81         path = path.replace("ACCESS_TOKEN", access_token).replace("OPENID", openid);
 82
 83         AuthorUserInfo tAuthorUserInfo = new AuthorUserInfo();
 84
 85         try
 86         {
 87             String strResp = WeChatUtil.doHttpsGet(path, "");
 88
 89             System.out.println(strResp);
 90
 91             // 解析获取的token信息
 92             Map<String, Object> tMap = WeChatUtil.jsonToMap(strResp);
 93
 94             System.out.println(tMap.toString());
 95
 96             // 封装 authortoken
 97             tAuthorUserInfo.setOpenid((String) tMap.get("openid"));
 98             tAuthorUserInfo.setNickname((String) tMap.get("nickname"));
 99             tAuthorUserInfo.setSex((String) tMap.get("sex"));
100             tAuthorUserInfo.setCountry((String) tMap.get("country"));
101             tAuthorUserInfo.setProvince((String) tMap.get("province"));
102             tAuthorUserInfo.setCity((String) tMap.get("city"));
103             tAuthorUserInfo.setHeadimgurl((String) tMap.get("headimgurl"));
104             tAuthorUserInfo.setPrivilege((List<String>) tMap.get("privilege"));
105             tAuthorUserInfo.setUnionid((String) tMap.get("unionid"));
106         }
107         catch (HttpException e)
108         {
109             // TODO Auto-generated catch block
110             e.printStackTrace();
111         }
112         catch (IOException e)
113         {
114             // TODO Auto-generated catch block
115             e.printStackTrace();
116         }
117
118         return tAuthorUserInfo;
119     }

这些搞定,我们就已经获取到了用户的信息了。 最后我们来给用户一个好的界面体验~

这里新增一个页面,显示获取到的用户昵称:

 1 <%@ page language="java" contentType="text/html; charset=GBK"
 2     pageEncoding="GBK"%>
 3 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 4 <html>
 5 <head>
 6 <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
 7 <title>damon‘s house</title>
 8 </head>
 9 <body>
10 <%
11 String nickname=request.getAttribute("nickname").toString();
12 %>
13 <table><tr><%=nickname %> 您好,感谢授权Damon的奇趣小屋!</tr></table>
14 </body>
15 </html>

来看一下效果吧~

微信网页授权,获取用户信息就到这啦~

时间: 2024-10-06 05:47:39

玩玩微信公众号Java版之六:微信网页授权的相关文章

玩玩微信公众号Java版之一:配置微信公众平台服务器信息

在进行微信公众平台开发前,前先做好准备工作,好了以后,我们可以开始啦! 第一.准备好服务端接口 定义一个http服务接口,主要分为如下几步: 1.创建一个servlet类,用来接收请求: 1 package com.wechat; 2 3 import java.io.IOException; 4 import java.io.PrintWriter; 5 6 import javax.servlet.ServletException; 7 import javax.servlet.http.H

玩玩微信公众号Java版之四:自定义公众号菜单

序: 微信公众号基本的菜单很难满足个性化及多功能的实现,那么微信能否实现自定菜单呢,具体的功能又如何去实现么?下面就来学习一下微信自定义公众号菜单吧! 自定义菜单接口可实现多种类型按钮,如下: 1.click:点击推事件用户点击click类型按钮后,微信服务器会通过消息接口推送消息类型为event的结构给开发者(参考消息接口指南),并且带上按钮中开发者填写的key值,开发者可以通过自定义的key值与用户进行交互:2.view:跳转URL用户点击view类型按钮后,微信客户端将会打开开发者在按钮中

玩玩微信公众号Java版之三:access_token及存储access_token

微信官方参考文档:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140183 基本说明: access_token是公众号的全局唯一接口调用凭据,公众号调用各接口时都需使用access_token.开发者需要进行妥善保存.access_token的存储至少要保留512个字符空间.access_token的有效期目前为2个小时,需定时刷新,重复获取将导致上次获取的access_token失效. 调用方式: 公众号可以使用App

玩玩微信公众号Java版之二:接收、处理及返回微信消息

前面已经配置了微信服务器,那么先开始最简单的接收微信消息吧~ 可以用我们的微信号来直接进行测试,下面先看测试效果图: 这是最基本的文本消息的接收.处理及返回,来看看是怎么实现的吧! 首先可以参考微信消息相关的接口文档:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140453 具体实现如下: 第一步,接收微信发送的文本消息入口: 1 /** 2 * 处理微信服务器发来的消息 3 */ 4 public void doPost

你所误解的微信公众号开发、以及微信公众号开发遇到的问题及详解

前言:有一星期没跟新博客了,最近太忙.项目赶进度就没把时间花在博客上:今天来说说所谓的微信公众号开发和填坑记录: 微信公众号:运行在微信终端的应用 (对于开发者来说比较爽的你只需考虑兼容微信浏览器,因为它是在微信浏览器环境下运行的) 微信公众号开发分为两部分: 一.传统开发(前后端分离) 推荐  页面量大的时候优点就尤其突出了 1. 微信首页 (即首页菜单.跳转链接.扫二维码.消息推送回复等功能) 不要慌  这些百分之90%都是后天来配置的,他们调用下微信公众平台提供的接口就ok了:为什么是后台

Java微信公众平台开发之OAuth2.0网页授权

根据官方文档点击查看在微信公众号请求用户网页授权之前,开发者需要先到公众平台官网中的"开发 - 接口权限 - 网页服务 - 网页帐号 - 网页授权获取用户基本信息"的配置选项中,修改授权回调域名.请注意,这里填写的是域名(是一个字符串),而不是URL,因此请勿加 http:// 等协议头,也不需要加具体的项目名,在域名空间的根目录放一个txt文件才能验证通过一.两种scope授权方式 以snsapi_base为scope发起的网页授权,是用来获取进入页面的用户的openid的,并且是静

微信公众号内H5调用微信支付国内服务商模式

最近在折微信公众号内H5用JSAPI调用微信支付,境内服务商版支付,微信支付给出的官方文档以及SDK不够详细,导至我们走了一些弯路,把他分享出来,我这边主要是用PHP开发,所以未加说的话示例都是PHP代码 微信的官方文档  https://pay.weixin.qq.com/wiki/doc/api/jsapi_sl.php?chapter=7_1 1.服务商模式下调用统一下单 独立商户模式统一下单:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php

.NET微信公众号开发-5.0微信支付

一.前言 在开始做这个功能之前,我们要做的第一件事情就是思考,如何做这个微信支付,从哪里开始,从哪里入手,官方的sdk说明什么的,有没有什么官方的demo,还有就是老板给我的一些资料齐全不,那些要申请的接口什么的都有没有. 经过自己的一些探索,在老板的催促下终于硬着头皮做完了这个,很坑很坑的微信支付,在此做一些总结,希望对你们有所帮助,本人能力有限,如果有什么说的不好,希望大家多多包涵. 二.开发前准备. 1.0微信支付官方开发者文档 2.0官方demo下载 我们用c#所以选择.net版本 不过

NET微信公众号开发-5.0微信支付(待测试)

开发前准备. 1.0微信支付官方开发者文档 2.0官方demo下载 我们用c#所以选择.net版本 不过这个官方的demo根本跑步起来 3.0官方demo运行起来解决方案 4.0微信支付官方.net版之坑你没商量 5.0开发前的微信公众平台的一些配置,请务必认真检查配置. 编码 做好了这些准备工作之后,我们知道微信支付有两种,1.原生态的,2.jsapi直接调用的,我项目中用到的是第二种 经过自己的一些业务逻辑处理,来到了我们的订单详情页面,现在需要去点击我们的支付按钮去支付,支付页面pay.a