第三方平台授权登录

做这个之前搞懂微信公众平台和微信开发平台的区别

微信公众平台是我们常见的公众号,包括订阅号、服务号和企业号,主要用于不具备太强技术开放能力,拥有一定运营能力的品牌、商户、媒体以及个人,作为一个自媒体平台或者服务窗口来用,是面向更广大的人群使用的。

微信开放平台是一个开发者平台,针对的是有较强技术开发能力、能够研发同微信对接的应用的开发者来使用的,面向的是技术公司和开发者,不是面向所有人都可以使用的。

公众平台只有一个网页授权域名,一个公众号基本只能做一件事情,局限性太大了。假如一家大型公司。业务范围不只是一种,有衣食住行等等服务时,将其外包给其他公司做,那是不是要创建几个IP,几个域名?现在使用微信开放平台,只需要授权公众号列表,以及白名单设置即可,这样不同的公司,只需要专注于自己的模块功能,在同一个平台完成不同的功能,这样一个公众号可以实现多个功能。

微信开放平台,总结就一个字  坑  深渊巨坑   ,各种文档对于开发者来说十分不友好,很多描述都是模棱两可。掉进了一个坑爬起来还没走两步,又是一个坑。下面还是跟着文档来。

先来准备工作,配置好该有的信息,下载官方的代码,加密解密需要(坑)

第三方平台授权登录_第1张图片

白名单,就把IP地址填写好就行了,然后去这里下载官方提供的代码

第三方平台授权登录_第2张图片

流程:

 

小程序或者公众号授权给第三方平台的技术实现流程比较简单,以公众号为例,如下图所示:

第一步、推送component_verify_ticket协议

这个玩意巨鸡儿恶心,没有接口,官方说明不是很详细,用起来很难受,对推送来的信息进行解密,格式转换,获取

将获取到的信息写入到文件中token.properties便于存储读取数据,之后获取到的信息都写入到该文件中

package com.wlw.servlet;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import com.wlw.preAuth.WXBiz.AesException;
import com.wlw.preAuth.WXBiz.WXBizMsgCrypt;
import com.wlw.util.PropUtil;

