portal--内实现免密登陆其他系统的方案
首先说一下需求,我们有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 vue-socket.io@3.0.7。否则旧版本+新写法会报错: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='加载中...' },
遇到的问题:
nginx 托管aos的静态文件后,通过portal访问,console了错误的日志:NET::ERR_CONTENT_LENGTH_MISMATCH 200 (OK)
百度的原因都是权限问题,
给我的nginx授权后,没有效果:sudo chmod -R 777 /usr/local/etc/nginx/*
最后,哈哈哈哈,竟然:sudo nginx,成功了,显然还是权限的问题,只不过授权错了
参考文档:https://www.freesion.com/article/4209772219/
python 中文名:蟒蛇,设计者:Guido van Rossum