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

本文代码: https://gitee.com/felord/spring-security-oauth2-tutorial/tree/wwopen/
现在很多企业都接入了企业微信,作为私域社群工具,企业微信开放了很多API,可以打通很多自有的应用。既然是应用,那肯定需要做登录。正好企业微信提供了企业微信扫码授权登录功能,而且号称使用了OAuth,正好拿这个检验一下Spring Security OAuth2专栏的威力。
正当我兴致勃勃打开文档学习的时候,脸上笑容逐渐消失,这确定是OAuth的吗?

参数都变了,跟OAuth(不管是1.0还是2.0)规定不一样,然而这还不是最离谱的。按正常OAuth2的要求,拿到code之后就可以换access_token了是吧?企业微信的access_token居然和上面扫码获取code这一步完全无关,甚至获取access_token才是第一步!

而且这个
access_token接口,你还不能频繁调用,要缓存起来公用。
那费了半天劲儿去拿code有啥用呢?

居然这个code是拿用户信息的,不得不说,我服了!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:8082
invybj.natappfree.cc会映射到我本地的8082端口,也就是我本地要开发应用的端口。
创建应用
首先去企业微信管理后台创建一个应用,如图:

图里的参数
AgentId和Secret要记下来备用。
还有一个企业微信的corpid,你可以从下面这个位置拿到,也要记下来备用。

配置内网穿透域名
在创建应用这一页往下拉到页面底端,你会看到:

点击已启用进入下面这个页面:

这里配置你授权登录应用生产的正式域名或者上面内网穿透的域名,注意只配置域名,而且不能使用localhost。
其实我感觉改写
hosts文件也能用啊,你可以试一试。
到这里环境就搞定了,接下来就开始写Spring Security兼容代码吧。
Spring Security兼容企业微信扫码登录
写起来太恶心了,不过对比文档和OAuth2的流程之后其实也没那么麻烦。我先放出我调试好的配置:
spring:
security:
oauth2:
client:
registration:
work-wechat-scan:
# client-id为企业微信 的企业ID
# 下面client-id是假的,你用你自己的企业ID
client-id: wwaxxxxxx
# client-secret企业微信对应应用的secret,
# 每个企业微信应用都有独立的secret,不要搞错
# 下面client-secret假的,你用你自己创建的企业微信应用secret
client-secret: nvzGI4Alp3zxxxxxxxKbnfTEets5W8
authorization-grant-type: authorization_code
redirect-uri: '{baseUrl}/login/oauth2/code/{registrationId}'
provider:
work-wechat-scan:
authorization-uri: https://open.work.weixin.qq.com/wwopen/sso/qrConnect
token-uri: https://qyapi.weixin.qq.com/cgi-bin/gettoken
user-info-uri: https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo
这里client-id使用你企业微信的企业ID,client-secret使用上面创建应用的secret值。
这里的
work-wechat-scan是客户端的registrationId
封装企业微信拉起二维码URL
我们期望的是保持Spring Security OAuth2的风格,当我访问:
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<OAuth2AuthorizationRequest.Builder>就行了。
逻辑是:把client_id替换为appid,增加一个agentid参数,连带redirect_uri和state四个参数之外的其它OAuth2参数全干掉,拼接成上面的URL。
这么写:

把这个Consumer配置到DefaultOAuth2AuthorizationRequestResolver就行了。
适配OAuth2获取access_token
经过这一步扫码拿到code就不成问题了,按照OAuth2该拿access_token了,需要自定义一个函数式接口:
Converter<OAuth2AuthorizationCodeGrantRequest, RequestEntity<?>>
也就是利用OAuth2AuthorizationCodeGrantRequest生成RestTemplate需要的请求对象RequestEntity<?>。按照企业微信获取access_token的文档,这样自定义:

把这个配置到DefaultAuthorizationCodeTokenResponseClient就行了。
access_token的缓存,我放在了下一步进行解决。
适配获取用户信息
code和access_token都拿到了,最后一步获取用户的信息。这里是比较麻烦的因为获取access_token后并没有直接提供将code传递给OAuth2UserService的方法。最后发现OAuth2AccessTokenResponse的additionalParameters属性可以传递到OAuth2UserService,于是就利用代理模式改造了OAuth2AccessTokenResponseClient来实现:

自定义企业微信OAuth2UserService
这个和微信网页授权我封装的差不多,改下参数封装成URI交给RestTemplate请求企业微信API。恶心的是要反序列化兼容三个微信研发工程师写的一个JSON:
@Data
public class WorkWechatOAuth2User implements OAuth2User {
private Set<GrantedAuthority> authorities;
private Integer errcode;
private String errmsg;
@JsonAlias("OpenId")
private String openId;
@JsonAlias("UserId")
private String userId;
}
收尾
拿到用户信息后,就结束了,你实现一个AuthenticationSuccessHandler来保证登录凭证和你平台一致,无论是cookie还是JWT,最后把它配置到这里:
httpSecurity.oauth2Login()
.successHandler(AuthenticationSuccessHandler successHandler)
试一下效果
务必使用域名进行访问,不要使用
localhost或者IP。
访问http://invybj.natappfree.cc/login,这里是内网穿透域名,出现:

企业微信扫码登录的地址其实就是http://invybj.natappfree.cc/oauth2/authorization/work-wechat-scan。点击跳转到扫码页面:

然后用你对应的企业微信APP扫码,企业和用户要和申请应用的一致。扫码后:

