欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

详解微信开发之Author网页授权

程序员文章站 2024-03-11 18:21:49
微信开发中,经常有这样的需求:获得用户头像、绑定微信号给用户发信息.. 那么实现这些的前提就是授权! 1.配置安全回调域名: 在微信公众号请求用户网页授权之前,开发...

微信开发中,经常有这样的需求:获得用户头像、绑定微信号给用户发信息.. 那么实现这些的前提就是授权!

1.配置安全回调域名:

详解微信开发之Author网页授权

在微信公众号请求用户网页授权之前,开发者需要先到公众平台官网中的“开发 - 接口权限 - 网页服务 - 网页帐号 - 网页授权获取用户基本信息”的配置选项中,修改授权回调域名,值得注意的是这里就是直接写全域名,如: 。然而我们开发h5中一般用的是二级域名,如:h5.liliangel.cn 也同样在安全回调域名中。

2.用户级授权和静默授权

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

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

3.网页授权access_token和普通access_token的区别

1、微信网页授权是通过oauth2.0机制实现的,在用户授权给公众号后,公众号可以获取到一个网页授权特有的接口调用凭证(网页授权access_token),通过网页授权access_token可以进行授权后接口调用,如获取用户基本信息;

2、其他微信接口,需要通过基础支持中的“获取access_token”接口来获取到的普通access_token调用。 

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

详解微信开发之Author网页授权

微信更新后,授权页也变化了。其实习惯了绿色的那个经典页面..

js:

