原创

Java基于微信公众号接口实现授权登录源码及原理分析

微信公众号授权登录操作前提必须注册微信公众平台账号,注意的是订阅号不支持授权登录操作,因此对于个人开发者注册的订阅号是无法实现的,必须注册企业号的微信平台账号而具体注册流程就不详细介绍了,有什么疑问可去微信公众号平台查看具体的文档。


接下来讲述一下具体的微信授权登录流程,打开微信开发文档官网(https://mp.weixin.qq.com/wiki),“微信网页开发”中找到“微信网页授权”,其中详细介绍了微信授权登录实现,如图:

2.png


AppId和AppSecret参数见下图:

1.png


网页授权流程分为四步:

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

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

3、如果需要,开发者可以刷新网页授权access_token,避免过期 

4、通过网页授权access_token和openid获取用户基本信息(支持UnionID机制) 


步骤一:首先需要获取code,具体发送链接如下:https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect

其中参数appid、redirect_uri、response_type、scope、state,具体说明如下图:

3.png

注意:当scope为snsapi_base(静默授权) ,就不会弹出授权页面;而scope为snsapi_userinfo(手动授权)时,是弹出授权页面的,可以获取用户的相关信息。

微信授权有两种网页授权方式

第一种静默授权:不会给登录用户任何提示直接返回用户code,但如果登录用户存在关注公众号的情况下,无法拿到登录用户的全部信息

以snsapi_base为scope发起的网页授权,是用来获取进入页面的用户的openid的,并且是静默授权并自动跳转到回调页的。用户感知的就是直接进入了回调页(往往是业务页面)

第二种手动授权:弹出授权页面,登录用户点击确定后可获取登录用户的信息

以snsapi_userinfo为scope发起的网页授权,是用来获取用户的基本信息的。但这种授权需要用户手动同意,并且由于用户同意过,所以无须关注,就可在授权后获取该用户的基本信息。 

参考案例:

静默授权 https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect

手动授权 https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect


步骤二:通过code值获取网页授权access_token票据

登录用户每次授权所携带的code都不一样,code只能使用一次,5分钟自动过期。

https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code

其中参数appid、secret、code、grant_type,具体说明如下图:

4.png


步骤三:刷新access_token(如果需要)

由于access_token拥有较短的有效期,当access_token超时后,可以使用refresh_token进行刷新,refresh_token有效期为30天,当refresh_token失效之后,需要用户重新授权。


步骤四:拉取用户信息(需scope为 snsapi_userinfo)

获取用户信息网页授权作用域为snsapi_userinfo,此时开发者可以通过access_token和openid获取用户信息。具体链接如下:https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN

其中参数access_token、openid、lang,具体说明如下图:

5.png


具体实现微信公众号授权登录代码,通过填写的回调url进入我们的后台登录调用方法,代码如下:

public void weixinLogin(HttpServletRequest request,HttpServletResponse response) throws Exception {  
  Map<String, String[]> params = request.getParameterMap();//针对get获取get参数  
  String[] codes = params.get("code");//拿到的code的值  
  String code = codes[0];//code  
  /*
   * 拼写微信api请求地址并通过微信的appId和微信公众号的AppSecret
   * 以及授权回调的code获取用户的openid和access_token
   */  
  String requestUrl = " https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID
  &redirect_uri=APPSECRET&response_type=code&scope=snsapi_userinfo&state=STATE"
  .replace("APPID",APPID).replace("APPSECRET", AppSecret).replace("CODE", code);  
  String requestResult = doGet(requestUrl);
  JSONObject jsons = JSON.parseObject(requestResult);//结果转换成JSON对象  
  if(jsons == null || jsons.getInteger("errcode") != null || jsons.getString("openid") == null) {  
    throw NoResultException();//自定义异常类
  }  
  String openid = jsons.getString("openid");  
  //注意:公众号通用的access_token和登录用户的access_token是有区别的
  //微信公众号的通用access_token每天只能取2000次 每次token有效期是7200S  
  requestUrl = "https://api.weixin.qq.com/sns/oauth2/access_token
  ?appid=APPID&secret=APPSECRET&code=CODE&grant_type=authorization_code"
  .replace("APPID", APPID).replace("APPSECRET", AppSecret);   
  requestResult = doGet(requestUrl);   
  JSONObject weixinToken = JSON.parseObject(requestResult);  
  if(jsonObject == null){  
      throw NoResultException();//自定义异常类,获取我们公众号token失败  
  }  
  String wxgzhToken =  accessToken.setToken(jsonObject.getString("access_token"));  
  requestUrl = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN
  &openid=OPENID&lang=zh_CN".replace("ACCESS_TOKEN", wxgzhToken).replace("OPENID", openid);  
  requestResult = doGet(requestUrl);   
  JSONObject user = JSON.parseObject(requestResult);  
  if(user == null || user.getInteger("errcode") != null ) {  
      throw NoResultException();//自定义异常类
  }  
  //把这些信息存在我们的数据库中然后跳转到我们前台页面 
}  
/**
 * get方式
 * @param url
 * @author blog.yoodb.com
 * @return
 */
public static String doGet(String url) {
  String responseMsg = "";
  HttpClient httpClient = new HttpClient();
  GetMethod getMethod = new GetMethod(url);
  getMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER
    ,new DefaultHttpMethodRetryHandler());
  try {
    httpClient.executeMethod(getMethod);
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    InputStream in = getMethod.getResponseBodyAsStream();
    int len = 0;
    byte[] buf = new byte[1024];
    while((len=in.read(buf))!=-1){
      out.write(buf, 0, len);
    }
    responseMsg = out.toString("UTF-8");
  } catch (HttpException e) {
    e.printStackTrace();
  } catch (IOException e) {
    e.printStackTrace();
  } finally {
    //释放连接
    getMethod.releaseConnection();
  }
  return responseMsg;
}

如果登录成功授权之后会返回正确的json格式数据,反之失败返回相对应的错误码。

关注下方微信公众号“Java精选”(w_z90110),回复关键字领取资料:如HadoopDubboCAS源码等等,免费领取资料视频和项目。 

涵盖:程序人生、搞笑视频、算法与数据结构、黑客技术与网络安全、前端开发、Java、Python、Redis缓存、Spring源码、各大主流框架、Web开发、大数据技术、Storm、Hadoop、MapReduce、Spark、elasticsearch、单点登录统一认证、分布式框架、集群、安卓开发、iOS开发、C/C++、.NET、Linux、Mysql、Oracle、NoSQL非关系型数据库、运维等。

评论

  1. #1

    呦西 (2017/07/21 10:28:07)回复
    感谢分享,写的比较详细。不错。

分享:

支付宝

微信