我们移植应用的时候经常希望集成懒猫微服的SSO,在打包LPK上架应用的时候,可以使用官方的配置文件进行集成。但是我们今天想要刨根问底,让他变得通用一些。如果我本地的app想要集成懒猫微服的SSO,是不是也有其他的办法呢,毕竟是底层也是通用的OpenID Connect协议,于是便有了这个文章。
懒猫的SSO是如下配置:
1 2 3 4 5 6 7 8
| - Issuer:https://name.heiyu.space/sys/oauth - HTTP 监听:0.0.0.0:8000(容器内部,没有映射到宿主机端口) - gRPC 监听:0.0.0.0:5557,开启了 reflection - 存储:SQLite3 内存模式(:memory:),意味着重启后所有数据丢失 - Connector:使用 authproxy 类型,名为 hportal - 没有配置任何 staticClients(OAuth client) - 在我的网络中,IP 为 172.18.0.2 - 没有端口映射到宿主机,应该是通过反向代理(路径 /sys/oauth)访问
|
懒猫微服的SSO服务运行在5557 端口,通过 docker 网络访问地址是 172.18.0.2:5557。
可以先使用grpcurl来连接测试:
1
| ./grpcurl -plaintext 172.18.0.2:5557 list
|
在这里下载GRPC:
https://github.com/fullstorydev/grpcurl/releases
gRPC 是一个跨语言、高性能的远程过程调用(RPC)框架,它强依赖 HTTP/2 协议,并默认使用 Protobuf 作为二进制序列化协议。它的核心优势在于利用 HTTP/2 的多路复用和头部压缩提升了性能,通过二进制传输减少了带宽消耗,并且通过强类型的接口定义保证了跨语言调用的严谨性。”
然后使用grpcurl对懒猫微服的SSO的API进行操作,因为是OIDC,所以这一步骤主要一个Oauth的应用, 也就是注册App name,client_id,client_secret,以及 redirect_uris。存储用的是内存 SQLite,容器重启后所有 OAuth token、授权码、已注册的 client 都会丢失。当然如果你想持久化的话,也可以写到systemd启动脚本让系统自启动拉起来。
1
| ./grpcurl -plaintext -d '{"client":{"id":"my-app","secret":"my-app-secret","redirect_uris":["http://localhost:8080/auth/callback"],"name":"My App"}}' 172.18.0.2:5557 api.Dex/CreateClient
|

注册之后我们把这些信息放到authlib代码里面,把SSO串起来。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| from flask import Flask, redirect, url_for, session, jsonify from authlib.integrations.flask_client import OAuth from functools import wraps import os
app = Flask(__name__) app.secret_key = os.urandom(24) oauth = OAuth(app)
oauth.register( name='dex', client_id='my-app', client_secret='my-app-secret', server_metadata_url='https://aimax.heiyu.space/sys/oauth/.well-known/openid-configuration', client_kwargs={'scope': 'openid email profile'}, )
def login_required(f): @wraps(f) def decorated(*args, **kwargs): if 'user' not in session: return redirect(url_for('login')) return f(*args, **kwargs) return decorated
@app.route('/') def index(): user = session.get('user') if user: return f'Hello, {user.get("email", user.get("name", "unknown"))}. <a href="/profile">Profile</a> | <a href="/logout">Logout</a>' return 'Welcome! Please <a href="/login">Login</a>.'
@app.route('/login') def login(): return oauth.dex.authorize_redirect(url_for('authorize', _external=True))
@app.route('/auth/callback') def authorize(): token = oauth.dex.authorize_access_token() session['user'] = token.get('userinfo') session['token_info'] = { 'access_token': token.get('access_token'), 'id_token': token.get('id_token'), 'token_type': token.get('token_type'), 'expires_at': token.get('expires_at'), } return redirect(url_for('index'))
@app.route('/profile') @login_required def profile(): return jsonify(userinfo=session['user'], token=session.get('token_info'))
@app.route('/logout') def logout(): session.pop('user', None) return redirect(url_for('index'))
if __name__ == '__main__': app.run(host='0.0.0.0', port=8080, debug=True)
|
这是一个用 Flask + authlib 对接 懒猫 SSO 的最小 OIDC 客户端应用:
- 通过 懒猫 SSO(OpenID Connect Provider)实现单点登录
- oauth.register 配置 懒猫 SSO 的 OIDC 发现端点,自动获取授权/token 等地址
- login_required 装饰器做路由守卫,未登录自动跳转登录
- /login 发起 OAuth2 授权码流程,跳转到 懒猫 SSO 登录页
- /auth/callback 接收 懒猫 SSO 回调,用授权码换取 access_token 和用户信息,存入 session
- /profile 展示当前登录用户的 userinfo 和 token 信息
- /logout 清除 session 登出
整个流程就是标准的 OAuth2 Authorization Code Flow:用户点登录 → 跳 懒猫 SSO → 认证通过 → 回调拿 token → 存
session → 完成登录。
访问应用的时候,一开始会出现这个认证,这个是懒猫域名自带的认证,是为了应用放在公网的上的强制用户名密码认证,所以不要把他当作是我们本次懒猫SSO的主角。

这个才是正式的OpenID Connect,点击Grant Access,然后就可以进行认证了。

登录之后我们可以查看profile信息,以及登录之后token,这样就抓到了OIDC的去全部信息:

如果之前注册的是 localhost,但 Flask 默认用127.0.0.1 。所以会收到Unregistered redirect_uri 的错误。所以把域名改成localhost就好。

好了,以上就是如何超越系统注册,使用API建立自己的懒猫SSO应用了,这样我们就可以不必再依赖三方的IDP了。
Less is more。