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

我们经常会访问一些网站,用微信登录的时候需要用到授权,那么微信网页授权是怎么一回事呢,一起来看看吧!
 
 
官方的文档有很详细的说明,这里就主要分析重要的几点:
第一,网页授权分类及说明:
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机制) 
 
了解到网页授权的这些知识,下面就开始去实现吧~
 
开始的准备工作:在接口配置中,设置对应的回调域名,地址:“开发 - 接口权限 - 网页服务 - 网页帐号 - 网页授权获取用户基本信息”的配置选项
由于我的是个人,因此使用测试账号的配置:
玩玩微信公众号Java版之六:微信网页授权

 

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

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

 

 

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

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

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

玩玩微信公众号Java版之六:微信网页授权
 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     }
View Code

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

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

玩玩微信公众号Java版之六:微信网页授权
 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     }
View Code

先看一下具体效果:

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

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

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

 

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

玩玩微信公众号Java版之六:微信网页授权
 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 }
View Code

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

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

1、用户授权Token类

玩玩微信公众号Java版之六:微信网页授权
 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 }
View Code

2、授权用户信息类

玩玩微信公众号Java版之六:微信网页授权
  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 }
View Code

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

玩玩微信公众号Java版之六:微信网页授权
  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     }
View Code

 

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

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

玩玩微信公众号Java版之六:微信网页授权
 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>
View Code

来看一下效果吧~

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

 

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

 

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

上一篇:微信平台开发——日历服务


下一篇:aiohttp请求