oauth2单点登录集成

发布时间 2023-10-19 17:53:18作者: huxiaofeng

单点登陆

概念: 单点登录其实就是在多个系统之间建立链接, 打通登录系统, 让同一个账号在多个系统中通用

举个例子: 登录Gmail的时候可以用账号密码登录, 也可以用google账号登录, 而使用google账号登录就是这里的单点登录

下面我将记录一下我们系统集成明道云(低代码平台)的单点登录功能

单点登录流程图

1. 集成明道云的单点登录功能

这是开发文档(虽然写的比较烂)
https://docs.pd.mingdao.com/faq/sso/oauth

有几个比较恶心的点

  • 挂载配置文件sso.json, 这个配置文件一定要配置好, 否则后患无穷

  • 另外还有一个就是几个请求的入出参数, 这两个请求都是需要在自己系统开发, 提供给明道云调用

    • /access_token
    • /userInfoUrl
  • 另外可以去私有化部署后台查看错误日志, 搜索sso

至此, 明道云算是集成完成, 这是我在本地测试环境下配置的sso.json

2. 本地测试环境搭建

这里我用flask搭建了一个测试平台, 对接第三方Github的oauth2单点登录, 如何去对接第三方github测试平台可以参考下面的文档

https://blog.csdn.net/CSDN2497242041/article/details/120416969

这里后端的思路(这里提供的后端接口都要和配置文件相对应):

  1. /login 接收明道云跳转到本地的地址
  2. /callback 对接第三方Github的回调地址(返回时会携带授权码code)
  3. /access_token 提供给明道云获取token的接口
  4. /getUserInfo 提供给明道云获取用户信息的接口

3. 本地测试源码

这些都是本地测试的情况下, 故很多数据是模拟的

from flask import Flask, request, redirect, url_for, jsonify
from oauthlib.oauth2 import WebApplicationClient
import requests

app = Flask(__name__)

# 定义OAuth2客户端配置
client_id = 'd0477fd462f8cc3a22a'
client_secret = 'be3c5c91d0d67c92217c9a20674749e316d9c11'
authorization_endpoint = 'https://github.com/login/oauth/authorize'
token_endpoint = 'http://106.15.59.77:8880/orgsso/oauth2'
redirect_uri = 'https://ae50-180-164-83-69.ngrok-free.app/callback'  # 替换成你的后端服务器的回调URL

client = WebApplicationClient(client_id)
access_token = "kl34j23kl4j23lk4jkl23"  # kl34j23kl4j23lk4jkl23
USER_INFO = {
    "uid": "112",  # 111, 112
    "name": "帅哥",
    "email": "nbaba@qq.com",
    "mobilePhone": "11111111111",
    "positions": ["职位1", "职位2"],
    "departments": ["部门1", "部门2"]
}


# 启动OAuth2认证流程
@app.route('/login')
def login():
    username = request.args.get("username")
    password = request.args.get("password")
    USER_INFO['name'] = username
    # 创建OAuth2授权请求 -> github
    authorization_url, state, _ = client.prepare_authorization_request(
        authorization_endpoint,
        redirect_url=redirect_uri
    )
    print(authorization_url)
    return redirect(authorization_url)


# 处理OAuth2回调
@app.route('/callback')
def callback():
    # 获取授权码
    code = request.args.get('code')
    print(code)

    # 到github中获取access_token
    # access_token_url = "https://github.com/login/oauth/access_token?code=%s&client_id=%s&client_secret=%s" % (
    # code, client_id, client_secret)
    # resp = requests.get(access_token_url)
    # access_token = resp.text.split("&")[0].split('=')[-1]
    # print(access_token)

    # getUserInfo_url = "https://api.github.com/user?access_token=%s" % access_token
    # headers = {
    #     "Authorization": "token %s" % access_token
    # }
    # resp = requests.get(getUserInfo_url, headers=headers)
    # print(resp.text)

    # 使用授权码请求访问令牌

    token_url = "http://106.15.59.77:8880/orgsso/oauth2"
    # params = {
    #     "code": code
    # }
    # token_response = requests.get(token_url, params=params)
    # print(token_response, token_response.text)
    return redirect(token_url + "?code=%s" % code)


