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

时间:2021-12-02 04:09:47
我们经常会访问一些网站,用微信登录的时候需要用到授权,那么微信网页授权是怎么一回事呢,一起来看看吧!
 
 
官方的文档有很详细的说明,这里就主要分析重要的几点:
第一,网页授权分类及说明:
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对链接进行处理,可以在工具类中添加一个转码方法:

     /**
* 对URL地址进行EnCode处理
* @param url
* @return
*/
public static String urlEnCode(String url)
{
String enCodedUrl = ""; try
{
enCodedUrl = URLEncoder.encode(url, "utf-8");
}
catch (UnsupportedEncodingException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("转码失败!");
} return enCodedUrl;
}

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

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

     /**
* 定义菜单属性
* @return
*/
private Menu getMenu()
{
Menu menu = new Menu(); // 建3个导航菜单
LevelMenu tLevelMenuOne = new LevelMenu();
tLevelMenuOne.setName("Damon");
LevelMenu tLevelMenuTwo = new LevelMenu();
tLevelMenuTwo.setName("Panou");
LevelMenu tLevelMenuThree = new LevelMenu();
tLevelMenuThree.setName("Papaw"); // 第一个导航菜单的子菜单
SubMenuButton tSubMenuButton_oneone = new SubMenuButton();
tSubMenuButton_oneone.setType(SysCon.WECHAT_MENU_TYPE_VIEW);
tSubMenuButton_oneone.setName("网页授权");
tSubMenuButton_oneone.setKey("11");
tSubMenuButton_oneone.setUrl(getAuthorUrl()); SubMenuButton tSubMenuButton_onetwo = new SubMenuButton();
tSubMenuButton_onetwo.setType(SysCon.WECHAT_MENU_TYPE_CLICK);
tSubMenuButton_onetwo.setName("swimming");
tSubMenuButton_onetwo.setKey("12"); // 加入导航菜单
tLevelMenuOne.setSub_button(new SubMenuButton[]
{ tSubMenuButton_oneone, tSubMenuButton_onetwo }); // 第二 个导航菜单的子菜单
SubMenuButton tSubMenuButton_twoone = new SubMenuButton();
tSubMenuButton_twoone.setType(SysCon.WECHAT_MENU_TYPE_CLICK);
tSubMenuButton_twoone.setName("watching TV");
tSubMenuButton_twoone.setKey("21"); SubMenuButton tSubMenuButton_twotwo = new SubMenuButton();
tSubMenuButton_twotwo.setType(SysCon.WECHAT_MENU_TYPE_CLICK);
tSubMenuButton_twotwo.setName("play games");
tSubMenuButton_twotwo.setKey("22"); SubMenuButton tSubMenuButton_twothree = new SubMenuButton();
tSubMenuButton_twothree.setType(SysCon.WECHAT_MENU_TYPE_CLICK);
tSubMenuButton_twothree.setName("shopping");
tSubMenuButton_twothree.setKey("23"); // 加入导航菜单
tLevelMenuTwo.setSub_button(new SubMenuButton[]
{ tSubMenuButton_twoone, tSubMenuButton_twotwo, tSubMenuButton_twothree }); // 第三个导航菜单的子菜单
SubMenuButton tSubMenuButton_threeone = new SubMenuButton();
tSubMenuButton_threeone.setType(SysCon.WECHAT_MENU_TYPE_CLICK);
tSubMenuButton_threeone.setName("cring");
tSubMenuButton_threeone.setKey("31"); SubMenuButton tSubMenuButton_threetwo = new SubMenuButton();
tSubMenuButton_threetwo.setType(SysCon.WECHAT_MENU_TYPE_CLICK);
tSubMenuButton_threetwo.setName("laughing");
tSubMenuButton_threetwo.setKey("32"); // 加入导航菜单
tLevelMenuThree.setSub_button(new SubMenuButton[]
{ tSubMenuButton_threeone, tSubMenuButton_threetwo }); menu.setButton(new MenuButton[]
{ tLevelMenuOne, tLevelMenuTwo, tLevelMenuThree }); return menu; } /**
* 获取微信网页授权页面链接
* @return
*/
private String getAuthorUrl()
{
String uri = "http://damonhouse.iok.la/Servlet/WeChatAuthorService"; uri = WeChatUtil.urlEnCode(uri); 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"; authorUrl = authorUrl.replace("APPID", "appid").replace("REDIRECT_URI", uri).replace("SCOPE", "snsapi_userinfo"); return authorUrl;
}

先看一下具体效果:

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

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

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

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

 /**
* 微信授权接口类
* @author Damon
*/
public class WeChatAuthorService extends HttpServlet
{ @Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
{
// TODO Auto-generated method stub
System.out.println("授权成功,进行返回处理!");
req.setCharacterEncoding("utf-8");
resp.setCharacterEncoding("utf-8"); String code = req.getParameter("code"); String state = req.getParameter("state"); System.out.println("code :" + code + " and stat :" + state); // 业务处理,获取授权用户信息
WeChatAuthorBL tWeChatAuthorBL = new WeChatAuthorBL();
AuthorUserInfo tAuthorUserInfo = tWeChatAuthorBL.getAuthorData(code, state); req.setAttribute("nickname", tAuthorUserInfo.getNickname());
// 获取信息成功,回写成功页面
req.getRequestDispatcher("../wechat/authorsucc.jsp").forward(req, resp); } @Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
{
// TODO Auto-generated method stub
super.doPost(req, resp);
} }

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

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

