微信开放平台授权登录流程详解

4,649 阅读5分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

本文已参与 「掘力星计划」 ,赢取创作大礼包,挑战创作激励金。


最近在工作中用到了一些微信开放平台授权第三方登录,来获取用户基本信息的操作。看了一下微信给出的官方文档,写的已经很详细了,这里按照自己的步骤进行了一下总结,并附带了一些示例,方便大家理解。

微信公众号进行对第三方授权的流程可分为以下四步:

  1. 用户同意授权,获取code
  2. 通过code换取网页授权access_token
  3. 刷新access_token(非必须)
  4. 拉取用户信息(需scopesnsapi_userinfo)

其中正常流程中,第3步为非必须步骤,仅使用在access_token失效的情况下,下面对每一个步骤进行详细介绍。

1、获取code

官方接口如下:

https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE&connect_redirect=1#wechat_redirect

当用户确认授权登录之后,会跳转到redirect_uri这个地址上,并带上微信后台生成的code参数,在前端可对code进行保存,用于后续获取access_token

参数说明:

参数必须说明
appid公众号的唯一标识
redirect_uri授权后重定向的回调链接地址, 需使用 urlEncode 对链接进行处理
response_type返回类型,请填写code
scope应用授权作用域,snsapi_base 或 snsapi_userinfo
state重定向后会带上state参数,开发者可以填写a-zA-Z0-9的参数值,最多128字节
#wechat_redirect无论直接打开还是做页面302重定向时候,必须带此参数

后端代码示例:

@Controller
@RequestMapping("wechat")
public class WeChatContraller {
    @GetMapping("authorization")
    public String authorization() throws UnsupportedEncodingException {
        return "redirect:https://open.weixin.qq.com/connect/oauth2/authorize?"
                + "?appid=" + WeChatUtil.appid + "&redirect_uri="
                + URLEncoder.encode(WeChatUtil.DomainName + "/index.html", "UTF-8")
                + "&response_type=code&scope=snsapi_base&state=123#wechat_redirect";
    }
}

需要注意的是,由于授权操作安全等级较高,所以在发起授权请求时,微信会对授权链接做正则强匹配校验,如果链接的参数顺序不对,授权页面将无法正常访问。

并且应用授权作用域在为snsapi_base时,不弹出授权页面,直接跳转,只能获取用户openid;而在snsapi_userinfo时弹出授权页面,后续可通过openid拿到昵称、性别、所在地。并且, 即使在未关注的情况下,只要用户授权,也能获取其信息。

2、获取access_token

这里通过code换取一个特殊的网页授权access_token,官方接口如下:

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

参数说明:

参数必须说明
appid公众号的唯一标识
secret公众号的appsecret
code填写第一步获取的code参数
grant_type填写为authorization_code

后端代码示例:

@ResponseBody
@GetMapping("getToken")
public String getToken(@RequestParam(name = "code") String code) {
    String url = "https://api.weixin.qq.com/sns/oauth2/access_token?"
           + "?appid=" + WeChatUtil.appid + "&secret=" + WeChatUtil.appsecret
           + "&code=" + code + "&grant_type=authorization_code";
    String rs = HttpSendUtil.get(url, null);
    JSONObject json = JSONObject.parseObject(rs);
    
    if(null == json.get("errcode")){
        return json.get("access_token").toString();        
    }else{
        return "获取access_token出错";
    }
}

这里使用HttpClient发送get请求,从返回的JSON中取出access_token返回。正确返回的完整JSON数据包如下:

{
  "access_token":"ACCESS_TOKEN",
  "expires_in":7200,
  "refresh_token":"REFRESH_TOKEN",
  "openid":"OPENID",
  "scope":"SCOPE" 
}

返回参数说明:

参数说明
access_token网页授权接口调用凭证,注意:此access_token与基础支持的access_token不同
expires_inaccess_token接口调用凭证超时时间,单位(秒)
refresh_token用户刷新access_token
openid用户唯一标识
scope用户授权的作用域,使用逗号(,)分隔

错误时微信会返回JSON数据包如下(示例为code无效错误):

{
  "errcode":40029,
  "errmsg":"invalid code"
}

需要注意code只能够使用一次,如果被消费后第二次仍然用相同code请求获取access_token则会失败。

3、刷新access_token(非必须)

access_token拥有时效性,当超时失效后可以使用refresh_token进行刷新,需要用户重新授权。

https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=APPID&grant_type=refresh_token&refresh_token=REFRESH_TOKEN

参数说明:

参数必须说明
appid公众号的唯一标识
grant_type填写refresh_token
refresh_token填写通过access_token获取到的refresh_token参数

正确时返回的JSON数据包如下,与直接获取格式相同:

{ 
  "access_token":"ACCESS_TOKEN",
  "expires_in":7200,
  "refresh_token":"REFRESH_TOKEN",
  "openid":"OPENID",
  "scope":"SCOPE" 
}

4、拉取用户信息

如果网页授权作用域为snsapi_userinfo,则此时开发者可以通过access_tokenopenid拉取用户信息了。

https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN

参数说明:

参数必须说明
access_token网页授权接口调用凭证,注意:此access_token与基础支持的access_token不同
openid用户的唯一标识
lang返回国家地区语言版本,zh_CN 简体,zh_TW 繁体,en 英语

后端代码示例:

@ResponseBody
@GetMapping("getUserInfo")
public JSONObject getUserInfo(@RequestParam(name = "accessToken") String accessToken,
                          @RequestParam(name = "openid") String openid) {
    String url = "https://api.weixin.qq.com/sns/userinfo?"
            + "?access_token=" + accessToken + "&openid=" +openid
            + "&lang=zh_CN";

    String rs = HttpSendUtil.get(url, null);
    JSONObject json = JSONObject.parseObject(rs);
    
    return json;
}

正确时返回的JSON数据包如下:

{   
  "openid":" OPENID",
  "nickname": NICKNAME,
  "sex":"1",
  "province":"PROVINCE",
  "city":"CITY",
  "country":"COUNTRY",
  "headimgurl":"http://thirdwx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/46",
  "privilege":[ "PRIVILEGE1" "PRIVILEGE2"],
  "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
}

返回参数说明:

参数说明
openid用户的唯一标识
nickname用户昵称
sex用户的性别,值为1时是男性,值为2时是女性,值为0时是未知
province用户个人资料填写的省份
city普通用户个人资料填写的城市
country国家,如中国为CN
headimgurl用户头像
privilege用户特权信息,json 数组
unionid只有在用户将公众号绑定到微信开放平台帐号后,才会出现该字段

错误时微信会返回JSON数据包如下(示例为openid无效):

{  
  "errcode":40003,
  "errmsg":" invalid openid "
}

需要注意的是,由于公众号的secret和获取到的access_token安全级别都非常高,只能保存在服务器,不允许传给客户端。后续刷新access_token、通过access_token获取用户信息等步骤,也必须从服务器发起。

总的来说,微信开放平台授权登录这一块功能应用了OAuth2的授权码模式,如果大家对OAuth2比较了解的话,这一块内容理解起来会非常容易,如果不熟的话,可以移步看一下这篇文章:OAuth2.0授权码模式实战,希望能够帮助到大家。

最后

如果觉得对您有所帮助,小伙伴们可以点赞、转发一下,非常感谢

公众号码农参上,加个好友,做个点赞之交啊