微信受權登陸

一. 微信公衆號受權

1.準備:

a.微信公衆號(或者微信公衆測試號)

準備已經經過認證的微信公衆號,或者申請微信公衆測試號也能夠,申請地址以下:                                    https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/loginhtml

微信關注該公衆號(或者公衆測試號)前端

b. 內網穿透+可訪問的公網地址(須要的是域名,而不是ip地址)

微信公衆號受權須要綁定一個回調地址,這個回調地址必須是公網能訪問的。準備帶公網ip的雲服務器,而且綁定合適的二級域名,再進行項目的部署是最好不過的了,可是不少狀況下咱們是在本地進行開發調試的,所以這裏以本地開發爲例進行說明:java

首先是內網穿透。因爲咱們是在本機進行開發,外網沒法訪問咱們的計算機,所以須要先將本機ip映射到公網。這裏選擇使用natapp的服務:git

 

購買了vip-1型隧道(免費的隧道不支持綁定本身的域名,且臨時域名/端口隨機,不定時強制更換),以後又購買了二級域名(購買隧道時默認給的臨時三級域名被微信屏蔽),將二級域名綁定到個人隧道上。把natapp客戶端(注意帶上config.ini這個文件,方便改配置)下載到本地,複製一下隧道的authtoken,填入到config.ini配置項中:github

   

雙擊natapp.exe便可啓動服務,出現以下界面,顯示綠色的「Online」,說明已經映射成功了,從配置能夠看出,natapp將域名映射到了本地的127.0.0.1:8080,你啓動Tomcat,在瀏覽器中輸入域名,應該就會看到Tomcat的歡迎頁了。web

  

c. 在微信公衆號(測試號)中綁定你的回調地址域名

千萬不要忘記這一步哦,否則測試中會報錯"沒法訪問回調地址"。首先在接口權限表中找到這一項:sql

 

點擊「修改」,在彈出來的窗口填入你的回調域名,注意的是,這裏填入的域名是一個字符串,不要加上http://協議頭數據庫

好了,至此,準備工做告一段落,下面開始着手代碼的開發。apache

2.代碼開發:

着手開發以前,咱們須要知道微信公衆號受權登陸的基本流程,這個在微信開發文檔中有詳細的說明,建議開發者詳細閱讀:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842json

總的來看呢,是如下四個步驟:

  1.  第一步:用戶贊成受權,獲取code
  2.  第二步:經過code換取網頁受權access_token
  3.  第三步:刷新access_token(若是須要)
  4.  第四步:拉取用戶信息(需scope爲 snsapi_userinfo)
  5.  附:檢驗受權憑證(access_token)是否有效

項目的結構如圖:

      

a ). 首先定義AuthUtil類,該類提供一個訪問接口url並返回json對象的方法:

package com.wx.auth.util;

import java.io.IOException;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;

import net.sf.json.JSONObject;

public class AuthUtil {
	public static final String APPID="wx6d6d0eabe8392e5a";//此處填寫本身的appid
	public static final String APPSECRET="6be3dff05e5da4584abdc9e90146b36b";//此處填寫本身的appsecret
	
	public static JSONObject doGetJson(String url) throws ClientProtocolException, IOException {
		
		JSONObject jsonObject=null;
		DefaultHttpClient client=new DefaultHttpClient();//初始化httpclient對象 
		HttpGet httpGet=new HttpGet(url);//經過get方式進行提交
		HttpResponse response=client.execute(httpGet);//使用execute()方法發送請求,此處會拋出異常
		HttpEntity entity=response.getEntity();//從response中獲取結果
		if (entity!=null) {
			String result=EntityUtils.toString(entity,"utf-8");
			jsonObject=JSONObject.fromObject(result);//將String對象裝換成json
		}
		 httpGet.releaseConnection();//把鏈接釋放掉
		return jsonObject;
	}
}

b ).而後定義LoginServlet,此處拼接入口地址,接口參數的順序要保證不能出錯!末尾的resp.sendRedirect(url),讓客戶端使用拼接好的接口地址去請求微信服務器

package com.wx.auth.servlet;

import java.io.IOException;
import java.net.URLEncoder;

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.wx.auth.util.AuthUtil;

/**
 * 拼接入口地址,順序不能出錯
 * @author xzf
 *
 */
