Halcon+MFC工业模板匹配实战:从环境搭建到产线鲁棒部署
2026/10/15 21:19:28
version: "3" services: appsmith: image: index.docker.io/appsmith/appsmith-ce:v2.1 container_name: appsmith environment: - APPSMITH_SSL_ENABLED=true - APPSMITH_CUSTOM_DOMAIN=podding.cn # 家里虚拟机不加这行https访问也可以 ports: - "80:80" - "443:443" volumes: - ./stacks:/appsmith-stacks restart: unless-stopped# cat stacks/configuration/docker.env # Sentry APPSMITH_SENTRY_DSN= # Smart look APPSMITH_SMART_LOOK_ID= # Google OAuth APPSMITH_OAUTH2_GOOGLE_CLIENT_ID= APPSMITH_OAUTH2_GOOGLE_CLIENT_SECRET= # Github OAuth APPSMITH_OAUTH2_GITHUB_CLIENT_ID= APPSMITH_OAUTH2_GITHUB_CLIENT_SECRET= # Form Login/Signup APPSMITH_FORM_LOGIN_DISABLED= APPSMITH_SIGNUP_DISABLED= # Segment APPSMITH_SEGMENT_KEY= #Client log level (debug | error) APPSMITH_CLIENT_LOG_LEVEL= # Email server APPSMITH_MAIL_ENABLED= APPSMITH_MAIL_HOST= APPSMITH_MAIL_PORT= APPSMITH_MAIL_USERNAME= APPSMITH_MAIL_PASSWORD= APPSMITH_MAIL_FROM= APPSMITH_REPLY_TO= # Email server feature toggles # true | false values APPSMITH_MAIL_SMTP_AUTH= APPSMITH_MAIL_SMTP_TLS_ENABLED= # Disable all telemetry # Note: This only takes effect in self-hosted scenarios. # Please visit: https://docs.appsmith.com/telemetry to read more about anonymized data collected by Appsmith APPSMITH_DISABLE_TELEMETRY=false #APPSMITH_SENTRY_DSN= #APPSMITH_SENTRY_ENVIRONMENT= # Google Recaptcha Config APPSMITH_RECAPTCHA_SITE_KEY= APPSMITH_RECAPTCHA_SECRET_KEY= APPSMITH_RECAPTCHA_ENABLED= APPSMITH_DB_URL=mongodb://appsmith:hB7i0a3DMaprr@localhost:27017/appsmith APPSMITH_POSTGRES_DB_URL=postgresql://appsmith:hB7i0a3DMaprr@localhost:5432/appsmith APPSMITH_MONGODB_USER=appsmith APPSMITH_MONGODB_PASSWORD=hB7i0a3DMaprr APPSMITH_REDIS_URL=redis://:o50cICEdwHLtr@127.0.0.1:6379 APPSMITH_REDIS_PASSWORD=o50cICEdwHLtr APPSMITH_ENCRYPTION_PASSWORD=88sgsqNUOyLS5 APPSMITH_ENCRYPTION_SALT=4bBnjg011Nv2Q APPSMITH_CUSTOM_DOMAIN= # Java command line arguments, as space-delimited string. Ex: "-Xms800M -Xmx800M" APPSMITH_JAVA_ARGS= # APPSMITH_PLUGIN_MAX_RESPONSE_SIZE_MB=5 # MAX PAYLOAD SIZE # APPSMITH_CODEC_SIZE= # Set this to a space separated list of addresses that should be allowed to load Appsmith in a frame. # Example: "https://mydomain.com https://another-trusted-domain.com" will allow embedding on those two domains. # Default value, if commented or not set, is "'none'", which disables embedding completely. # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/frame-ancestors APPSMITH_ALLOWED_FRAME_ANCESTORS="'self' *" APPSMITH_DISABLE_IFRAME_WIDGET_SANDBOX=falseimport requests import logging from urllib.parse import urljoin, urlparse, parse_qs from flask import Flask, redirect, request logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(filename)s - line %(lineno)d - %(levelname)s - %(message)s' ) app = Flask(__name__) BASE_URL = "http://10.69.84.14:9280" def get_csrf(): """获取csrf值""" url = urljoin(BASE_URL, "api/v1/consolidated-api/view") response = requests.request(method="GET", url=url) cookies_dict = response.cookies.get_dict() logging.info(f"cookies_dict: {cookies_dict}") csrf_token = cookies_dict.get('XSRF-TOKEN') if not csrf_token: raise ValueError("无法获取XSRF-TOKEN") return csrf_token def register(csrf_token, username, password): """ 正常场景时跳转的接口:http://10.69.84.14:9280/signup-success?redirectUrl=http%3A%2F%2F10.69.84.14%3A9280%2Fapplications%2F6a195617f9f2e66092daccea%2Fpages%2F6a195617f9f2e66092daccec%2Fedit&enableFirstTimeUserExperience=true 异常场景时跳转的接口: http://10.69.84.14:9280/user/signup?error=There%20is%20already%20an%20account%20registered%20with%20this%20email%20test%40qq.com.%20Please%20sign%20in%20instead. :param csrf_token: :param username: :param password: :return: """ url = urljoin(BASE_URL, "api/v1/users") headers = { "Content-Type": "application/x-www-form-urlencoded", "Cookie": f"XSRF-TOKEN={csrf_token}" } body = { "_csrf": f"{csrf_token}", "email": username, "password": password } resp = requests.request(method="POST", url=url, headers=headers, data=body, allow_redirects=True) status_code = resp.status_code logging.info(f"返回状态: {status_code}, resp.url:{resp.url}") if status_code in [302, 200] and '/signup-success?redirectUrl' in resp.url: return True, "OK" if status_code in [302, 200] and '/user/signup?error=' in resp.url: parsed_url = urlparse(resp.url) query_params = parse_qs(parsed_url.query) error_content = query_params.get('error', [None])[0] # 获取error参数(注意:parse_qs返回的是列表) logging.info(f"error_content: {error_content}") if "There is already an account registered with this email" in error_content: return True, "OK" else: return False, error_content return False, "appsmith register failed" @app.route("/login_and_go/<username>/<password>") def login_and_jump(username, password): # http://10.69.84.14:5000/login_and_go/zhang@qq.com/Zhang@123 try: csrf_token = get_csrf() has_user, content = register(csrf_token, username, password) if not has_user: raise ValueError(content) url = urljoin(BASE_URL, "api/v1/login") headers = { "Content-Type": "application/x-www-form-urlencoded", "Cookie": f"XSRF-TOKEN={csrf_token}" } body = { "_csrf": f"{csrf_token}", "username": username, "password": password } # 使用Session自动处理cookie和重定向 session = requests.Session() # session设置cookie session.cookies.set("XSRF-TOKEN", csrf_token) # 发送登录请求 response_obj = session.post(url, headers=headers, data=body, allow_redirects=False) status_code = response_obj.status_code logger.info(f"login--> response_obj.headers: {response_obj.headers}, Cookies: {response_obj.cookies}") if status_code == 302: """ 登录正常的话,理论上响应头里存在的location:'Location': '/applications', 登录密码错误,响应头里的location大概是:'Location': '//user/login?error=true' 登录账号锁定,响应头里的location大概是:'Location': '/user/login?error=true&message=Your+account+is+suspended+for+24+hours.+Please+reset+your+password+to+continue' """ location = response_obj.headers['Location'] logger.info(f"location: {location}") if location.startswith('//user/login?error=true'): logger.info("Authentication failed") raise Exception("Authentication failed") if location.startswith('/user/login'): message = parse_qs(urlparse(location).query).get('message', [''])[0] logger.error(message) raise Exception(message) # 获取登录后的cookies cookies = session.cookies.get_dict() # 获取所有cookie logging.info(f"statu_code: {status_code}, cookies: {cookies}") # allow_redirects=False时为302,allow_redirects=True时是200 # 重定向到目标页面 redirect_url = urljoin(BASE_URL, "/applications") resp = redirect(redirect_url) # 将cookie传递给客户端 for key, value in cookies.items(): resp.set_cookie( key, value, httponly=True, secure=False, # 生产环境应设置secure=True. 需要 HTTPS,否则很多浏览器会拒绝 samesite="Lax", # SameSite=None 才允许跨站携带 cookie,但需配合secure=True ) # 添加额外的响应头帮助跨域 resp.headers['Access-Control-Allow-Origin'] = '*' return resp else: error_msg = f"登录失败,状态码: {response_obj.status_code}" logging.error(error_msg) return { "error": error_msg, "status_code": status_code, }, status_code except Exception as e: logging.exception(f"跳转到appsmith失败,error is: {e}") return { "error": str(e), "status_code": 500 }, 500 if __name__ == '__main__': app.run(host='0.0.0.0', port=5000, debug=True) # csrf_token = get_csrf() # res = register(csrf_token, "chen@qq.com", "Chen@123") # logging.info(f"res: {res}") ''' 这个flask应用部署在appsmith服务器上(10.69.84.14),在本地访问http://10.69.84.14:5000/login_and_go/zhang@qq.com/Zhang@123可以正常跳转到appsmith应用页面。 这个flask应用部署在本地机器上,在本地访问http://127.0.0.1:5000/login_and_go/zhang@qq.com/Zhang@123无法正常跳转到appsmith应用页面 -- 跨域导致 '''官网:Security | Appsmith
临时方案:
把redis的数据文件(dump.rdb)删除,再重启appsmith即可