SaaS化实践——如何用一个微信公众号登录多个不同的域名

24次阅读

共计 2118 个字符,预计需要花费 6 分钟才能阅读完成。

背景
SaaS 作为一种服务,需要为不同的客户定制不同的域名以满足客户定制化的需求。而微信登录时需要填写一个回调地址,单一的回调地址是难以处理多客户域名的业务需求的,经过不同的 SaaS 项目的实践,总结出了下面的方式。
微信登录的核心代码依然采用 psa 这个库 https://github.com/python-soc…。
微信说明
阅读微信公众平台文档,可以看到,当同一个微信公众号需要在多个服务间使用时,微信的建议是提供一台中控服务器,防止 access_token 的重复刷新,这个坑确实踩到过。
oauth 2.0
https://tools.ietf.org/html/r…

核心概念、表结构
中控机
中控机为同一引导用户登录的微信登录服务器,其中此机器做的为 oauth 2.0 截图部分的 A、B,引导用户授权,微信回调到此中控机,拿到 code。中控机通过 state 参数,解除 customerid,根据 customer 配置找到回调地址。回调是将 state,code 带去回调的客户域名。
customer
customer 表需要记录微信的 appid,appsecret,这样即使客户需要定制自己的微信公众号,中控机也可以 saas 化。
redirecturl
由于微信的 state 参数长度有限,因此提供一张 redirecturl 表记录回调地址,登录时只需要将 redirecturl_id 带入 state 中即可。redirecturl 记录的为回调客户域名 +psa compelate 地址的完整路由。
state
state 为 oauth 2.0 中允许的回调参数,state 的构成为: 客户 id,回调地址 id,其他需要回调参数
核心流程

核心代码
中控机通过 customer 获取对应的 appid,secret。微信回调到 cherrypick 后,拿着 code,state 跳转到对应的客户域名。

def _auth(request, backend):
cid = request.GET[‘cid’]
# TODO: DoesNotExist
customer = Customer.objects.get(id=cid)
appid, appsecret = customer.get_key_and_secret()
log.info(‘login cid:%s, key:%s’, cid, appid)
def get_key_and_secret():
return appid, appsecret
request.backend.get_key_and_secret = get_key_and_secret
return do_auth(request.backend)

@never_cache
@psa(‘our_social:cherrypick’)
def auth(request, backend, key=”):
return _auth(request, backend)

@never_cache
@psa()
def cherrypick(request, backend):
code = request.GET.get(‘code’, ”)
state = request.GET.get(‘state’, ”)
redirect_url_id = state.split(‘,’)[0]
redirect_url = RedirectURL.objects.get(id=redirect_url_id).url
redirect_url = ‘{}?code={}&state={}’.format(redirect_url, code, state)
log.info(‘cherrypick, redirect_url: %s, state: %s’, redirect_url, state)
return redirect(redirect_url)
SaaS 服务器处理 oauth 2.0 C、D 之后的步骤
@psa(‘our_social:complete’)
def complete(request, backend, *args, **kwargs):
“””Authentication complete view”””
logout(request)
state = request.GET.get(‘state’, ”)
……
state 解析出 cid 等参数
customer = Customer.objects.get(id=cid)
appid, appsecret = product.get_key_and_secret()
request._customer = customer
覆盖 backend 的方法
def get_key_and_secret():
log.info(‘login complete use appid: %s %s’, appid, state)
request.backend.get_key_and_secret = get_key_and_secret
return do_complete(request.backend, _do_login, request.user,
redirect_name=REDIRECT_FIELD_NAME, request=request,
*args, **kwargs)

正文完
 0