@app.route('/access_token', methods=['POST'])
def token():
    data = {
        "access_token": access_token,
        "expires_in": 7200
    }
    print(data)
    return jsonify(data)


@app.route('/getUserInfo', methods=['GET'])
def get_user_info():
    response = {
        "data": USER_INFO
    }
    return jsonify(response)


if __name__ == '__main__':
    import os

    os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1'
    app.run(debug=True)

4. 前端代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
    <link rel="stylesheet" href="bootstrap-3.4.1-dist/css/bootstrap.min.css">
    <script src="bootstrap-3.4.1-dist/js/bootstrap.min.js"></script>
</head>
<body>
    <div class="container-fluid">
        <div class="row">
            <div class="col-md-6 col-md-offset-3">
                <form action="http://106.15.59.77:8880/orgsso/sso?returnUrl=http://106.15.59.77:8880/app/my">
                    <h1 class="text-center">这是Linkda的主站</h1>
                    <p>
                       <label for="username">username:</label>
                        <input type="text" class="form-control" name="username" id="username">
                    </p>
                    <p>
                        <label for="password">password:</label>
                        <input type="password" class="form-control" name="password" id="password">
                    </p>
                    <p>
                        <input type="submit" value="登录" class="btn btn-primary btn-block">
                    </p>
                </form>
            </div>
        </div>
    </div>
</body>
</html>

从最上面的思路流程图中我们可以看出来, 前端最主要的是点击提交后我们跳转的地址是http://106.15.59.77:8880/orgsso/sso?returnUrl=http://106.15.59.77:8880/app/my, 而这个地址会由明道云转发到本地的/login, 再进行后续操作

5. 单点登录效果

  1. 前端登录界面点击登录

  2. 跳转到后台, 且获取github授权码

  3. 携带code发送到明道云之后, 明道云会发两个请求 /access_token /getUserInfo 获取到用户信息就是单点登录成功

  • 这是后台接收日志

  • 会根据ReturnUrl跳转到明道云界面, 此时单点登录完成

补充:

1. 服务器如何访问本地测试地址

相信看到这里, 会有很多人问: 你后台明明是测试环境, 为什么地址是这玩意儿

"oauth2Url": "https://ae50-180-164-83-69.ngrok-free.app"

这其实就涉及到一个内网穿透的问题, 为了方便测试, 没问在本地搭的服务也就是127.0.0.1:5000在明道云私有部署的服务器之间肯定是无法访问的, 那么我们就需要去借助一个工具Ngrok将本地地址暴露到公网上, 让服务器能访问到, 这个工具的功能就类似于代理

使用起来也比较简单, 直接点击ngrok.exe文件, 在终端输入命令

ngork http 5000
# 5000可以换成本地的其他端口

此时Forwarding后面就是暴露到公网的地址

我们可以在明道云的服务器上测试, 如果又返回, 说明暴露成功

curl -X POST https://ae50-180-164-83-69.ngrok-free.app/access_token

注意: 此时的网址, 当出现302跳转的时候还是会报错, 这需要我们登录ngrok账号, 拿到Authtoken且执行以下命令才可以完成302redirect

ngrok config add-authtoken 2WvKgyYxeIpT3wyToJOwNEwXbkF_47CPhYhHcTKnyNv5qw81D

2.不使用第三方Github实现oauth2

oauth2只是一个协议, 我们可以跟着官网的规范来, 在自己的系统中跟着流程搭建自己系统的oauth2服务, 自己搭建服务有两个好处

  • 第三方Github链接不稳定, 反应迟钝用户体验感差
  • 使用Github第三方会出现授权界面(Authorize), 这样会对有自己品牌的系统产生影响(你懂的)

后面我会继续跟新关于我们系统集成oauth2授权的相关思路