@WebServlet("/wx9325b66ca913be2e/callback")  //平台的AppID,详细参考  授权事件接收URL   http://w.ngrok.xiaomiqiu.cn/we3/$APPID$/callback
public class callback extends HttpServlet{
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private static final String appid = "wx9325b66ca913be2e";
	private static final String token = "opentoken";
	private static final String decryptStr = "9VQuyIhjcJLH4Q84Zk6XkHhAdXU4Msg3N4uYJkqHHl2";
	private static final String secreet = "64e647c56e02e9a75fece3535b014acf";
	private static final String component_access_token_url = "https://api.weixin.qq.com/cgi-bin/component/api_component_token";
	private static final String pre_auth_code_url = "https://api.weixin.qq.com/cgi-bin/component/api_create_preauthcode?component_access_token=";
	private static final String auth_page_url = "https://mp.weixin.qq.com/cgi-bin/componentloginpage?";
	
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		doPost(req, resp);
	}
	
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		try {     //后台获取微信推送消息的时间,便于记录
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			System.out.println("本次微信推送请求时间:"+sdf.format(new Date()));
			Map map =  xmlToMap(req);  //将推送过来的XML的信息转换为map格式
		
			//进行请求参数解密   调用官方的代码中的方法进行解密
			WXBizMsgCrypt   crypt  =  new WXBizMsgCrypt(token, decryptStr, appid);
			String decryptStr =  crypt.decrypt(map.get("Encrypt"));
			/*上述解密之后为xml形式字符串,样例数据格式如下
			
				
				1531378645
				
				
			*/
			Map decryptStrMap = xmlStrToMap(decryptStr);
			//由于微信每10分钟会自动刷新ComponentVerifyTicket并通知,此处将解密后的ComponentVerifyTicket进行保存
			PropUtil.setProp("token.properties", "component_verify_ticket",decryptStrMap.get("ComponentVerifyTicket"));
			//返回suceess至微信请求端
			PrintWriter pWriter = resp.getWriter();
			pWriter.println("success");
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	        
	}
        //将微信推送的信息转换为map类型的方法
	public static Map xmlToMap(HttpServletRequest request) throws IOException, DocumentException {
		Map map = new HashMap<>();
		SAXReader reader = new SAXReader();
		InputStream in = request.getInputStream();
		Document document = reader.read(in);
		Element root = document.getRootElement();
		List list = root.elements();
		for (Element e : list) {   //遍历测试是否获取到了
			map.put(e.getName(), e.getText());  
			System.out.println(e.getName());
			System.out.println(e.getText());
		}
		in.close();
		return map;
	}
	//将解析处理后的XML格式的数据转换为Map格式
	public static Map xmlStrToMap(String xmlStr){
		SAXReader saxReader = new SAXReader();
		Document document;
		Map map = new HashMap<>();
		try {
			document = saxReader.read(new ByteArrayInputStream(xmlStr.getBytes("UTF-8")));
			Element root = document.getRootElement();
			List list = root.elements();
			for (Element e : list) {
				map.put(e.getName(), e.getText());
				System.out.println(e.getName());
				System.out.println(e.getText());
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		return  map;
	}
}



AppID,详细参考  授权事件接收URL   http://w.ngrok.xiaomiqiu.cn/we3/$APPID$/callback

public class callback extends HttpServlet{
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private static final String appid = "wx9325b66ca913be2e";
	private static final String token = "opentoken";
	private static final String decryptStr = "9VQuyIhjcJLH4Q84Zk6XkHhAdXU4Msg3N4uYJkqHHl2";
	private static final String secreet = "64e647c56e02e9a75fece3535b014acf";
	private static final String component_access_token_url = "https://api.weixin.qq.com/cgi-bin/component/api_component_token";
	private static final String pre_auth_code_url = "https://api.weixin.qq.com/cgi-bin/component/api_create_preauthcode?component_access_token=";
	private static final String auth_page_url = "https://mp.weixin.qq.com/cgi-bin/componentloginpage?";
	
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		doPost(req, resp);
	}
	
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		try {     //后台获取微信推送消息的时间,便于记录
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			System.out.println("本次微信推送请求时间:"+sdf.format(new Date()));
			Map map =  xmlToMap(req);  //将推送过来的XML的信息转换为map格式
		
			//进行请求参数解密   调用官方的代码中的方法进行解密
			WXBizMsgCrypt   crypt  =  new WXBizMsgCrypt(token, decryptStr, appid);
			String decryptStr =  crypt.decrypt(map.get("Encrypt"));
			/*上述解密之后为xml形式字符串,样例数据格式如下
			
				
				1531378645
				
				
			*/
			Map decryptStrMap = xmlStrToMap(decryptStr);
			//由于微信每10分钟会自动刷新ComponentVerifyTicket并通知,此处将解密后的ComponentVerifyTicket进行保存
			PropUtil.setProp("token.properties", "component_verify_ticket",decryptStrMap.get("ComponentVerifyTicket"));
			//返回suceess至微信请求端
			PrintWriter pWriter = resp.getWriter();
			pWriter.println("success");
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	        
	}
        //将微信推送的信息转换为map类型的方法
	public static Map xmlToMap(HttpServletRequest request) throws IOException, DocumentException {
		Map map = new HashMap<>();
		SAXReader reader = new SAXReader();
		InputStream in = request.getInputStream();
		Document document = reader.read(in);
		Element root = document.getRootElement();
		List list = root.elements();
		for (Element e : list) {   //遍历测试是否获取到了
			map.put(e.getName(), e.getText());  
			System.out.println(e.getName());
			System.out.println(e.getText());
		}
		in.close();
		return map;
	}
	//将解析处理后的XML格式的数据转换为Map格式
	public static Map xmlStrToMap(String xmlStr){
		SAXReader saxReader = new SAXReader();
		Document document;
		Map map = new HashMap<>();
		try {
			document = saxReader.read(new ByteArrayInputStream(xmlStr.getBytes("UTF-8")));
			Element root = document.getRootElement();
			List list = root.elements();
			for (Element e : list) {
				map.put(e.getName(), e.getText());
				System.out.println(e.getName());
				System.out.println(e.getText());
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		return  map;
	}
}
授权页面,点击连接进入回调地址,处理对应的逻辑
<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>




Insert title here


  点击授权

回调地址处理后续的业务

获取到了component_verify_ticket之后其他的不难了,就只是消息参数的组装和路径的填写,下面消息的组装就不使用实体类了,直接使用JSONObject

package com.wlw.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.wlw.util.PropUtil;
import com.wlw.util.wenxinUtil;
import net.sf.json.JSONObject;



@WebServlet("/auth")
public class auth extends HttpServlet{

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private static final String appid = "wx9325b66ca913be2e";                               //AppID
	private static final String token = "opentoken";                                        //消息校验Token
	private static final String decryptStr = "9VQuyIhjcJLH4Q84Zk6XkHhAdXU4Msg3N4uYJkqHHl2"; //消息加解密Key
	private static final String secreet = "****************";                               //AppSecret
	private static final String component_access_token_url = "https://api.weixin.qq.com/cgi-bin/component/api_component_token";  
	private static final String pre_auth_code_url = "https://api.weixin.qq.com/cgi-bin/component/api_create_preauthcode?component_access_token=";
	private static final String auth_page_url = "https://mp.weixin.qq.com/cgi-bin/componentloginpage?";
	
	
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		doPost(req, resp);
	}
	
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		try {
			//第一步:获取第三方平台调用凭据 component_access_token
			JSONObject json = new JSONObject();
			json.put("component_appid", appid);
			json.put("component_appsecret", secreet);
			json.put("component_verify_ticket", PropUtil.getProp("token.properties", "component_verify_ticket"));
			System.out.println("开始请求component_access_token_url,请求参数:"+json.toString());
	  	    JSONObject jsonResult = wenxinUtil.HttpRequest(component_access_token_url, "POST", json.toString()); 
	  	    PropUtil.setProp("token.properties", "component_access_token",jsonResult.get("component_access_token").toString());
	  		System.out.println("获取第三方开放平台access_token,返回结果:"+jsonResult.toString());

	  		//第二步:获取预授权码 pre_auth_code
	  		JSONObject preJson = new JSONObject();
	  		preJson.put("component_appid", appid);
			System.out.println("开始请求pre_auth_code_url,url地址为:"+pre_auth_code_url+jsonResult.get("component_access_token")+",请求参数:"+preJson.toString());
	  	    JSONObject preResult = wenxinUtil.HttpRequest(pre_auth_code_url+jsonResult.get("component_access_token"), "POST", preJson.toString());  
	  		System.out.println("获取预授权码接口返回结果:"+preResult.toString());
	  		String redirectUrl = auth_page_url+"component_appid="+appid+"&pre_auth_code="+preResult.get("pre_auth_code")+"&redirect_uri=http://w.ngrok.xiaomiqiu.cn/we3/nofiy&auth_type=3";
	  		System.out.println("重定向微信开放平台授权页面url:"+redirectUrl);
	  		resp.sendRedirect(redirectUrl);
	  		
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	        
	}
}

 

 

 

package com.wlw.servlet;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.wlw.util.PropUtil;
import com.wlw.util.wenxinUtil;
import net.sf.json.JSONObject;

@WebServlet("/nofiy")
public class nofiy extends HttpServlet{
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private static final String appid = "wx9325b66ca913be2e";
	private static final String token = "opentoken";
	private static final String decryptStr = "9VQuyIhjcJLH4Q84Zk6XkHhAdXU4Msg3N4uYJkqHHl2";
	private static final String secreet = "64e647c56e02e9a75fece3535b014acf";
	private static final String component_access_token_url = "https://api.weixin.qq.com/cgi-bin/component/api_component_token";
	private static final String pre_auth_code_url = "https://api.weixin.qq.com/cgi-bin/component/api_create_preauthcode?component_access_token=";
	private static final String auth_page_url = "https://mp.weixin.qq.com/cgi-bin/componentloginpage?";
	private static final String authorizer_access_token_url = "https://api.weixin.qq.com/cgi-bin/component/api_query_auth?component_access_token=";
	private static final String api_authorizer_token_url = "https:// api.weixin.qq.com /cgi-bin/component/api_authorizer_token?component_access_token=";
    private static final String api_get_authorizer_info_url="https://api.weixin.qq.com/cgi-bin/component/api_get_authorizer_info?component_access_token=";
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		doPost(req, resp);
	}
	
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		System.out.println("本次微信授权回调请求时间:"+sdf.format(new Date()));
		//获取微信回调返回的授权码集过期时间,并进行存储
		String auth_code = req.getParameter("auth_code");
		String expires_in = req.getParameter("expires_in");
		PropUtil.setProp("token.properties", "auth_code",auth_code);
		PropUtil.setProp("token.properties", "expires_in",expires_in);
		
		//4.使用授权码换取公众号或小程序的接口调用凭据和授权信息
		JSONObject json = new JSONObject();
		json.put("component_appid", appid);
		json.put("authorization_code", auth_code);
		JSONObject jsonResult = wenxinUtil.HttpRequest(authorizer_access_token_url, "POST", json.toString());
		//授权方的AppID    authorizer_appid  
		String authorizer_appid=jsonResult.get("authorizer_appid").toString();
		//授权方接口调用凭据    authorizer_access_token
		String authorizer_access_token=jsonResult.get("authorizer_access_token").toString();
		//接口调用凭据刷新令牌  authorizer_refresh_token
		String authorizer_refresh_token=jsonResult.get("authorizer_refresh_token").toString();
		//        (加上  授权方的AppID 区分)   
		PropUtil.setProp("token.properties", authorizer_appid+"authorizer_appid",authorizer_appid);
		PropUtil.setProp("token.properties", authorizer_appid+"authorizer_access_token",authorizer_access_token);
		PropUtil.setProp("token.properties", authorizer_appid+"authorizer_refresh_token",authorizer_refresh_token);
	   
		//5.获取(刷新)授权公众号或小程序的接口调用凭据(令牌)    
/*		JSONObject jsonObject = new JSONObject();
		jsonObject.put("component_appid", appid);
		jsonObject.put("authorizer_appid", authorizer_appid);
		jsonObject.put("authorizer_refresh_token", authorizer_refresh_token);
		JSONObject preResult=wenxinUtil.HttpRequest(api_authorizer_token_url, "POST", jsonObject.toString());
		//授权方令牌 authorizer_access_token
		String authorizer_access_token=preResult.get("authorizer_access_token").toString();
		//刷新令牌 authorizer_refresh_token
		String authorizer_refresh_token=preResult.get("authorizer_refresh_token").toString();
		PropUtil.setProp("token.properties", authorizer_appid+"authorizer_access_token",authorizer_access_token);
		PropUtil.setProp("token.properties", authorizer_appid+"authorizer_refresh_token",authorizer_refresh_token);*/
	
		//6.获取授权方的帐号基本信息
	    JSONObject object=new JSONObject();
	    object.put("component_appid", appid);
	    object.put("authorizer_appid", authorizer_appid);
	    JSONObject result=wenxinUtil.HttpRequest(api_get_authorizer_info_url, "POST", object.toString());
	    System.out.println("result=\t"+result);
	}
}