@WebServlet("/wxLogin")
public class LoginServlet extends HttpServlet{
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		String backUrl="http://xzf.nat300.top/WxAuth/wxCallBack";//回調地址必需要在公網可以訪問
		String url="https://open.weixin.qq.com/connect/oauth2/authorize?appid="+AuthUtil.APPID
				+ "&redirect_uri="+URLEncoder.encode(backUrl,"utf-8")
				+ "&response_type=code"
				+ "&scope=snsapi_userinfo"//做用域
				+ "&state=STATE#wechat_redirect";
		resp.sendRedirect(url);
	}
}

c ).定義CallBackServlet類,用於處理回調以後的各項操做,包括獲取用戶信息,微信和當前系統帳號綁定等。

package com.wx.auth.servlet;

import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.wx.auth.util.AuthUtil;

import net.sf.json.JSONObject;

public class CallBackServlet extends HttpServlet{
	
	private String dbUrl;
	private String driverName;
	private String userName;
	private String password;
	private Connection conn=null;
	private PreparedStatement ps=null;
	private ResultSet rs=null;
	
	/**
	 * 此處初始化工做主要進行數據庫鏈接的準備
	 */
	@Override
	public void init(ServletConfig config) throws ServletException {
	
		try {
			this.dbUrl=config.getInitParameter("dbUrl");
			this.driverName=config.getInitParameter("driverName");
			this.password=config.getInitParameter("password");
			this.userName=config.getInitParameter("userName");
			Class.forName(driverName);
 
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	/**
	 * 微信服務器訪問回調地址時,訪問的就是doGet方法,參數中帶上了code
	 * 這裏帶上code,再拼裝接口,獲取access_token
	 * 獲取了access_token以後,就能夠拉取用戶信息了
	 */
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		String code=req.getParameter("code");//微信服務器訪問回調地址時會帶上code參數
		//獲取access_token
		String url="https://api.weixin.qq.com/sns/oauth2/access_token?appid="+AuthUtil.APPID
				+ "&secret="+AuthUtil.APPSECRET
				+ "&code="+code
				+ "&grant_type=authorization_code";
		JSONObject jsonObject=AuthUtil.doGetJson(url);
		String openid=jsonObject.getString("openid");
		String token=jsonObject.getString("access_token");
		//拉取用戶信息
		String infoUrl="https://api.weixin.qq.com/sns/userinfo?access_token="+token
				+ "&openid="+openid
				+ "&lang=zh_CN";
		JSONObject userInfo=AuthUtil.doGetJson(infoUrl);
		System.out.println(userInfo);
		
//		//1.使用微信用戶信息直接登陸,無需註冊和綁定
//		req.setAttribute("info", userInfo);
//		req.getRequestDispatcher("/index1.jsp").forward(req, resp);
		
		//2.將微信與當前系統帳號綁定
		try {
			String nickName=getNickName(openid);
			if (!"".equals(nickName)) {
				//綁定成功
				req.setAttribute("nickName", nickName);
				req.getRequestDispatcher("/index2.jsp").forward(req, resp);
			}else {
				//未綁定
				req.setAttribute("openid", openid);
				req.getRequestDispatcher("/login.jsp").forward(req, resp);
			}
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
	
	public int updUser(String openid,String account,String userPassword) throws SQLException {
		
		conn=DriverManager.getConnection(dbUrl,userName,password);
		String sql="update user set openid=? where account=? and password=?";
		ps=conn.prepareStatement(sql);
		ps.setString(1, openid);
		ps.setString(2, account);
		ps.setString(3, userPassword);
		int temp=ps.executeUpdate();
		
		rs.close();
		ps.close();
		conn.close();
		return temp;
	}
	
	public String getNickName(String openid) throws SQLException {
		String nickName="";
		conn=DriverManager.getConnection(dbUrl,userName,password);
		String sql="select nickname from user where openid=?";
		ps=conn.prepareStatement(sql);
		ps.setString(1, openid);
		rs=ps.executeQuery();
		while(rs.next()){
			nickName=rs.getString("NICKNAME");
		}
		rs.close();
		ps.close();
		conn.close();
		return nickName;
	}
	
	/**
	 * 微信綁定帳號,login.jsp傳回來的參數在這裏進行綁定
	 */
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		String account=req.getParameter("account");
		String password=req.getParameter("password");
		String openid=req.getParameter("openid");
		try {
			int temp=updUser(openid, account, password);
			if (temp>0) {
				System.out.println("帳號綁定成功");
			}else {
				System.out.println("帳號綁定失敗");
			}
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

核心代碼如上,至於一些配置文件,諸如web.xml,pom.xml以及前端顯示頁面,包括index.jsp,login.jsp這裏不一一貼代碼,只說須要注意的幾點:

  • 若jsp頁面中的EL表達式失效,則須要在頭文件中加上 isELIgnored="false",好比:<%@ page isELIgnored="false" language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8"%>
  • pom中的jar包依賴,能夠指定jdk編譯版本
    <dependency>
    			<groupId>net.sf.json-lib</groupId>
    			<artifactId>json-lib</artifactId>
    			<version>2.4</version>
    			<classifier>jdk15</classifier><!-- 指定jdk版本 -->
    		</dependency>
    源代碼地址:https://gitee.com/github-19300436/WxAuth.git 

二. 微信開放平臺受權登陸

使用微信開放平臺須要先進行資質認證,面向的對象是企業和組織,不面向我的,而且須要繳納300元審覈費用。能夠看一下微信開放平臺的開發手冊,上面的操做步驟十分詳細:

https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419316505&token=&lang=zh_CN

開放平臺的受權登陸和公衆號受權登陸,其基本流程是徹底同樣的,可能某些參數值上會有一些不一樣,建議開發時仔細參照微信開發手冊。關於在開放平臺的應用部署,配置,因爲沒有開放平臺的開發者認證資質,這裏沒有作演示,具體能夠參照慕課網課程學習:http://www.imooc.com/video/14031

三. 公衆號與開放平臺的關聯

使用公衆號受權和使用開放平臺的受權得到的openid是不同的

 

這樣就會致使一個問題:即在公衆號受權成功以後,數據庫記錄了公衆號受權的openid,在pc端開放平臺受權下並不能直接登陸,須要從新綁定開放平臺的openid,反之亦然。

爲了解決這個問題,須要將公衆號與開放平臺進行綁定:

1. 首先在開放平臺中綁定本身的微信公衆號

2. 兩者經過UnionID屬性進行關聯

3. 綁定的時候綁定UnionId,而不是openid

數據庫表中新增UnionID字段,獲取access_token以後,拉取用戶信息能夠拿到UnionID的值,在進行綁定的時候,將UnionID的值綁定到系統帳戶上。後續判斷該微信號是否綁定帳戶時,也用UnionID值去查詢系統帳戶信息(基本上就是用UnionID替換掉openid)

四. 微信公衆平臺和開放平臺的一些區別

按微信的 「開放」 佈局,開放平臺是包含公衆平臺的(還包括移動,網站應用開發,公衆號第三方平臺)。開放平臺和公衆平臺是主從關係。

1. 移動應用開發主打 微信分享、微信收藏、微信支付。有本身的手機 APP,用這個會比較多;
2. 網站應用開發 支持使用微信賬號登陸,這種就是在網站上集成第三方登陸,已經很廣泛了;
3. 公衆平臺 就是公衆帳號開發(訂閱號,服務號,企業號);
4. 公衆號第三方平臺 讓公衆平臺裏的用戶能夠受權給第三方來進行託管,使用相關的服務。

我有軟件開發能力,我能夠給本身開發公衆號,但這就和作軟件同樣,須要設計,開發,測試,上線部署,維護等等。
有些時候作出來的功能還不必定好用。

而用上第三方平臺以上這些都不須要管了。它們能提供專業的,針對不一樣行業的軟件服務。我要開網店,我要作營銷,我要作自媒體等等。
惟一要作的事就是註冊一個公衆號,運營。

公衆號第三方平臺最大的便利就是給沒有相關行業從業經歷,沒有軟件開發能力的企業或我的提供專業的軟件服務。實質上第三方平臺就是開發了一個公衆號而後租給不一樣的用戶來使用。

做者:吳貽
連接:https://www.zhihu.com/question/21074751/answer/96828624
來源:知乎
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

微信公衆平臺開發者文檔已經說的很清楚了:

微信公衆平臺開發是指爲微信公衆號進行業務開發,爲移動應用、PC 端網站、公衆號第三方平臺(爲各行各業公衆號運營者提供服務)的開發,請前往微信開放平臺接入。
相關文章
相關標籤/搜索