oauth2單點登入整合

2023-10-19 21:01:13

單點登陸

概念: 單點登入其實就是在多個系統之間建立連結, 打通登入系統, 讓同一個賬號在多個系統中通用

舉個例子: 登入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": "[email protected]",
    "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授權的相關思路