var center = {
    init: function(){
      .....
    },
    enterwxauthor: function(){
      var wxuserinfo = localstorage.getitem("wxuserinfo");
      if (!wxuserinfo) {
        var code = common.geturlparameter('code');
        if (code) {
          common.getwxuserinfo();
          center.init();
        }else{
          //没有微信用户信息,没有授权-->> 需要授权,跳转授权页面
          window.location.href = 'https://open.weixin.qq.com/connect/oauth2/authorize?appid='+ wx_appid +'&redirect_uri='+ window.location.href +'&response_type=code&scope=snsapi_userinfo#wechat_redirect';
        }
      }else{
        center.init();
      }
    }
}
$(document).ready(function() { 
  center.enterwxauthor();
}

以scope=snsapi_userinfo为例,页面加载的时候进入授权方法,首先从缓存获取wxuserinfo对象,如果有说明之前已经授权过,直接进入初始化方法。如果没有,判断url是否包含code,有code说明是进入授权页回调后的页面,那么通过code换取用户信息即可。没有code,即用户第一次进入该页面,引导去授权页,redirect_uri为当前页面地址。

getwxuserinfo方法:

/**
   * 授权后获取用户的基本信息
   */
  getwxuserinfo:function(par){
    var code = common.geturlparameter("code");
    
    if (par) code = par;
    
    $.ajax({
      async: false,
      data: {code:code},
      type : "get",
      url : wx_root + "wechat/authorization",
      success : function(json) {
        if (json){
          try {
            //保证写入的wxuserinfo是正确的
            var data = json.parse(json);
            if (data.openid) {
              localstorage.setitem('wxuserinfo',json);//写缓存--微信用户信息
            }
          } catch (e) {
            // todo: handle exception
          }
        }
      }
    });
  },

5.后台restful-- /wechat/authorization,根据code换取用户信息

  /**
   * 微信授权
   * @param code 使用一次后失效
   * 
   * @return 用户基本信息
   * @throws ioexception 
   */
  @requestmapping(value = "/authorization", method = requestmethod.get)
  public void authorizationweixin(
      @requestparam string code,
      httpservletrequest request, 
      httpservletresponse response) throws ioexception{
    request.setcharacterencoding("utf-8"); 
    response.setcharacterencoding("utf-8"); 

    printwriter out = response.getwriter();
    logger.info("restful of authorization parameters code:{}",code);   
    try {
      string rs = wechatservice.getoauthaccesstoken(code);
      out.write(rs);
      logger.info("restful of authorization is successful.",rs);
    } catch (exception e) {
      logger.error("restful of authorization is error.",e);
    }finally{
      out.close();
    }
  }

这里有一个授权access_token,切记:授权access_token非全局access_token ,需要使用缓存,这里我使用的redis,具体配置不多说后面写相关配置博文,当然也可以使用ehcache,关于ehcahe配置在我的第一篇博客中有详细介绍。

/**
   * 根据code 获取授权的token 仅限授权时使用,与全局的access_token不同
   * @param code
   * @return
   * @throws ioexception 
   * @throws clientprotocolexception 
   */
  public string getoauthaccesstoken(string code) throws clientprotocolexception, ioexception{
    string data = redisservice.get("weixin_sq_access_token");
    string rs_access_token = null;
    string rs_openid = null;
    string url = wx_oauth_access_token_url + "?appid="+wx_appid+"&secret="+wx_appsecret+"&code="+code+"&grant_type=authorization_code";
    if (stringutils.isempty(data)) {
      synchronized (this) {
        //已过期,需要刷新
        string hs = apiservice.doget(url);
        jsonobject json = jsonobject.parseobject(hs);
        string refresh_token = json.getstring("refresh_token");
        string refresh_url = "https://api.weixin.qq.com/sns/oauth2/refresh_token?appid="+wx_appid+"&grant_type=refresh_token&refresh_token="+refresh_token;
        string r_hs = apiservice.doget(refresh_url);
        jsonobject r_json = jsonobject.parseobject(r_hs);
        string r_access_token = r_json.getstring("access_token");
        string r_expires_in = r_json.getstring("expires_in");
        rs_openid = r_json.getstring("openid"); 
        rs_access_token = r_access_token;
        redisservice.set("weixin_sq_access_token", r_access_token, integer.parseint(r_expires_in) - 3600);
        logger.info("set sq access_token to redis is successful.parameters time:{},realtime",integer.parseint(r_expires_in), integer.parseint(r_expires_in) - 3600);
      }
    }else{
      //还没有过期
      string hs = apiservice.doget(url);
      jsonobject json = jsonobject.parseobject(hs);
      rs_access_token = json.getstring("access_token");
      rs_openid = json.getstring("openid");
      logger.info("get sq access_token from redis is successful.rs_access_token:{},rs_openid:{}",rs_access_token,rs_openid);
    }
    
    return getoauthuserinfo(rs_access_token,rs_openid);
  }
  /**
   * 根据授权token获取用户信息
   * @param access_token
   * @param openid
   * @return
   */
  public string getoauthuserinfo(string access_token,string openid){
    string url = "https://api.weixin.qq.com/sns/userinfo?access_token="+ access_token +"&openid="+ openid +"&lang=zh_cn";
    try {
      string hs = apiservice.doget(url);
      //保存用户信息
      saveweixinuser(hs);  
      return hs;
    } catch (ioexception e) {
      logger.error("restful of authorization is error.",e);
    }
    return null;
  }

当时赶时间,代码命名较乱。可以看到,我用了一个同步的方法,先从缓存中获取key为weixin_sq_access_token,如果取到了说明没有过期,直接通过httpclient调用微信提供的接口,返回用户信息的字符串给前端。如果没有取到,说明没有或者已经过期,则根据refresh_token刷新access_token,再写缓存,由于access_token拥有较短的有效期,为了保险我这里设置了缓存的失效时间微信给的时间再减一个小时。回过头来看代码发现,上面的逻辑有点点小问题,这样写会导致第一次获取或者缓存失效后第一次获取access_token都会去刷新一次,暂时不影响使用,后面做优化修改 todo。

6:保存用户信息

通常情况下,授权后我们会将用户信息保存数据库表,openid为唯一主键,外键关联起我们自己的用户表,这样一来,无论是后续要开展什么业务,还是做运营数据统计,都有了一个跟微信公众号的关联关系。值得注意的是:我们获取到的headimgurl是微信提供的一个url地址,当用户修改头像后可能导致原来的地址失效,所以最好是通过将图片保存到本地服务器然后保存本地的地址url!

微信返回的值:

详解微信开发之Author网页授权

参考链接:

微信公众平台官方文档:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842&token=&lang=zh_cn

在线接口调试工具:

没有公众号福利:测试账号申请

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持!