微信公众号开发网页授权获得OPENID的过滤器

1.填写授权回调页面域名:

1.1获取微信公众平台测试账号

alt 获取微信公众平台测试账号
alt 获取微信公众平台测试账号

1.2对帐号进行接口配置填写

alt 对帐号进行接口配置填写
alt 对帐号进行接口配置填写

1.3填写授权回调页面域名

  • 注意域名填写不要加 http:// 或者 https://
    alt 填写授权回调页面域名
    alt 填写授权回调页面域名

2授权成功获得Openid

2.1用户同意授权,获取code

在确保微信公众账号拥有授权作用域<scope参数>的权限的前提下(服务号获得高级接口后,默认拥有scope参数中的snsapi_basesnsapi_userinfo),引导关注者打开如下页面:

https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect 
//若提示“该链接无法访问”,请检查参数是否填写错误,是否拥有scope参数对应的授权作用域权限。 

2.1.1封装普通url成授权url

  • 本人是采用过滤器的方式封装url引导用户访问上面授权链接:

      public class OpenidFilter implements Filter {
          private static String flag1 = "1";
          private static String flag2 = "2";
          @Override
          public void destroy() {
          }
      
          @Override
          public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
                  throws IOException, ServletException {
              //转换request 和 respond 
              HttpServletRequest request = (HttpServletRequest) req;
              HttpServletResponse response = (HttpServletResponse) resp;
              flag1 = request.getRequestURI();
              // 判断是否同一个路径封装成微信的路径再次访问
              System.out.println("是否同一个路径封装成微信的路径再次访问" + flag1.equals(flag2));
              if (!flag1.equals(flag2)) {
                  // 判断request中是否有openid
                  if (CheckUtil.isNullOrBlank((String) request.getSession().getAttribute("openid"))) {
                      flag2 = request.getRequestURI();
      
                      // 修改成微信的url
                      String url = WeixinUtil.AUTHORIZE_URL.replace("APPID", WeixinUtil.APPID)
                              .replace("SCOPE", WeixinUtil.SCOPR)
                              .replace("REDIRECT_URI", WeixinUtil.DOMAIN_NAME + request.getRequestURI());
                      System.out.println("过滤修改后的url:" + url);
                      //重定向url
                      response.sendRedirect(url);
                      return;
                  }
              }
              chain.doFilter(request, response);
          }
      
          @Override
          public void init(FilterConfig arg0) throws ServletException {
      
          }
      }
    
  • 此过滤器应该为一级调用,web.xml配置:

     <filter>
         <filter-name>openidFilter</filter-name>
         <filter-class>com.weixin.oauth.filter.OpenidFilter</filter-class>
     </filter>
     <filter-mapping>
         <filter-name>openidFilter</filter-name>
         <url-pattern>/*</url-pattern>
         <dispatcher>1</dispatcher>
     </filter-mapping>
    
  • 直接在微信Web开发工具输入需要封装的url:


    alt  使用微信开发工具输入url
    alt 使用微信开发工具输入url
  • 过滤修改后的url:

     https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx9240e5de6afdd7b1&redirect_uri=http://zhixiaoyi.nat300.top/weixinOAuth/OAuthServlet.do&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect

2.1.2授权访问获得code

  • 之后会进入授权页面:
alt  用户进行授权
alt 用户进行授权

2.2通过code获得openid

  • 在获得code之后需立即采用WeixinUtil通过code换取网页授权access_token。

这里通过code换取的是一个特殊的网页授权access_token,与基础支持中的access_token(该access_token用于调用其他接口)不同。公众号可通过下述接口来获取网页授权access_token。如果网页授权的作用域为snsapi_base,则本步骤中获取到网页授权access_token的同时,也获取到了openidsnsapi_base式的网页授权流程即到此为止。

  • 获得access_token的请求连接: https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code

  • 其返回JSON数据包如下:

    { "access_token":"ACCESS_TOKEN",    
      "expires_in":7200,    
      "refresh_token":"REFRESH_TOKEN",    
      "openid":"OPENID",    
      "scope":"SCOPE" }     
  • 获得code和openid的servlet:

     @WebServlet(name = "OAuthServlet.do", urlPatterns = { "/OAuthServlet.do" })
     public class OAuthServlet extends HttpServlet {
     
         private static final long serialVersionUID = 1L;
     
         public OAuthServlet() {
         }
     
         protected void doGet(HttpServletRequest request, HttpServletResponse response)
                 throws ServletException, IOException {
             doPost(request, response);
         }
     
         protected void doPost(HttpServletRequest request, HttpServletResponse response)
                 throws ServletException, IOException {
             // 得到code
             String code = request.getParameter("code");
             //先检测是否已经得到openid
             String openid = (String) request.getSession().getAttribute("openid");
             if(CheckUtil.isNullOrBlank(openid)){
                 //判断cede是否为空即是否需要访问获得openid
                 if (!CheckUtil.isNullOrBlank(code)) {
                     System.out.println("code:" + code);
                     //采用WeixinUtil通过code换取网页授权access_token
                     OAuthInfo oauthInfo = WeixinUtil.getAccessToken(WeixinUtil.APPID, WeixinUtil.APPSECRET, code);
                     request.getSession().setAttribute("openid", oauthInfo.getOpenId());
                 }
             }
             request.getRequestDispatcher("index.jsp").forward(request, response);
             System.out.println("openid:" + openid);
         }
     
     }
    
  • WeixinUtil代码如下:

    public class WeixinUtil {
        // 公众号id
        public static String APPID = "wx9240e5de6afdd7b1";
        // 公众号密钥
        public static String APPSECRET = "2de51d7fae9cb5f36d5468c15bc288fe";
        // 用户同意授权url,获取code
        public static String AUTHORIZE_URL = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect";
        // 通过code换取网页授权access_token的url
        public static String ACCESS_TOKEN_BY_CODE_URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";
        // 授权域名
        public static String DOMAIN_NAME = "http://zhixiaoyi.nat300.top";
        // url范围
        public static String SCOPR = "snsapi_userinfo";
    
        /**
         * Get请求
         * 
         * @param url
         * @return
         */
        public static JSONObject doGetStr(String url) {
            CloseableHttpClient httpClient = HttpClients.createDefault();
            HttpGet httpGet = new HttpGet(url);
            JSONObject jsonObject = null;
            try {
                HttpResponse httpRequest = httpClient.execute(httpGet);
                HttpEntity entity = httpRequest.getEntity();
    
                if (entity != null) {
                    String result = EntityUtils.toString(entity, "UTF-8");
                    jsonObject = JSONObject.fromObject(result);
                }
    
            } catch (ClientProtocolException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
    
            return jsonObject;
        }
    
        /**
         * Post请求
         * 
         * @param url
         * @param outStr
         * @return
         */
        public static JSONObject doPostStr(String url, String outStr) {
    
            CloseableHttpClient httpClient = HttpClients.createDefault();
            HttpPost httpPost = new HttpPost(url);
            JSONObject jsonObject = null;
            try {
                httpPost.setEntity(new StringEntity(outStr, "UTF-8"));
                HttpResponse httpRequest = httpClient.execute(httpPost);
                HttpEntity entity = httpRequest.getEntity();
    
                String result = EntityUtils.toString(entity, "UTF-8");
                jsonObject = JSONObject.fromObject(result);
    
            } catch (ClientProtocolException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
    
            return jsonObject;
        }
    
        /**
         * 网页授权获取openId第2步,根据code取得openId
         * 
         * @param appid
         *            公众号的唯一标识
         * @param secret
         *            公众号的appsecret密钥
         * @param code
         *            code为换取access_token的票据
         * @return
         */
        /**
         * 
         * 通过code获取access_token
         * 
         * @return
         */
        public static OAuthInfo getAccessToken(String appid, String secret, String code) {
            OAuthInfo oAuthInfo = new OAuthInfo();
            String url = ACCESS_TOKEN_BY_CODE_URL.replace("APPID", appid).replace("SECRET", secret).replace("CODE", code);
            JSONObject jsonObject = doGetStr(url);
            if (jsonObject != null) {
                oAuthInfo.setAccessToken(jsonObject.getString("access_token"));
                oAuthInfo.setOpenId(jsonObject.getString("openid"));
                oAuthInfo.setExpiresIn(jsonObject.getInt("expires_in"));
                oAuthInfo.setRefreshToken(jsonObject.getString("refresh_token"));
                oAuthInfo.setScope(jsonObject.getString("scope"));
            }
            return oAuthInfo;
        }
    
    }
  • 控制台输出结果:

     是否同一个路径封装成微信的路径再次访问false
     过滤修改后的url:https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx9240e5de6afdd7b1&redirect_uri=http://zhixiaoyi.nat300.top/weixinOAuth/OAuthServlet.do&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect
     是否同一个路径封装成微信的路径再次访问true
     code:051FhwC11h9UfM1y5xE11yjBC11FhwC6
     openid:ozlH6v1yu2otJOmT1BsD24d25xBU
    
  • 页面展示openid:

alt  页面展示openid
alt 页面展示openid
  • 用到的pojo:

      public class OAuthInfo {
      
          // 网页授权接口调用凭证
          private String accessToken;
      
          // access_token接口调用凭证超时时间
          private int expiresIn;
      
          // 用户刷新access_token
          private String refreshToken;
      
          // 用户唯一标识
          private String openId;
      
          // 用户授权的作用域
          private String scope;
      
          public String getAccessToken() {
              return accessToken;
          }
      
          public int getExpiresIn() {
              return expiresIn;
          }
      
          public String getRefreshToken() {
              return refreshToken;
          }
      
          public String getOpenId() {
              return openId;
          }
      
          public String getScope() {
              return scope;
          }
      
          public void setAccessToken(String accessToken) {
              this.accessToken = accessToken;
          }
      
          public void setExpiresIn(int expiresIn) {
              this.expiresIn = expiresIn;
          }
      
          public void setRefreshToken(String refreshToken) {
              this.refreshToken = refreshToken;
          }
      
          public void setOpenId(String openId) {
              this.openId = openId;
          }
      
          public void setScope(String scope) {
              this.scope = scope;
          }
      
          @Override
          public String toString() {
              return "OAuthInfo [accessToken=" + accessToken + ", expiresIn=" + expiresIn + ", refreshToken=" + refreshToken
                      + ", openId=" + openId + ", scope=" + scope + "]";
          }
          
      }
    

3.经验总结

推荐阅读更多精彩内容