3、OAuth2.0授权机制:企业微信OAuth2.0流程详解

说到OAuth2.0,很多刚接触企业微信开发的朋友会觉得有点绕。其实说白了,它就是一套「通行证」机制。你想想看,用户不可能每次都把密码告诉你的应用,那太危险了。OAuth2.0就是让用户授权给你的应用,去访问他在企业微信里的部分信息。

我个人习惯把OAuth2.0理解成「酒店房卡」——用户在前台(企业微信)办入住,拿到一张房卡(code),然后凭这张卡去开门(获取成员信息)。整个过程不需要用户把身份证押在你这里。

3.1 企业微信OAuth2.0流程全景

整个流程分三步走,我画个简图给你看:

用户点击应用 → 跳转企业微信授权页 → 获取code
    ↓
用code换取access_token → 用access_token获取成员信息
    ↓
完成身份认证,进入业务系统

嗯,这里要注意一个关键点:企业微信的OAuth2.0和微信公众平台的不太一样。企业微信的授权是「静默」和「手动」两种模式。我在项目中遇到过,很多新手把这两种模式搞混,结果授权页面死活弹不出来。

3.2 获取code:第一步也是最重要的一步

获取code是整个流程的入口。你需要构造一个URL,让用户跳转到企业微信的授权页面。

URL格式长这样:

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

这里有几个参数我重点说一下:

  • appid:你的企业ID,在管理后台「我的企业」里能找到。我建议你把它配在配置文件里,别硬编码。
  • redirect_uri:回调地址,需要URL编码。我曾经踩过一个坑——回调地址没在管理后台配置白名单,结果一直报redirect_uri错误。
  • scope:授权范围。snsapi_base是静默授权,用户无感知;snsapi_userinfo是手动授权,会弹确认框。
  • state:防跨站攻击的参数。我个人习惯用随机字符串+时间戳,回调时校验一下。
避坑指南: 我曾经因为state参数没校验,被安全团队通报过。记住,state一定要生成随机值,回调时做比对。别偷懒用固定值。

3.3 通过code获取成员信息

拿到code之后,就该用它换成员信息了。这里需要调用企业微信的API:

GET https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?
access_token=ACCESS_TOKEN
&code=CODE

返回的数据结构大概是这样的:

{
  "errcode": 0,
  "errmsg": "ok",
  "UserId": "zhangsan",
  "DeviceId": "xxxxxxxx",
  "user_ticket": "xxxxxxxx"
}

这里有个细节:如果用户是企业外部联系人,返回的是OpenId而不是UserId。我在做客户管理系统时就遇到过这个情况,内外部的处理逻辑完全不一样。

小技巧: code的有效期只有5分钟,而且只能用一次。我建议你拿到code后立即处理,别在中间环节做太多耗时操作。

3.4 access_token的管理与刷新

access_token是企业微信API的「万能钥匙」。几乎所有接口都需要它。但它的有效期只有7200秒(2小时),过期了就得重新获取。

获取access_token的接口很简单:

GET https://qyapi.weixin.qq.com/cgi-bin/gettoken?
corpid=ID
&corpsecret=SECRET

返回结果:

{
  "errcode": 0,
  "errmsg": "ok",
  "access_token": "xxxxxx",
  "expires_in": 7200
}

嗯,这里我要重点说说管理策略。我见过太多人每次调用API都去获取一次access_token,这其实很浪费。正确的做法是:

  1. 缓存起来:用Redis或者本地文件存起来,别每次都请求。
  2. 提前刷新:我习惯在过期前10分钟就刷新,避免临界点问题。
  3. 加锁处理:高并发场景下,多个请求同时发现token过期,会同时去刷新。这时候需要加分布式锁。
我的实践经验: 我曾经在一个日活10万的应用里,因为access_token没做缓存,导致企业微信API调用量暴增,直接被限流了。后来改用Redis缓存+定时刷新,问题就解决了。

刷新策略的伪代码我写一下:

function getAccessToken() {
  // 先从缓存取
  token = redis.get("qywx_access_token")
  if (token != null) {
    return token
  }
  
  // 加锁,防止并发刷新
  lock = redis.lock("qywx_token_lock", 10)
  if (lock) {
    // 双重检查
    token = redis.get("qywx_access_token")
    if (token == null) {
      // 调用API获取新token
      token = fetchTokenFromAPI()
      // 设置缓存,过期时间设为7100秒(留100秒缓冲)
      redis.set("qywx_access_token", token, 7100)
    }
    redis.unlock(lock)
  }
  return token
}
特别注意: 企业微信的access_token每天有调用次数限制。我建议你在测试环境用单独的corpsecret,别和生产环境混用。否则测试跑多了,生产环境反而拿不到token。

3.5 完整流程串联

把上面这些串起来,一个完整的OAuth2.0认证流程大概是这样的:

  1. 用户访问你的应用,你检测到未登录
  2. 构造授权URL,让用户跳转到企业微信
  3. 用户授权后,企业微信回调你的redirect_uri,带上code和state
  4. 你校验state,然后用code换取用户信息
  5. 根据UserId创建或更新本地用户会话
  6. 用户登录成功,进入业务系统

说起来简单,但实际落地时坑不少。我建议你先把流程图画清楚,再动手写代码。尤其是异常处理——用户取消授权怎么办?code过期怎么办?这些都要想好。

最后说一句: OAuth2.0的调试可以用企业微信的「开发者工具」里的「OAuth2.0调试」功能。我刚开始做的时候,全靠这个工具验证回调地址和参数对不对。