微信受权登陆

一. 微信公众号受权

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 端网站、公众号第三方平台(为各行各业公众号运营者提供服务)的开发,请前往微信开放平台接入。
相关文章
相关标签/搜索