1、用户授权Token类

 /**
* 用户授权Token
* @author Damon
*/
public class AuthorToken
{
// 网页授权接口调用凭证,注意:此access_token与基础支持的access_token不同
private String access_token = ""; // access_token接口调用凭证超时时间,单位(秒)
private int expires_in = 0; // 用户刷新access_token ="";
private String refresh_token = ""; // 用户唯一标识,请注意,在未关注公众号时,用户访问公众号的网页,也会产生一个用户和公众号唯一的OpenID
private String openid = ""; // 用户授权的作用域,使用逗号(,)分隔
private String scope = ""; public String getAccess_token()
{
return access_token;
} public void setAccess_token(String access_token)
{
this.access_token = access_token;
} public int getExpires_in()
{
return expires_in;
} public void setExpires_in(int expires_in)
{
this.expires_in = expires_in;
} public String getRefresh_token()
{
return refresh_token;
} public void setRefresh_token(String refresh_token)
{
this.refresh_token = refresh_token;
} public String getOpenid()
{
return openid;
} public void setOpenid(String openid)
{
this.openid = openid;
} public String getScope()
{
return scope;
} public void setScope(String scope)
{
this.scope = scope;
} }

2、授权用户信息类

 /**
* 通过网页授权获取的用户信息
* @author Damon
*/
public class AuthorUserInfo
{
// 用户的唯一标识
private String openid = ""; // 用户昵称
private String nickname = ""; // 用户的性别,值为1时是男性,值为2时是女性,值为0时是未知
private String sex = ""; // 用户个人资料填写的省份
private String province = ""; // 普通用户个人资料填写的城市
private String city = ""; // 国家,如中国为CN
private String country = ""; // 用户头像,最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像),用户没有头像时该项为空。若用户更换头像,原有头像URL将失效。
private String headimgurl = ""; // 用户特权信息,json 数组,如微信沃卡用户为(chinaunicom)
private List<String> privilege = new ArrayList<String>(); // 只有在用户将公众号绑定到微信开放平台帐号后,才会出现该字段。
private String unionid = ""; public String getOpenid()
{
return openid;
} public void setOpenid(String openid)
{
this.openid = openid;
} public String getNickname()
{
return nickname;
} public void setNickname(String nickname)
{
this.nickname = nickname;
} public String getSex()
{
return sex;
} public void setSex(String sex)
{
this.sex = sex;
} public String getProvince()
{
return province;
} public void setProvince(String province)
{
this.province = province;
} public String getCity()
{
return city;
} public void setCity(String city)
{
this.city = city;
} public String getCountry()
{
return country;
} public void setCountry(String country)
{
this.country = country;
} public String getHeadimgurl()
{
return headimgurl;
} public void setHeadimgurl(String headimgurl)
{
this.headimgurl = headimgurl;
} public List<String> getPrivilege()
{
return privilege;
} public void setPrivilege(List<String> privilege)
{
this.privilege = privilege;
} public String getUnionid()
{
return unionid;
} public void setUnionid(String unionid)
{
this.unionid = unionid;
} }

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

     /**
* 获取授权用户
* @param code
* @param state
* @return
*/
public AuthorUserInfo getAuthorData(String code, String state)
{ // 1、通过code获取授权的authortoken
AuthorToken tAuthorToken = getAuthorToken("appid", "appsecret", code); // 2、通过获取的 access_token和 openid 获取用户信息
AuthorUserInfo tAuthorUserInfo = getAuthorUserInfo(tAuthorToken.getAccess_token(), tAuthorToken.getOpenid()); return tAuthorUserInfo;
} /**
* 获取授权的access_token
* @param appid
* @param appsceret
* @param code
* @return
*/
private AuthorToken getAuthorToken(String appid, String appsceret, String code)
{ String path = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code "; path = path.replace("APPID", appid).replace("SECRET", appsceret).replace("CODE", code); AuthorToken tAuthorToken = new AuthorToken(); try
{
String strResp = WeChatUtil.doHttpsGet(path, ""); System.out.println(strResp); // 解析获取的token信息
Map<String, Object> tMap = WeChatUtil.jsonToMap(strResp); System.out.println(tMap.toString()); // 封装 authortoken tAuthorToken.setAccess_token((String) tMap.get("access_token"));
tAuthorToken.setExpires_in(Integer.parseInt((String) tMap.get("expires_in")));
tAuthorToken.setOpenid((String) tMap.get("openid"));
tAuthorToken.setScope((String) tMap.get("scope"));
tAuthorToken.setRefresh_token((String) tMap.get("refresh_token")); }
catch (HttpException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
} return tAuthorToken;
} /**
* 通过授权的access_token及用户的openid来拉取用户信息
* @param access_token
* @param openid
* @return
*/
private AuthorUserInfo getAuthorUserInfo(String access_token, String openid)
{
String path = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN"; path = path.replace("ACCESS_TOKEN", access_token).replace("OPENID", openid); AuthorUserInfo tAuthorUserInfo = new AuthorUserInfo(); try
{
String strResp = WeChatUtil.doHttpsGet(path, ""); System.out.println(strResp); // 解析获取的token信息
Map<String, Object> tMap = WeChatUtil.jsonToMap(strResp); System.out.println(tMap.toString()); // 封装 authortoken
tAuthorUserInfo.setOpenid((String) tMap.get("openid"));
tAuthorUserInfo.setNickname((String) tMap.get("nickname"));
tAuthorUserInfo.setSex((String) tMap.get("sex"));
tAuthorUserInfo.setCountry((String) tMap.get("country"));
tAuthorUserInfo.setProvince((String) tMap.get("province"));
tAuthorUserInfo.setCity((String) tMap.get("city"));
tAuthorUserInfo.setHeadimgurl((String) tMap.get("headimgurl"));
tAuthorUserInfo.setPrivilege((List<String>) tMap.get("privilege"));
tAuthorUserInfo.setUnionid((String) tMap.get("unionid"));
}
catch (HttpException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
} return tAuthorUserInfo;
}

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

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

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

来看一下效果吧~

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

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