Java实现微信网页授权
阅读原文时间:2022年04月21日阅读:1

开发前的准备:

1、需要有一个公众号(我这里用的测试号),拿到AppID和AppSecret;

2、进入公众号开发者中心页配置授权回调域名。具体位置:接口权限-网页服务-网页账号-网页授权获取用户基本信息-修改

注意,这里仅需填写全域名(如www.qq.com、www.baidu.com),勿加 http:// 等协议头及具体的地址字段;

  我们可以通过使用Ngrok来虚拟一个域名映射到本地开发环境,网址https://www.ngrok.cc/,大家自己去下载学习怎么使用

同时还需要扫一下这个二维码

授权步骤:

1、引导用户进入授权页面同意授权,获取code

2、通过code换取网页授权access_token(与基础支持中的access_token不同)

3、通过网页授权access_token和openid获取用户基本信息

先看一下我的项目结构:

web.xml相关代码:


http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app\_3\_0.xsd" id="WebApp\_ID" version="3.0">
WxAuth
index.html index.htm index.jsp default.html default.htm default.jsp

wxCallBack com.xingshang.servlet.CallBackSerclet dbUrl jdbc:mysql://127.0.0.1:3306/wxauth driverClassName com.mysql.jdbc.Driver userName root passWord 123456 1

wxCallBack /wxCallBack

AuthUtil工具类:

package com.xingshang.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 = "wx45c1428e5584fcdb";  
public static final String APPSECRET = "98174450eb706ada330f37e646be85d5";

public static JSONObject doGetJson(String url) throws ClientProtocolException, IOException{  
    JSONObject jsonObject = null;  
    //首先初始化HttpClient对象  
    DefaultHttpClient client = new DefaultHttpClient();  
    //通过get方式进行提交  
    HttpGet httpGet = new HttpGet(url);  
    //通过HTTPclient的execute方法进行发送请求  
    HttpResponse response = client.execute(httpGet);  
    //从response里面拿自己想要的结果  
    HttpEntity entity = response.getEntity();  
    if(entity != null){  
        String result = EntityUtils.toString(entity,"UTF-8");  
        jsonObject = jsonObject.fromObject(result);  
    }  
    //把链接释放掉  
    httpGet.releaseConnection();  
    return jsonObject;  
}  

}

Java实现:

1、引导用户进入授权页面同意授权,获取code

这一步其实就是将需要授权的页面url拼接到微信的认证请求接口里面,比如需要用户在访问页面  时进行授权认证

其中的scope参数有两个值:

snsapi_base:只能获取到用户openid。好处是静默认证,无需用户手动点击认证按钮,感觉上像是直接进入网站一样。

snsapi_userinfo:可以获取到openid、昵称、头像、所在地等信息。需要用户手动点击认证按钮。

相关代码

package com.xingshang.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.xingshang.util.AuthUtil;

/**
* 入口地址
* @author Administrator
*
*/
@WebServlet("/wxLogin")
public class LoginServlet extends HttpServlet {

/\*\*  
 \*  
 \*/  
private static final long serialVersionUID = 1L;

@Override  
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    //第一步:引导用户进入授权页面同意授权,获取code

    //回调地址  

// String backUrl = "http://suliu.free.ngrok.cc/WxAuth/callBack"; //第1种情况使用
String backUrl = "http://suliu.free.ngrok.cc/WxAuth/wxCallBack";//第2种情况使用,这里是web.xml中的路径

    //授权页面地址  
    String url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid="+AuthUtil.APPID  
            + "&redirect\_uri="+URLEncoder.encode(backUrl)  
            + "&response\_type=code"  
            + "&scope=snsapi\_userinfo"  
            + "&state=STATE#wechat\_redirect";

    //重定向到授权页面  
    response.sendRedirect(url);  
}  

}

2、通过第一步获取的code换取网页授权access_token(与基础支持中的access_token不同)

这一步需要在控制器中获取微信回传给我们的code,通过这个code来请求access_token,通过access_token和openid获取用户基本信息:

相关代码:

package com.xingshang.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.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.xingshang.util.AuthUtil;

import net.sf.json.JSONObject;

/**
* 回调地址
* @author Administrator
*
*/
//@WebServlet("/callBack")
public class CallBackSerclet extends HttpServlet {

/\*\*  
 \*  
 \*/  
private static final long serialVersionUID = 1L;

private String dbUrl;  
private String driverClassName;  
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.driverClassName = config.getInitParameter("driverClassName");  
        this.userName = config.getInitParameter("userName");  
        this.passWord = config.getInitParameter("passWord");  
        Class.forName(driverClassName);  
    } catch (ClassNotFoundException e) {  
        // TODO Auto-generated catch block  
        e.printStackTrace();  
    }  
}

@Override  
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    //第二步:通过code换取网页授权access\_token

    //从request里面获取code参数(当微信服务器访问回调地址的时候,会把code参数传递过来)  
    String code = request.getParameter("code");

    System.out.println("code:"+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);

    System.out.println("==========================jsonObject"+jsonObject);

    //从返回的JSON数据中取出access\_token和openid,拉取用户信息时用  
    String token =  jsonObject.getString("access\_token");  
    String openid = jsonObject.getString("openid");

    // 第三步:刷新access\_token(如果需要)

    // 第四步:拉取用户信息(需scope为 snsapi\_userinfo)  
    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种情况:使用微信用户信息直接登录,无需注册和绑定  

// request.setAttribute("info", userInfo);
//直接跳转
// request.getRequestDispatcher("/index1.jsp").forward(request, response);

    //第2种情况: 将微信与当前系统的账号进行绑定(需将第1种情况和@WebServlet("/callBack")注释掉)  
    //第一步,根据当前openid查询数据库,看是否该账号已经进行绑定  
    try {  
        String nickname = getNickName(openid);  
        if(!"".equals(nickname)){  
            //已绑定  
            request.setAttribute("nickname", nickname);  
            request.getRequestDispatcher("/index2.jsp").forward(request, response);  
        }else{  
            //未绑定  
            request.setAttribute("openid", openid);  
            request.getRequestDispatcher("/login.jsp").forward(request, response);  
        }  
    } catch (SQLException e) {  
        // TODO Auto-generated catch block  
        e.printStackTrace();  
    }

}

//数据库的查询  
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;  
}

//数据库的修改(openid的綁定)  
public int updateUser(String account,String password,String openid) 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, password);  
    int temp = ps.executeUpdate();

    //关闭链接  
    rs.close();  
    ps.close();  
    conn.close();

    return temp;  
}

//post方法,用来接受登录请求  
@Override  
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    String account = request.getParameter("account");  
    String password = request.getParameter("password");  
    String openid = request.getParameter("openid");

    try {  
        int temp = updateUser(account, password, openid); 

        if(temp > 0){  
            String nickname = getNickName(openid);  
            request.setAttribute("nickname", nickname);  
            request.getRequestDispatcher("/index2.jsp").forward(request, response);  
            System.out.println("账号绑定成功");  
        }else{  
            System.out.println("账号绑定失败");  
        }

    } catch (SQLException e) {  
        // TODO Auto-generated catch block  
        e.printStackTrace();  
    }

}

}

login.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

Insert title here

index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

Insert title here 微信公众授权登录

index1.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

Insert title here

登陆成功!
用户昵称:${info.nickname}
用户头像:

index2.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

Insert title here

登陆成功!
用户昵称:${nickname}

最后附上需要的jar包

到此,微信授权登录成功,如果有运行问题请自行调试,我这边能正常运行的