这个就是Spring Security 封装的用户认证信息Authentication对象,是真正的登录,这里我没有注入权限,你需要在企业微信的OAuth2UserService实现中注入权限和更多的信息。
总结
没有实现不了的,只要把原理和流程搞清楚就行。不过如果上游微信把代码写规范一些,下游何必写这么多冗余的代码。
关注公众号:Felordcn 获取更多资讯
Spring Security整合企业微信的扫码登录,企微的API震惊到我了的更多相关文章
- Java实现微信客户端扫码登录
此篇文章记录自己开发中的微信客户端扫码登录的实例以及步骤,便于以后自行学习记起的关键,看到的网友有借鉴的地方就借鉴,看不懂的也请别吐槽,毕竟每个人的思维和思路以及记录东西的方式不一样: 1.首先需要一 ...
- Web应用多账号系统设计及微信扫码登录实现
Web应用多账号系统设计及微信扫码登录实现 1 前言概述 公司对功能测试,性能测试,安全测试等等都做了比较好的自动化后,急需要一个MIS系统来统一管理这些结果及报表. 此MIS系统特点如下: 仅内 ...
- C#开发微信门户及应用(45)--微信扫码登录
在前面随笔<C#开发微信门户及应用(41)--基于微信开放平台的扫码登录处理>介绍了基于微信开放平台接口实现的微信扫码直接登录的过程.本篇介绍对扫码登录的一些改进和处理,以便更方便应用在实 ...
- 微信开放平台开发——网页微信扫码登录(OAuth2.0)
1.OAuth2.0 OAuth(开放授权)是一个开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用. 允许用户提供 ...
- 第三方登录:微信扫码登录(OAuth2.0)
1.OAuth2.0 OAuth(开放授权)是一个开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用. 允许用户提供 ...
- php微信开放平台--第三方网页微信扫码登录(OAuth2.0)
第一.OAuth2.0 OAuth(开放授权)是一个开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用. 允许用户提 ...
- 微信开放平台PC端扫码登录功能个人总结
最近公司给我安排一个微信登录的功能,需求是这样的: 1.登录授权 点击二维码图标后,登录界面切换为如下样式(二维码),微信扫描二维码并授权,即可成功登录: 若当前账号未绑定微信账号,扫描后提示“ ...
- Java之微信支付(扫码支付模式二)案例实战
摘要:最近的一个项目中涉及到了支付业务,其中用到了微信支付和支付宝支付,在做的过程中也遇到些问题,所以现在总结梳理一下,分享给有需要的人,也为自己以后回顾留个思路. 一:微信支付接入准备工作: 首先, ...
- spring boot高性能实现二维码扫码登录(上)——单服务器版
前言 目前网页的主流登录方式是通过手机扫码二维码登录.我看了网上很多关于扫码登录博客后,发现基本思路大致是:打开网页,生成uuid,然后长连接请求后端并等待登录认证相应结果,而后端每个几百毫秒会循环查 ...
随机推荐
- HashMap和ConcurrentHashMap的原理和实现
一.线程不安全的HashMap 多线程环境下,使用HashMap进行put操作会引起死循环(jdk1.7 Entry链表形成环形数据结构),导致CPU利用率接近100%. 结构:数组 table[]+ ...
- [ SOS ] 版本控制工具 笔记
https://www.cnblogs.com/yeungchie/ soscmd 创建工作区 soscmd newworkarea $serverName $projectName [$path] ...
- Python入门-深入了解数据类型以及方法
写在开始:每一种数据类型,有对应一种功能,面对不同的问题,使用不同类型. 1.全部数据类型 1.2数值型:解决数字的计算问题 #基础的计算,求除结果,求商,求余数 print(10 / 3) prin ...
- 轻量化安装 TKEStack:让已有 K8s 集群拥有企业级容器云平台的能力
关于我们 更多关于云原生的案例和知识,可关注同名[腾讯云原生]公众号~ 福利: ①公众号后台回复[手册],可获得<腾讯云原生路线图手册>&<腾讯云原生最佳实践>~ ②公 ...
- 更改docker默认的data,metadata存储大小(实操)
为什么要更改 data,metadata呢?我们运行环境中涉及大量数据操作,数据增长有时候很快,由于之前规划不足,所以磁盘很快达到瓶颈需要进行重新部署.这就需要调整原来的一些docker配置.操作系统 ...
- 面试官:RabbitMQ有哪些工作模式?
哈喽!大家好,我是小奇,一位不靠谱的程序员 小奇打算以轻松幽默的对话方式来分享一些技术,如果你觉得通过小奇的文章学到了东西,那就给小奇一个赞吧 文章持续更新 一.前言 今天又.又.又来面试了,还是老规 ...
- vue - scss 引入 外部 在线 css
<style lang="scss"> @import url('https://fonts.googleapis.com/css2?family=Lobster&am ...
- partTwo自动出题程序
需求介绍 一家软件公司程序员二柱的小孩上了小学二年级,老师让家长每天出30道四则运算题目给小学生做. 二柱立马就想到写一个小程序来做这件事. 这个事情可以用很多语言或者工具来实现: Excel, C/ ...
- Android Studio 的蓝牙串口通信(附Demo源码下载)
根据相关代码制作了一个开源依赖包,将以下所有的代码进行打包,直接调用即可完成所有的操作.详细说明地址如下,如果觉得有用可以GIthub点个Star支持一下: 项目官网 Kotlin版本说明文档 Jav ...
- 为何PostgreSQL即将超越SQL Server?
DB-Engines 2021年10月份统计,PostgreSQL当月上升10.30点,总分是597.27:SQLServer当月大幅下降16.32,总分是954.29 .按照这样的速度,2年之内,P ...