由于后期需要在微信里跳转网页将用户的openid以及其他信息和学工号绑定,所以需要在通过网页授权来获取用户的基本信息.还有另一种获取用户信息的接口是直接获取的,就无法和业务进行对接了.

获取code

获取code的网址为

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

这里的redirect_uri的就是自己的业务页面.在用户主动同意授权后,页面将跳转至 redirect_uri/?code=CODE&state=STATE.这个state参数貌似有点意思,我曾经想过用这个参数来传递学工号来着,然后在跳转后的页面绑定.但是后来又改成了先用学工号登录自己的网站,把学工号存在cookie里,在跳转后读取cookie然后绑定.这样顺便也利用cookie实现了一下自动登录之类的功能. 好了,接下来新建一个OAuth2Servlet类,来处理网页的参数和跳转自己的页面.

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse respons(
            throws ServletException,IOException {
        request.setCharacterEncoding("UTF-8");
        response.setCharacterEncoding("UTF-8");
        // 用户同意授权后,能获取到code
        String code = request.getParameter("code");
        }

所以可以向而知了,这个OAuth2Servlet就是我们的redirect_uri,需要在测试号里设置一下网址(测试号可以用ip),以确保可以访问.

用code 获取access_token

这里也要用到之前写的doGet()方法,请求的Http地址为

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

这里将处理网页的实现,放在一个新的WebUtil类中继承WechatUtil,便可以直接用父类的doGet(),doPost()和一些字段了.具体代码如下:

    public OAuth2AccessToken getOAuth2AccessToken(String code){
        OAuth2AccessToken oAuth2AccessToken=new OAuth2AccessToken();
        String url = WEB_ACCESS_TOKEN_URL.replace("APPID", getAPPID()).replace("SECRET", getAPPSECRET()).replace("CODE",code);
        JSONObject jsonObject = doGet(url);
        if (jsonObject != null) {
            oAuth2AccessToken.setAccess_token(jsonObject.getString("access_token"));
            oAuth2AccessToken.setExpires_in(jsonObject.getInt("expires_in"));
            oAuth2AccessToken.setRefresh_token(jsonObject.getString("refresh_token"));
            oAuth2AccessToken.setOpenid(jsonObject.getString("openid"));
            oAuth2AccessToken.setScope(jsonObject.getString("scope"));
        }
        return oAuth2AccessToken;
    }

这里有一个坑啊,因为此access_token,非彼access_token.这里通过code换取的是一个特殊的网页授权access_token,与基础支持中的access_token(该access_token用于调用其他接口)不同.所以微信为了安全又在这里搞了另一个token,来增大在网页获取用户信息的难度?

用access_token和openid获取用户基本信息

新建一个UserInfo实体类来储存用户信息,代码就不贴了.接着继续在WebUtil类中添加代码,依旧是doGet()方法,请求的链接是https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN:

    public UserInfo getUserInfo(String webAccessToken, String openid){
        UserInfo userInfo=new UserInfo();
        String url=USER_INFO_URL.replace("ACCESS_TOKEN",webAccessToken).replace("OPENID",openid);
        JSONObject jsonObject = doGet(url);
        if (jsonObject!=null) {
            userInfo.setOpenid(jsonObject.getString("openid"));
            userInfo.setNickname(jsonObject.getString("nickname"));
            userInfo.setSex(jsonObject.getString("sex"));
            userInfo.setProvince(jsonObject.getString("province"));
            userInfo.setCity(jsonObject.getString("city"));
            userInfo.setCountry(jsonObject.getString("country"));
            userInfo.setHeadimgurl(jsonObject.getString("headimgurl"));
            userInfo.setPrivilege(jsonObject.getString("privilege"));
        }
        return userInfo;
    }

这样就已经实现了获取用户的基本信息,但是还没有结束,再在OAuth2Servlet()类中调用以上的方法,

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException,IOException {
        request.setCharacterEncoding("UTF-8");
        response.setCharacterEncoding("UTF-8");
        // 用户同意授权后,能获取到code
        String code = request.getParameter("code");
        if (code!=null&&!code.equals("")) {
                WebUtil webUtil = new WebUtil();
                //通过code换取网页授权的access_token
                OAuth2AccessToken oAuth2AccessToken = webUtil.getOAuth2AccessToken(code);
                //access_token
                String access_token = oAuth2AccessToken.getAccess_token();
                //openid
                String openid = oAuth2AccessToken.getOpenid();
                //获取用户信息
                UserInfo userInfo = webUtil.getUserInfo(access_token, openid);
                //todo 可以改成跳转到profile.jsp页面,通过参数()来显示是否已经绑定
                request.setAttribute("UserInfo", userInfo);
                request.getRequestDispatcher("message.jsp").forward(request,response);
            }
    }

可以看到在经过一系列操作之后得到了userInfo对象,并且将他传递到下一个页面.

实现自己的跳转页面

message.jsp代码如下:

<%@ page language="java" pageEncoding="UTF-8"%>
<%@ page import="ObjectC.UserInfo"%>
<html>
<head>
	<title>账号设置</title>
	<meta name="viewport" content="width=device-width,user-scalable=0">
	<link rel="shortcut icon" href="home/favicon.ico">
	<style type="text/css">
		*{margin:0; padding:0}
		table{border:1px dashed #B9B9DD;font-size:12pt}
		td{border:1px dashed #B9B9DD;word-break:break-all; word-wrap:break-word;}
		#under{width: 200px;height: 20px;margin-top: 350px;}
	</style>
</head>
<body>
	<%
		UserInfo user = (UserInfo)request.getAttribute("UserInfo");
		if(null != user) {
		String name=user.getName();
		String openid=user.getOpenid();
		String schoolid=user.getSchoolid();
		String headImage=user.getHeadimgurl();
	%>

    <center>
	    <div id="users"><p>
    	  <%=name %><br>
    	  <%=schoolid%><br>
    	  <%=openid%><br>
    	  <%=headImage%><br>
           绑定成功!<br>
    	<a href="profile.jsp">返回个人设置</a>
	</center>

    <center>
	<div id="under">
	<p>Copyright © 2016-2017 Yappy Doggie</p>
	</div>
	</center>

	<%
		}
		else
			out.print("用户不同意授权,未获取到用户信息!");
	%>
</body>
</html>

主要是判断了一下用户是否授权,如果没有就显示"用户不同意授权,未获取到用户信息!"。这样基本的获取用户信息和跳转自己的页面就实现了。

最后

到现在终于写完了五篇,不能每个个细节都说的详细,但我也是看着开发文档和一些博客/视频,一步一步做出来的,虽然写的是垃圾代码,到目前为止也没有实现什么核心的业务逻辑,但是整个过程…..开心就好😂…..