当前位置: 首页 > 后端技术 > Java

Spring Security整合企业微信的扫码登录,企微的API惊讶到我了

时间:2023-04-02 00:28:30 Java

SpringSecurity集成了企业微信的扫码登录,奇微的API让我惊喜领域社区工具,企业微信开放了很多API,可以开放很多自有应用。既然是应用,那肯定是要登录的。正好企业微信提供了企业微信扫码授权登录的功能,并且号称使用OAuth。只需使用它来测试SpringSecurityOAuth2专栏的强大功能。就在我兴奋地打开文档学习时,脸上的笑容渐渐消失了。你确定是OAuth吗?参数变了,跟OAuth的规定不一样(不管是1.0还是2.0),但这还不是最离谱的。按照正常的OAuth2要求,拿到code后就可以改access_token了吧?企业微信的access_token和上面扫码获取code这一步没有任何关系,甚至获取access_token都是第一步!还有这个access_token接口,你不能经常调用它,它得缓存起来供公众使用。花很长时间弄代码有什么用?其实这段代码是拿用户信息的,不得不说,我服了!OAuth2的123进程改成213了,算了,命名能不能稍微用心一点,一会儿下划线,一会儿驼峰:{"errcode":0,"errmsg":"ok","OpenId":"OPENID","DeviceId":"DEVICEID","external_userid":"EXTERNAL_USERID"}这个json样式确实是大厂,注意了!三个人写一个JSON才算体面!反序列化的时候,我得给你写一个兼容的。这是为了填我的KPI吧?算了,忍一忍,老大要这个功能,小菜一碟,开发者还得含着泪吃,干!环境准备内网穿透准备微信相关应用的开发需要内网穿透,我在之前的文章中有介绍。创建一个映射域名,像这样:http://invybj.natappfree.cc->127.0.0.1:8082invybj.natappfree.cc会映射到我本地的8082端口,也就是我要在本地开发应用的端口.创建应用首先要到企业微信管理后台创建一个应用,如图:图中的参数AgentId和Secret要记录下来,以备后用。还有一个企业微信Corpid,可以从下面的位置获取,也记下来以备后用。配置内网穿透域名创建应用时下拉到页面底部,会看到:点击启用,进入如下页面:这里配置您授权登录应用的官方域名或上面的域名内网穿透,注意只配置域名,不能使用localhost。其实我觉得重写hosts文件也可以,大家可以试试。环境到此安顿下来,接下来开始编写SpringSecurity兼容代码。SpringSecurity兼容企业微信扫码登录,写起来很恶心,不过对比文档和OAuth2流程,倒是没那么麻烦。我先放出我调试好的配置:spring:security:oauth2:client:registration:work-wechat-scan:#client-id是微信企业的企业ID#下面的client-id是假的,你用自己的enterpriseIDclient-id:wwaxxxxxx#client-secret企业微信应用的秘密,#每个企业微信都有一个独立的secret,不要搞错#下面的client-secret是假的,你用的是企业微信你自己创建的秘密客户端秘密:nvzGI4Alp3zxxxxxxxKbnfTEets5W8/open.work.weixin.qq.com/wwopen/sso/qrConnecttoken-uri:https://qyapi.weixin.qq.com/cgi-bin/gettokenuser-info-uri:https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo这里client-id使用你企业微信的企业ID,client-secret使用上面创建的应用的secret值。这里的work-wechat-scan就是客户端的registrationId包。微信拉取二维码网址。我们期望的是保持SpringSecurityOAuth2的风格。当我访问:http://invybj.natappfree.cc/oauth2/authorization/work-wechat-scan会重定向到企业微信扫码登录链接,格式为:https://open.work.weixin.qq。com/wwopen/sso/qrConnect?appid=CORPID&agentid=AGENTID&redirect_uri=REDIRECT_URI&state=STATE这个和之前胖哥授权微信网页的原理类似。它们都是通过修改OAuth2AuthorizationRequestResolver接口实现的,只需要实现一个Consumer即可。其逻辑是:将client_id替换为appid,增加一个agentid参数,去掉除redirect_uri和state之外的所有OAuth2参数,拼接到上述URL中。这么写:只要将这个Consumer配置为DefaultOAuth2AuthorizationRequestResolver即可。适配OAuth2获取access_token这一步之后,扫码取码就不成问题了。根据OAuth2,是时候获取access_token了。需要自定义一个功能接口:Converter>,需要使用OAuth2AuthorizationCodeGrantRequest请求对象RequestEntity生成RestTemplate。根据企业微信获取access_token文件,自定义如下:将这个配置为DefaultAuthorizationCodeTokenResponseClient即可。access_token的缓存,我放在下一步解决。适配获取用户信息code和access_token已经获取,最后一步就是获取用户信息。这里比较麻烦,因为没有办法在获取access_token后直接将代码传给OAuth2UserService。最后发现OAuth2AccessTokenResponse的additionalParameters属性可以传递给OAuth2UserService,于是我采用代理方式改造OAuth2AccessTokenResponseClient实现:自定义企业微信OAuth2UserService这个类似于我封装的微信网页授权,将参数包改成一个URI,交给RestTemplate去请求企业微信API。恶心的是反序列化了一个兼容三位微信研发工程师的JSON:@DatapublicclassWorkWechatOAuth2UserimplementsOAuth2User{privateSetauthorities;私有整数错误代码;私有字符串错误消息;@JsonAlias("OpenId")私有字符串openId;@JsonAlias("UserId")privateStringuserId;}最后,拿到用户信息后,就结束了。你实现一个AuthenticationSuccessHandler来保证登录凭证和你的平台一致,不管是cookie还是JWT,最后在这里配置:httpSecurity.oauth2Login().successHandler(AuthenticationSuccessHandlersuccessHandler)试试效果。一定要使用域名访问,不要使用localhost或IP。访问http://invybj.natappfree.cc/login,这里是内网穿透域名,出现:企业微信扫码登录地址其实是http://invybj.natappfree.cc/oauth2/authorization/work-微信-扫一扫。点击跳转到扫码页面:然后使用您对应的企业微信APP扫码,企业和用户必须与申请申请一致。扫码后:这是SpringSecurity封装的用户认证信息Authentication对象,才是真正的登录。这里我没有注入权限。您需要在企业微信的OAuth2UserService实现中注入权限和更多信息。综上所述,没有什么是做不到的,只要把原则和流程弄清楚。但是,如果上游的微信把代码写的更规范一些,为什么下游还要写那么多多余的代码。关注公众号:Felordcn获取更多资讯个人博客:https://felord.cn