基于IdentityServer的系统对接微信公众号
业务需求
公司有两个业务系统,A和B,AB用户之间属于多对一的关系,数据库里面也就是两张表,A表有个外键指向B。现在需要实现以下几个功能。
- A用户扫描B的二维码,填写相关的注册信息,注册完成之后自动属于B。也就是表A的外加字段指向B。
- 老用户和微信openid绑定。
- 用户在公众号里面自动登录。
项目结构
公司项目基于.net core 2.1 + Vue,
后端有以下几个子系统:
- 基于IdentityServer4 的asp.net mvc,简称account 项目,配了域名account.xxx.com
- 两个业务系统api。A和B。分别域名配置aapi.xxx.com 和bapi.xxx.com
- 其他。。
前端有以下几个系统,都是基于Vue的SPA:
- A业务系统,域名a.xxx.com
- B业务系统,域名b.xxx.com
- 其他。
登录这块的逻辑实现方式是类似的。都是基于IdentityModel/oidc-client-js
简单介绍一下IdentityServer这个东西。
用户登录A或B系统,就是调用A和B对应的webapi,webapi配置了自己的验证服务器是account服务器,account验证未通过,前端就得到401状态码,通过oidc-client-js的内部方法引导用户进行登录。跳转account的页面,用户输入用户名密码,登录成功,account服务器判断是A or B过来的登录请求,带上token回跳到配置的对应页面。业务系统再次用获取到的token请求api,调用成功。用一个图来说。
实现方法
用了盛派微信sdk,特别感谢大佬的贡献。
推荐一下微信沙箱环境,项目做完下来除了"无法在测试的公众号里面推送小程序消息”无法实现之外(因为推送的需要公众号和小程序有一个绑定关系),其他都ok。
因为版本的关系,account系统升级了asp.net core 2.2。
先实现上面第一个需求
这里用到微信里面生成带参数的二维码功能。B系统创建了用户之后,生成一个对应的guid,然后把这个guid作为参数,调用sdk就能得到二维码的url。
//创建ticket
var qrRstTicketRst = await QrCodeApi.CreateAsync(weixinSetting.WeixinAppId, 30, 100000,
QrCode_ActionName.QR_LIMIT_STR_SCENE, sceneId);
//通过ticket获取二维码对应的url
var url = QrCodeApi.GetShowQrCodeUrl(qrRstTicketRst.ticket);
这里我们项目中用到的是永久二维码
,虽然这个二维码上限10W个,我们业务系统B用户不会超过那么多。
B用户展示二维码给A用户,A用户扫描,根据文档:
如果用户还未关注公众号,则用户可以关注公众号,关注后微信会将带场景值关注事件推送给开发者。
如果用户已经关注公众号,在用户扫描后会自动进入会话,微信也会将带场景值扫描事件推送给开发者。
触发代码里面分别对应的是OnEvent_SubscribeRequest
和OnEvent_ScanRequest
,两个方法里面的代码基本上是一样的。RequestMessageEvent_Scan.EventKey
可以得到上面的guid值。Subscribe事件里面得到的EventKey会比Scan的多一个qrscene
前缀,处理的时候要注意一点。两个方法参数都能通过FromUserName
获取到扫描的用户的openId,然后在这个方法里面返回一个带参数(A的openId,和B的guid)的注册链接,A用户注册的时候就提交了这两个参数,后台就能拿到。
顺道说一句,公众号里面用户每次操作只能被动返回一条消息。如要主动推送,需要用模板消息的方式。
实现第二个需求
对于老用户,这里需要一个账号绑定的功能。也就是业务系统的账号和openId做一个关联。绑定的关键在于这个如何获取这个openId,这里有两种方式。
- 用户点击公众号的菜单,后端获取到这个事件,在
OnEvent_ClickRequest
中,判断RequestMessageEvent_Click.EventKey==xxx
,返回一个带openId的绑定页面的链接给用户。比如/bind?openId=xxx,用户点击这个链接,系统引导用户登录,然后点击绑定按钮,实现绑定。 - 基于微信网页授权,这个在自动登录里面也用到了,所以下面解释。
实现第三个需求
系统中用户和微信的openId已经绑定,所以,只要知道每次访问页面的openId就应该能实现自动登录。openId是通过微信网页授权的方式获取到。流程可以看文档。简单来说,先拿code,再换token,同时拿到openId。实现步骤分以下几步。
- 添加一个公众号菜单,type是view,也就是点了之后会打开一个页面,页面地址直接用获取code的url.
{
"type": "view",
"name": "登录A",
"url":"https://open.weixin.qq.com/connect/oauth2/authorize?appid=wxb66259f2a353&redirect_uri=http%3A%2F%2Faccount.xxx.cn%2Fweixincallback%2Fcallback&response_type=code&scope=snsapi_base&state=spa.A#wechat_redirect"
}
url中的state
参数会和code一起返回给设置的redirectUrl,这个可以用来给我们在account登录中心判断是需要登录A还是B,以便最后回跳到对应的业务页面。
这里在沙箱配置跳转域名的时候注意一下,只要写域名就好。
- 打开页面,需要用户点允许授权。通过之后浏览器会把code 和 state参数带这get请求redirect_url
- callback页面的逻辑
callback 接收code和state两个参数。
public async Task<IActionResult> Callback(string code, string state){...}//方法签名
用这个code调用sdk里面的api获取token,同时可以拿到openid。
var tokenResult = await OAuthApi.GetAccessTokenAsync(AppId, AppSecret, code);
if (tokenResult.errcode != ReturnCode.请求成功)
{
throw new BizException("获取微信用户信息失败");
}
var openId = tokenResult.openid;
通过open获取用户信息。
var userInfo = await userService.GetByOpenId(openId);//userService是自己的业务service
然后调用HttpContext.SignInAsync
登录。
public static async Task SignInAsync(this HttpContext context, string subject, string name, AuthenticationProperties properties, params Claim[] claims)
{
var clock = context.GetClock();
var user = new IdentityServerUser(subject)
{
DisplayName = name,
AdditionalClaims = claims,
AuthenticationTime = clock.UtcNow.UtcDateTime
};
await context.SignInAsync(user, properties);
}
HttpContext是当前请求的上下文。
subject可以理解为用户的标识。
name可以理解是用户显示的名字。
AuthenticationProperties是此次认证的一些配置,比如有效时长之类的。
Claim可以理解为这个subject带的一些属性。
await HttpContext.SignInAsync(userMobile, userName, props, claims);
调用完之后就登录成功。
然后通过带来的state参数判断需要跳转的client。
var client = await clientStore.FindClientByIdAsync(state);
return Redirect($"{client.PostLogoutRedirectUris.FirstOrDefault()}?logined=true");
这里带一个logined=true参数,用来给client做一些逻辑。
总结
首先要感谢的肯定是盛派微信sdk的contributors,没有他们系统对接起来应该会慢很多。
然后我想说,IdentityServer是个好东西,现在公司.NET相关的系统都已经用这个实现统一的登录逻辑了,系统维护的代价小了许多。
说起来其实也是第一次对接微信公众号相关的东西,在走通这条路之前走了不少弯路,不过好在走通了。希望对其他人有帮助。
基于IdentityServer的系统对接微信公众号的更多相关文章
- 在微信框架模块中,基于Vue&Element前端的微信公众号和企业微信的用户绑定
在一个和微信相关的业务管理系统,我们有时候需要和用户的微信账号信息进行绑定,如对公众号.企业微信等账号绑定特定的系统用户,可以进行扫码登录.微信信息发送等操作,用户的绑定主要就是记录公众号用户的ope ...
- PHP应用如何对接微信公众号JSAPI支付
微信支付的产品有很多,1. JSAPI支付 2. APP支付 3. Native支付 4.付款码支付 5. H5支付. 其中基于微信公众号开发的应用选择“JSAPI支付“产品,其他APP支付需 ...
- 苹果CMSv10对接微信公众号教程
首先声明下,对接公众号的话需要自行注册公众号“订阅号” 对接失败的原因大多是域名变红导致!简单的测试方法就是把域名链接发给qq好友或是qq群里看看有没有变红 域名变红以后大概率不会对接成功的,请知悉 ...
- Java对接微信公众号模板消息推送
内容有点多,请耐心! 最近公司的有这个业务需求,又很凑巧让我来完成: 首先想要对接,先要一个公众号,再就是开发文档了:https://developers.weixin.qq.com/doc/offi ...
- 从Python爬虫到SAE云和微信公众号:二、新浪SAE上搭建微信服务
目的:用PHP在SAE上搭建一个微信公众号的服务器. 1.申请一个SAE云账号 SAE申请地址:http://sae.sina.com.cn/ 可以使用微博账号登陆,SAE是新浪的云服务,时间也比较 ...
- 个人微信公众号搭建Python实现 -开发配置和微信服务器转入-配置说明(14.1.2)
@ 目录 1.查看基本配置 2.修改服务器配置 3.当上面都配置好,点击提交 4.配置如下 1.查看基本配置 登录到微信公众号控制面板后点击基本配置 这里要讲的就是订阅号 前往注册微信公众号 2.修改 ...
- CRMEB系统就是集客户关系管理+营销电商系统,能够真正帮助企业基于微信公众号、小程序实现会员管理、数据分析,精准营销的电子商务管理系统。可满足企业新零售、批发、分销、等各种业务需求。
**可以快速二次开发的开源小程序商城系统源码**源码开源地址:https://github.crmeb.net/u/LXT 项目介绍: CRMEB系统就是集客户关系管理+营销电商系统,能够真正帮助企业 ...
- 微信公众号支付(JSAPI)对接备忘
0 说明 本文里说的微信公众号支付对接指的是对接第三方支付平台的微信公众号支付接口. 非微信支付官方文档里的公众号支付开发者文档那样的对接.不过,毕竟腾讯会把一部分渠道放给银行或有支付牌照的支付机构, ...
- 微信公众号开发系列-13、基于RDIFramework.NET框架整合微信开发应用效果展示
1.前言 通过前面一系列文章的学习,我们对微信公众号开发已经有了一个比较深入和全面的了解. 微信公众号开发为企业解决那些问题呢? 我们经常看到微信公众号定制开发.微信公众平台定制开发,都不知道这些能给 ...
随机推荐
- BZOJ_3011_[Usaco2012 Dec]Running Away From the Barn _可并堆
BZOJ_3011_[Usaco2012 Dec]Running Away From the Barn _可并堆 Description 给出以1号点为根的一棵有根树,问每个点的子树中与它距离小于l的 ...
- Angularjs interceptor
angularJs 请求过滤 新建一个服务, $HttpProvider 中有一个 interceptore 数组,所谓的拦截器就是一个注册到该数组的工厂,该工厂在app.config() 中注入, ...
- Pandas 错误笔记(持续更新)
更新至2018.5.1 字典生成DataFrame 今天一个字典生成一个DataFrame,采用了以下形式,每一个value都是一个数(不是vector) df = pd.DataFrame({ 'i ...
- 如何在招聘中考核.NET架构师
.NET架构师招聘不如JAVA那么顺利,可以搜索到的.NET架构师可以说是凤毛菱角.当然好的架构师都是需要长期观察和挖角才能得手,如何去招聘到合适的.NET架构师可能是摆在所有求贤者面前的难题.这里的 ...
- Docker常见故障
— Docker虚拟化故障 — Docker虚拟化主要有三类故障: 应用故障:应用执行状态与预期不一致. 容器故障:无法正确创建.停止.更新容器等. 集群故障:集群创建失败.更新失败.无法连接等. — ...
- windows粘贴板操作-自己的应用和windows右键互动
一.粘贴板操作函数 BOOL OpenClipboard(HWND hWnd);参数 hWnd 是打开剪贴板的窗口句柄,成功返回TRUE,失败返回FALSE BOOL CloseClipboard() ...
- 为什么HTTPS比HTTP更安全?
摘要: 理解HTTPS. 作者:浪里行舟 Fundebug经授权转载,版权归原作者所有. 前言 近几年,互联网发生着翻天覆地的变化,尤其是我们一直习以为常的HTTP协议,在逐渐的被HTTPS协议所取代 ...
- Chrome启动后打开第一个网页很慢的解决方案
Chrome启动后打开第一个网页很慢的解决方案 Chrome/Chromium以速度快著称,最近每当打开chrome的时候,打开第一个页面都非常慢,往往需要数十秒的时间,经分 析,应该是卡在了域名解析 ...
- SqlServer中的系统数据库
SqlServer中的系统数据库有五个,平时写代码不太关注,今天一时兴起研究了一下. 1. master 记录SQL Server系统的所有系统级信息,例如:登陆账户信息.链接服务器和系统配置设置.记 ...
- ZJOI2019二轮游记
Postscript 这个彩笔的省选随心游被中考实验考试坑掉了 所以前两天都一直脱离部队,第一天讲课完了才有的过去 一轮凉了那么二轮翻盘?翻车预定.之后还有上海的ACM没有CXR神仙的ACM窝怎么打啊 ...