企业微信oauth认证_企业微信登陆

引言

用户登陆时,原设计是使用工号加密码进行登陆,只是工号不好记,为了推广,设计了企业微信登陆。

bVbteKp?w=1557&h=470

企业微信中可以设置自建应用,其实就是内嵌了一个Chrome,点击左侧的自建应用,会在右侧浏览器显示相关应用,所有工作都放在企业微信中,需实现当前企业微信账号自动登陆系统。

bVbteK0?w=1332&h=863

开发的过程很坎坷。让微信折腾的一点脾气都没有。

当时不会调试,因为企业微信中的自建应用要求设置成线上地址,写好了,打包,传给服务器,然后再测试。

五点,觉得还有十分钟就写完了,写完了就去吃饭。

六点、八点,改到九点半,都要改哭了,还是不好使,最后放弃了。

后来邢彦年师兄帮我梳理流程,潘老师教我调试方法,才完成这个功能。

感谢邢彦年师兄和潘老师。

实现

文档

找文档一定要找对地方,两个API,一个服务端,一个客户端。

4b271d9483c08c5aa2bfb6363f4ae5b1.png

最开始我以为是使用客户端的API呢?点进去学了学,企业微信小程序可用的API接口,这个用不了,此应用不是小程序。然后JS-SDK不支持登陆授权。

b245ee76c3573e5c221b6d55bb40a029.png

相关文档在服务端API中的身份认证一节中。

OAuth 2.0

当我们用微信登陆某个网站时,会出现类似这样的授权页面。

e35b40821088e7e2b149ad5120809b4e.png

点击确认登陆,该应用就能获取到用户相关的信息。

用户通过用户名和密码的方式进行微信的使用,第三方应用想获取微信用户信息,不是通过用户名密码,而是微信提供的令牌,这就是OAuth 2.0,既可以让应用获取不敏感的信息,又可以保证账户的安全性。

登陆流程

用户点开应用,实际上是访问当前系统微信授权的入口

dd75ac695a82bcbc6c691ba50d675477.png

微信网页授权地址:https://open.weixin.qq.com/connect/oauth2/authorize

参数

说明

appid

企业的CorpID

redirect_uri

授权后的回调地址,需使用urlencode处理

response_type

回调数据返回类型

scope

应用授权作用域。企业自建应用固定填写:snsapi_base

state

回调时额外的参数,非必选

#wechat_redirect

终端使用此参数判断是否需要带上身份信息

看这个表格也是在无聊,下面是我配置好的微信授权链接,大家只需将相应参数改写即可。注:回调的url一定要使用encodeURIComponent处理!

https://open.weixin.qq.com/connect/oauth2/authorize?appid=xxxxxxxx&redirect_uri=https%3A%2F%2Falice.dgitc.net%2Fsetup%2Fwechat&response_type=code&scope=snsapi_base#wechat_redirect

用户静默授权成功,跳转到回调地址

用户授权成功后,会带着code参数重定向到回调地址。

类似这样:

https://alice.dgitc.net/setup/wechat?code=xxxxxx

前台的组件就通过路由获取到了code,然后通过code去进一步获取用户信息。

const code = this.route.snapshot.queryParamMap.get('code');

this.userService.enterpriseWeChatLogin(code).subscribe(...);

后台通过code找微信后台获取用户信息

这个是分成两次获取,先获取access_token,再通过access_token和code获取用户信息。

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

这个是获取access_token的地址,获取access_token的过程是重点!

上面传的参数名是corpid和corpsecret,企业id和密钥。

c41777e5ad18689e0895b11a01385523.png

bVbteVv?w=422&h=335

这是企业微信的设计,企业id是一个,标识这个企业,每一个功能模块都有相应的secret。

然后企业id和secret配对,获取到只能访问这个功能模块的一个access_token。

2f9e15a3febfac624f309b9fcb2b2e6e.png

45564295c9ef448fb14c3fbee6681c7d.png

就拿当前Alice系统来举例,自建应用Alice存在secret,通过此secret和corpid获取到access_token,即相当于拿到了受保护API的访问权限。

因为这个access_token是通过Alice应用的secret获取到的,所以再用它访问其他的功能,是不合法的。

access_token有访问频率限制,所以设计了一套缓存方案。

@Override

