portal--內實現免密登陸其他系統的方案
阿新 • • 發佈:2022-05-27
首先說一下需求,我們有2套前後端的專案要做整合,其中一套使用開源系統scui作為portal,另外一套A專案以iframe的形式加到portal選單裡去。並且想要實現從portal跳轉A專案時候是免密的,無需再次登陸。
這時候瞭解到vue的localstorage存的資訊在同一個域名,同一個埠的情況下,可以共享localstorage,只需要將2個系統的localstorage的key存成一致的,且value形態是一致的。
我們的方式是:藉助caddy啟動portal前+後端,caddy埠40080;用caddy再將A專案的前+後端啟動,caddy埠50080。這時再配置nginx,用nginx的1個埠代理這兩個caddy的埠,通過nginx的location來分別分發到40080和50080。
這樣做的好處是:2個系統可以使用各自的埠單獨使用,也可以通過portal免密到A專案。可獨立可共存。
然後在程式碼的層面作出修改,為什麼需要修改程式碼?舉例,2個系統的登陸介面可能都是/api/auth/login,那麼用nginx的這個埠去訪問的話,可能會轉發錯誤。所以需要給A專案增加一級url,比如:/aos/api/auth/login。通過這樣的方式實現了2個系統的巢狀使用。
專案部署
# 安裝caddy:(mac:brew install caddy) 或者下載https://caddyserver.com/download caddy是go語言的,免安裝,linux裡都能拷貝過去就用。
-----------nginx的配置--------------------
server { listen 80 default_server; server_name localhost 10.10.10.10; location / { proxy_pass http://127.0.0.1:40080; } location/aos/{ proxy_pass http://127.0.0.1:50080; } }
portal部署
--------portal專案配置bin/Caddyfile------
{ admin off } :40080 { handle /api/* { reverse_proxy /api/* 127.0.0.1:8000 } handle { root * /mnt/it-ops-portal-platform/web file_server try_files {path} /index.html } log { output file bin/logs/httpd.log } }
----------restart.sh-------------
#!/bin/bash source /etc/profile programpath=/mnt/portal cd ${programpath}; pwd # web & vue ps aux | grep ${programpath}/bin/caddy | grep -v grep | awk '{print $2}' | xargs kill -9 sleep 1 ${programpath}/bin/caddy start --config ${programpath}/bin/Caddyfile # api ps aux| grep ${programpath}/manage.py | grep -v grep | awk '{print $2}' | xargs kill -9 sleep 1 nohup python3 ${programpath}/manage.py run >/dev/null 2>&1 &
A專案部署
-----------A專案bin/Caddyfile----------
{ admin off } :50080 { handle /aos/api/* { reverse_proxy /aos/api/* 127.0.0.1:5000 } handle { root * /mnt/it-ops-product-center-platform/web encode gzip # 前端靜態檔案壓縮gzip後,需要做配置才能訪問到壓縮後的檔案 file_server try_files {path} /index.html } log { output file bin/logs/httpd.log } }
---------A專案restart.sh-------
#!/bin/bash source /etc/profile programpath=/mnt/A cd ${programpath}; pwd # web & vue ps aux | grep ${programpath}/bin/caddy | grep -v grep | awk '{print $2}' | xargs kill -9 sleep 1 ${programpath}/bin/caddy start --config ${programpath}/bin/Caddyfile # task ps aux | grep "celery -A app.main.service.celerytask.celery worker -l info --workdir ${programpath}" | grep -v grep | awk '{print $2}' | xargs kill -9 sleep 1 nohup celery -A app.main.service.celerytask.celery worker -l info --workdir ${programpath} >/dev/null 2>&1 & # api ps aux | grep ${programpath}/manage.py | grep -v grep | awk '{print $2}' | xargs kill -9 sleep 1 nohup python3 ${programpath}/manage.py run >/dev/null 2>&1 &
上程式碼:
vue將所有請求加上一級url
-------router/index.js-----
export default new Router({ mode: 'history', # 要新增的路由 base: '/aos/', routes: [
------config/index.js------
module.exports = { # 要新增的路由 publicPath: '/aos/', build: { env: require('./prod.env'), index: path.resolve(__dirname, '../dist/index.html'), assetsRoot: path.resolve(__dirname, '../dist'), # 靜態資源路徑,通過npm run build之後,原先dist目錄下的static目錄前會增加一層目錄:dist/aos/static… dist/index.html assetsSubDirectory: 'aos/static', assetsPublicPath: '/', productionSourceMap: true, # 這裡改為了false,不生成map檔案 productionGzip: false, # 這裡後來改了true,將前端靜態檔案壓縮,可以有效的減少vue頁面首次載入的白屏時間,參考:https://blog.csdn.net/weixin_44668908/article/details/109157082 productionGzipExtensions: ['js', 'css'], bundleAnalyzerReport: process.env.npm_config_report }, dev: { env: require('./dev.env'), port: 8082, autoOpenBrowser: true, # 靜態資源路徑 assetsSubDirectory: 'aos/static', assetsPublicPath: '/', proxyTable: { }, cssSourceMap: false, }
flask socketio官方文件
https://flask-socketio.readthedocs.io/en/latest/api.html?highlight=path#flask_socketio.SocketIO flask 怎麼接收這個請求呢? 沒改路由之前是OK的,但是改的過程中發現:可能報跨域問題,404問題,等等,然後才發現,flask_socket也自帶path屬性,前後端的path值保持一致即可------------manage.py-------------
from flask_socketio import SocketIO,send,emit app = create_app(os.getenv('BOILERPLATE_ENV') or 'dev') # flask http請求的base_url app.register_blueprint(blueprint,url_prefix='/aos') CORS(app, resources=r'/*') CORS(app,supports_credentials=True) # path為socket.io的路由 socketio = SocketIO(app,cors_allowed_origins='*',path='/aos/api/socket/') # jenkins應用構建 @socketio.on('jenkins_build') def jenkins_build_start(message,sid): message = json.loads(urllib.parse.unquote(message)) message['action'] = 'can_deploy_app' response = jenkins_job_build(message) if response.get('code')==200: thread = socketio.start_background_task(target=background_thread_get_build_info,kwargs=response,sid=sid) else: socketio.emit('jenkins_build_console', {'text': response},room=sid,broadcast=True) # 定時獲取jenkins構建日誌 def background_thread_get_build_info(sid,**kwargs): while True: check_args = kwargs.get('kwargs').get('msg') tail_output,status = check_app_build_consolelog(check_args) if tail_output: tail_output = tail_output+'<br/>載入中…' socketio.emit('jenkins_build_console', {'text': {'code':200,'msg':tail_output}},room=sid, broadcast=True) print("status",status) if status : tail_output = tail_output + '<br/>任務完成!' socketio.emit('jenkins_build_console', {'text': {'code': 200, 'msg': tail_output}},room=sid,broadcast=True) build_result = {} build_result['log_detail'] = tail_output build_result['status'] = status build_result['app_name'] = check_args.get('app_name') build_result['job_id'] = check_args.get('job_id') build_result['app_id'] = check_args.get('app_id') task = save_jenkins_build_job_log(build_result) task = save_jenkins_build_job_log.delay(build_result) back_up_build_production_backage.delay(check_args) break socketio.sleep(5) @socketio.on('connect', namespace='/aos') def test_connect(): print('=====socketio====') socketio.emit('my response', {'data': 'Connected'}) @socketio.on('disconnect', namespace='/aos') def test_disconnect(): print('Client disconnected'
Socket io的預設路由改成指定字首的url
----------config/urls.js----------
export default { // api請求地址 // API_URL: 'http://127.0.0.1:5000/aos', // // socketio請求地址 // SOCKET_URL: 'http://127.0.0.1:5000' API_URL: 'http://1.1.1.1:50080/aos', SOCKET_URL: 'http://1.1.1.1:50080' }
-----------main.js---------
socketio物件可以加的一些屬性:https://blog.csdn.net/ZYS10000/article/details/122737466 import URLS from '../config/urls' import VueSocketio from 'vue-socket.io' // vue-socket.io 2.1.1舊版本引用方式 // Vue.use(VueSocketio,URLS.API_URL,store); // URLS.SOCKET_URL = http://127.0.0.1:5000 // 如下配置需要將版本升級:npm install [email protected]。否則舊版本+新寫法會報錯:Uncaught TypeError: Vue2.default is not a constructor Vue.use(new VueSocketio({ debug:true, //# 不自動連結,指定頁面的指定場景再連結 autoConnect: false, connection:URLS.SOCKET_URL, vuex:{ store, }, options:{ //# 通過path屬性可以將socketio原來預設的url中/socket.io/部分替換成path變數 path:'/aos/api/socket/' } }))---------vue指定頁面-------
created() { // this.$socket.connect(); // this.$socket.open(); this.handleClick() }, sockets:{ // 接收應用構建日誌 jenkins_build_console: function(val){ if (val['text']['code']!=200){ alert(val['text']['msg']) }else{ document.getElementById('app_build_logs').innerHTML=val['text']['msg'] // 監聽滾動事件 document.querySelector(".box").addEventListener('scroll',this.scrolling) this.scrollToBottom(); } }, }, methods: { // 執行構建 execute_built() { // 釋出分支和回滾版本必選 if (!this.form.branch){ alert('請選擇釋出分支') return false } # 開啟socket io this.$socket.open(); var params = { app_id: this.app_id, branch: this.form.branch, username: JSON.parse(localStorage.getItem('username')) } document.getElementById('app_build_logs').innerHTML='' console.log(this.$socket.id) this.$socket.emit('jenkins_build',encodeURI(JSON.stringify(params)),this.$socket.id); document.getElementById('app_build_logs').innerHTML='載入中...' },