另外的两个工具类

工具类一 : 将获取到的数据写入文件中

package com.wlw.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Properties;
public class PropUtil {

	public static void main(String[] args) {
		System.out.println(PropUtil.getProp("token.properties", "name"));
		PropUtil.setProp("token.properties", "name", "11111111133333111");
		
	}
	/**
	 * * 获取文件中指定key的值
	 * @param filePath文件路径(根目录下)
	 * @param keyֵ
	 */
	public static String getProp(String filename, String key) {

		try {

			Properties props = new Properties();

			String filepath = Thread.currentThread().getContextClassLoader().getResource("").getPath() + filename;

			File file = new File(filepath);

			InputStream in = new FileInputStream(file);

			props.load(in);

			in.close();

			String value = props.getProperty(key);

			return value == null ? "":value;

		} catch (Exception e)

		{
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * *设置指定key值,并保存至文件
	 * 
	 * @param filePath文件路径(根目录下)
	 * 
	 */

	public static void setProp(String filename, String key, String value) {

		try {

			Properties prop = new Properties();

			String filepath = Thread.currentThread().getContextClassLoader().getResource("").getPath() + filename;

			File file = new File(filepath);

			InputStream in = new FileInputStream(file);

			prop.load(in); 

			in.close();

			System.out.println("filepath---------->" + filepath);

			OutputStream fos = new FileOutputStream(file);
			prop.setProperty(key, value); 

			prop.store(fos, "Update '" + key + "' value");

			fos.flush();

			fos.close();

		} catch (Exception e) {

			e.printStackTrace();

		}
	}
}
工具类二 : 处理htpps请求
package com.wlw.util;

/** 
 * 请求数据通用类*/
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;

import com.wlw.menu.Menu;

import net.sf.json.JSONObject;
import wlw.wechat.msg.model.media.AccessToken;
public class wenxinUtil {
    /** 
     * 发起https请求并获取结果 
     *  
     * @param requestUrl 请求地址 
     * @param requestMethod 请求方式(GET、POST) 
     * @param outputStr 提交的数据 
     * @return JSONObject 返回JSONObject对象(通过JSONObject.get(key)的方式获取json对象的属性值) 
     * @author Engineer.Jsp
     */  
	public static JSONObject HttpRequest(String request , String RequestMethod , String output){
		@SuppressWarnings("unused")
		// 定义 JSONObject 对象
		JSONObject jsonObject = null;
		// buffer 缓冲流
		StringBuffer buffer = new StringBuffer();
		try {
			//建立连接
			URL url = new URL(request);
			// 获取 HttpURLConnection对象
			HttpURLConnection connection = (HttpURLConnection) url.openConnection();
			// 设置输出流
			connection.setDoOutput(true);
			// 设置输入流
			connection.setDoInput(true);
			// 是否使用缓存
			connection.setUseCaches(false);
			// 请求方式
			connection.setRequestMethod(RequestMethod);
			// 流不为空
			if(output!=null){
				// 获取流
				OutputStream out = connection.getOutputStream();
				// 写数据流 UTF-8 编码
				out.write(output.getBytes("UTF-8"));
				// 关闭
				out.close();
			}
			//流处理
			InputStream input = connection.getInputStream();
			// 读取流 UTF-8 编码
			InputStreamReader inputReader = new InputStreamReader(input,"UTF-8");
			// 缓冲流 buffer
			BufferedReader reader = new BufferedReader(inputReader);
			// 定义 String 来读取每一行
			String line;
			// 循环读取每一行,知道数据没有了,意思是读取完了
			while((line=reader.readLine())!=null){
				// 添加到StringBuffer字符流里面
				buffer.append(line);
			}
			//关闭连接、释放资源
			reader.close();
			// 关闭
			inputReader.close();
			// 关闭
			input.close();
			// 强制释放对象,缓解JVM内存
			input = null;
			// 关闭连接
			connection.disconnect();
			// 把写到 StringBuffer 字符流的数据用 JSONObject.fromObject 函数转换成 JSONObject 对象
			jsonObject = JSONObject.fromObject(buffer.toString());
			System.out.println(buffer.toString());
		} catch (Exception e) {
		}
		// 如果为空,返回一个空对象,否则返回jsonObject实例对象
		return jsonObject;
	}   

}  

 

然后开启Tomcat,打开JSP页面等微信端发送消息来。

 

发送信息来了后点击登录,会跳转

 

第三方平台授权登录_第3张图片

 

用微信扫码即可授权成功!!!

后台返回的消息

第三方平台授权登录_第4张图片

 

你可能感兴趣的:(微信公众号开发,JAVA,微信开放平台授权,微信第三方平台)