public String getAccessTokenBySecret(String secret) {

logger.debug("从缓存中获取令牌");

String access_token = this.cacheService.get(secret);

logger.debug("如果获取到了,直接返回");

if (null != access_token) {

return access_token;

}

logger.debug("否则,发起HTTP请求");

logger.debug("获取企业验证信息");

String url = enterpriseInformation.getAccessTokenUrl();

String corpId = enterpriseInformation.getCorpid();

logger.debug("获取认证令牌");

ResponseEntity responseEntity = restTemplate.getForEntity(url + "?corpid=" + corpId + "&corpsecret=" + secret, EnterpriseAuth.class);

logger.debug("如果请求成功");

if (responseEntity.getStatusCode().is2xxSuccessful()) {

logger.debug("获取响应体");

EnterpriseAuth enterpriseAuth = responseEntity.getBody();

Assert.notNull(enterpriseAuth, "微信令牌为空");

logger.debug("如果微信请求成功");

if (enterpriseAuth.successed()) {

logger.debug("存储缓存,返回令牌");

access_token = enterpriseAuth.getAccessToken();

this.cacheService.put(secret, access_token, enterpriseAuth.getExpiresIn(), TimeUnit.SECONDS);

return access_token;

}

}

logger.debug("请求失败,返回空令牌");

return "";

}

缓存是通过把Redis工具类包装了一下实现的,很简单。

@Service

public class CacheServiceImpl implements CacheService {

/**

* Redis操作模版

*/

private final StringRedisTemplate redisTemplate;

private final ValueOperations valueOperations;

@Autowired

public CacheServiceImpl(StringRedisTemplate redisTemplate) {

this.redisTemplate = redisTemplate;

this.valueOperations = redisTemplate.opsForValue();

}

@Override

public void put(String key, String value, Long time, TimeUnit timeUnit) {

this.valueOperations.set(key, value, time, timeUnit);

}

@Override

public String get(String key) {

return this.valueOperations.get(key);

}

@Override

public void clear(String key) {

this.redisTemplate.delete(key);

}

}

access_token和code都有了,终于可以获得用户信息了。

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

这个简单了,问题出在数据不规范的问题上,大写的json,如果按这样建,实体就不符合java规范了。

{

"errcode": 0,

"errmsg": "ok",

"UserId":"USERID",

"DeviceId":"DEVICEID"

}

最后在字段添加JsonAlias注解。

@JsonAlias("UserId")

private String userId;

这里获取到的信息是用户的userId,这个userId和我们熟知的openId是不一样的。

userId就是管理员为用户在企业内设置的唯一标识,企业内唯一。

具体的后台获取userId的细节:

@Override

public Boolean enterpriseWeChatLogin(String code) {

logger.debug("构造参数");

String secret = this.enterpriseInformation.getAgentSecret();

String access_token = this.aliceCommonService.getAccessTokenBySecret(secret);

String url = this.enterpriseInformation.getUserInfoUrl() + "?code=" + code + "&access_token=" + access_token;

logger.debug("请求用户信息");

ResponseEntity responseEntity = this.restTemplate.getForEntity(url, EnterpriseUser.class);

logger.debug("如果请求成功");

if (responseEntity.getStatusCode().is2xxSuccessful()) {

logger.debug("获取响应体");

EnterpriseUser enterpriseUser = responseEntity.getBody();

Assert.notNull(enterpriseUser, "企业用户不能为空");

logger.debug("如果企业微信端也成功了");

if (enterpriseUser.successed()) {

logger.debug("获取userId");

String wxId = enterpriseUser.getUserId();

logger.debug("如果有userId,说明当前用户存在此企业中");

if (null != wxId) {

// 请自行填充登陆的具体细节

}

} else if (enterpriseUser.tokenInvalided()) {

logger.debug("token不合法,清空缓存,重新获取");

this.cacheService.clear(secret);

return this.enterpriseWeChatLogin(code);

}

}

logger.debug("其他一律返回false");

return false;

}

前台跳转,登陆成功

前台在订阅中添加跳转方法,登陆成功后,跳转到首页,登陆失败,401走拦截器,跳转到登陆页。

this.userService.enterpriseWeChatLogin(code)

.subscribe(() => {

this.userService.setCurrentLoginUser();

this.router.navigateByUrl('main');

}, () => {

console.log('network error');

});

改Host

一定要记住,非常重要!!!

cf283f21d894ef29aaf945bf6a30b91d.png

以后再碰到只能访问线上地址的情况,想在本地调试,一定要改Host!!!

总结

最后的总结就是多想想潘老师评论的这句话,有些路总不过去,很大的可能是方法错了。

3d874ab19cf197a52e6496e27230139d.png

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值