惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

酷 壳 – CoolShell
酷 壳 – CoolShell
H
Hacker News: Front Page
P
Palo Alto Networks Blog
T
ThreatConnect
Apple Machine Learning Research
Apple Machine Learning Research
博客园_首页
T
True Tiger Recordings
P
Privacy & Cybersecurity Law Blog
B
Blog
IT之家
IT之家
Last Week in AI
Last Week in AI
F
Full Disclosure
Hacker News: Ask HN
Hacker News: Ask HN
C
Comments on: Blog
Microsoft Azure Blog
Microsoft Azure Blog
C
Cybersecurity and Infrastructure Security Agency CISA
Microsoft Security Blog
Microsoft Security Blog
博客园 - 【当耐特】
N
News and Events Feed by Topic
NISL@THU
NISL@THU
腾讯CDC
雷峰网
雷峰网
Security Latest
Security Latest
李成银的技术随笔
M
Microsoft Research Blog - Microsoft Research
L
LangChain Blog
L
Lohrmann on Cybersecurity
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
C
Check Point Blog
Y
Y Combinator Blog
Recent Announcements
Recent Announcements
博客园 - Franky
N
News | PayPal Newsroom
V
V2EX
A
About on SuperTechFans
The Register - Security
The Register - Security
月光博客
月光博客
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Google Online Security Blog
Google Online Security Blog
MyScale Blog
MyScale Blog
Cisco Talos Blog
Cisco Talos Blog
Vercel News
Vercel News
WordPress大学
WordPress大学
C
Cyber Attacks, Cyber Crime and Cyber Security
The Hacker News
The Hacker News
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
爱范儿
爱范儿
A
Arctic Wolf
L
LINUX DO - 最新话题
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More

博客园 - 黄洪波

安装openclaw 排查项目中依赖的mybatis 拦截器 ModelAttribute 老革命遇上新问题 使用calcite构造ddl建表语句 IDEA自带的Maven 3.9.x无法刷新http nexus私服(转) windows docker安装rocketmq之踩坑记 分布式系统设计经典论文(转载) 训练自己的yolo-v11数据集(二) 训练自己的yolo-v11数据集(一) 本地使用pycharm进行yolo推理 2024年的云原生架构需要哪些技术栈 (转) yolo v11学习,入门篇 - 黄洪波 OpenWebUI单点登录之深坑 AI工具验证 解决Win10无法进入睡眠模式(转) idea常用插件 内网离线模式下激活JRebel java导入json数据至doris 将SpringBoot打包之后的jar设为守护进程
OpenWebUI单点登录之解决动态参数问题
黄洪波 · 2025-03-10 · via 博客园 - 黄洪波

我一直以为自己已经写了这一篇,直到好几位网友留言我才发现自己其实没有写。

本篇分为四章
1.动态传参失败的原因

2.解决方案

3.剩余问题

4.过程中踩的坑放最后

言归正传:

动态传参失败的原因:
构造登录地址:http://owl.tyl.com/?name=zxx&email=zxx@xxx.com.cn

跳转到http://owl.tyl.com/

真正问题出在从页面点击链接到后面真正的跳转登录过程中请求头没有往下带,跳转过程中参数丢了。

我是看了无数遍nginx日志才看出来的,也是官网中没有写的地方。

解决方案:

这个时候就得想办法保持会话,gpt告诉我用cookie。

于是各种折腾,想到了一个办法,既然cookie可行,那就用以下思路:

1.当发现请求地址携带参数 email 和name时,将其放置到 会话cookie中,后续所有的请求获得该cookie,并在所有请求将其放入请求头X-User-Email 和X-User-Name中,允许跨站访问,在nginx日志中将cookie的值以及X-User-Email X-User-Name打印出来

调试的过程不必细讲,最终解决方案如下:

最终解决方案如下,基本完美解决

新的逻辑如下:

1.当发现请求地址携带参数 email 和name时,将其放置到 会话cookie中,后续所有的请求获得该cookie,

2.并在请求/auth或/api/v1/auths/或/api/v1/auths/signin时将其放入请求头X-User-Email 和X-User-Name中,允许跨站访问,

3.在/api/v1/auths/signout时删除会话中存储的name和email。

4.在nginx日志中将cookie的值以及X-User-Email X-User-Name打印出来

之所以说完美解决,只剩下几个很小的问题了

a.用户a点击了登出,用户b登录后再登出,此时用户a在登录,失败,必须关掉浏览器重新登录--无需处理

b.浏览器地址栏把用户名和邮箱明文展示,--问题不大

c.官方说明:启动的时候只能选择一种模式,经测试,使用trust header的模式,第一个登录的账户被默认为管理员账户(我使用了docker模式,没有测试本地安装模式)

d.trusted header模式不会自动创建用户,得管理员自己去后台创建或导入用户

解决方案:

1.配置nginx

2.自定义open webui的login页面(还有一个更6的解决方案,在单点来源的系统登录的之后,种下基于*.xyz.com的全局cookie X-User-Email X-User-Name,这样连login.html都不用写了。

配置文件:

server {
    listen 80;
    server_name owl.tyl.com;

    # 添加访问日志
    access_log C:/nginx-1.26.2/logs/owl.tyl.com.access.log custom_format;

    location /ws/socket.io/ {
        access_log off;  # 禁用访问日志
        proxy_pass http://127.0.0.1:3000;
        # WebSocket 特殊头
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";

        # 其他配置
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
#         proxy_set_header X-Forwarded-Proto $scheme;
        # 防止 WebSocket 超时
        proxy_read_timeout 600s;
    }


    # 静态页面
    location /login.html {
        root C:/nginx-1.26.2/html/tyl; # 静态文件存放目录
        index login.html;

        # CORS 配置,支持跨域访问
        add_header Access-Control-Allow-Origin * always;
        add_header Access-Control-Allow-Methods "GET, POST, OPTIONS" always;
        add_header Access-Control-Allow-Headers "Content-Type" always;
    }


    location / {
        proxy_pass http://127.0.0.1:3000;

        # 从 Cookie 提取用户信息
        set $user_email "";
        set $user_name "";

        if ($http_cookie ~* "X-User-Email=([^;]+)") {
            set $user_email $1;
        }

        if ($http_cookie ~* "X-User-Name=([^;]+)") {
            set $user_name $1;
        }

        proxy_set_header X-User-Email $user_email;
        proxy_set_header X-User-Name $user_name;

        # CORS 配置
        add_header Access-Control-Allow-Origin * always;
        add_header Access-Control-Allow-Methods "GET, POST, OPTIONS" always;
        add_header Access-Control-Allow-Headers "X-User-Email, X-User-Name, Content-Type" always;
#         add_header Access-Control-Max-Age 3600 always;

        if ($request_method = OPTIONS) {
            return 204;
        }

        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }


    location /api/v1/auths/signout {
        # 删除 Cookie 中的 X-User-Name 和 X-User-Email
        add_header Set-Cookie "X-User-Name=; Path=/; HttpOnly; SameSite=Lax; Max-Age=0;";
        add_header Set-Cookie "X-User-Email=; Path=/; HttpOnly; SameSite=Lax; Max-Age=0;";

        # 代理到后端的注销逻辑
        proxy_pass http://127.0.0.1:3000;

        # 传递常见的请求头设置
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

日志格式文件:

    # 配置访问日志格式
    include       mime.types;
    default_type  application/octet-stream;
    

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  logs/access.log  main;
    
    
    # 配置访问日志格式
    log_format custom_format '$remote_addr - $remote_user [$time_local] "$request" '
                          '$status $body_bytes_sent "$http_referer" '
                          '"$http_user_agent" "$http_x_forwarded_for" '
                          'Request-URI=$request_uri '
                          'X-User-Email=$arg_email '
                          'X-User-Name=$arg_name '
                          'Accept=$http_accept '
                          'Content-Type=$http_content_type '
                          'User-Agent=$http_user_agent '
                          'X-Real-IP=$http_x_real_ip '
                          'X-Forwarded-For=$http_x_forwarded_for '
                          'X-Forwarded-Proto=$http_x_forwarded_proto'
                          'cookie: "$http_cookie"';

                              
                              
    # 引用独立的配置文件
    include C:/nginx-1.26.2/conf/conf.d/*.conf;'cookie: "$http_cookie"';

自定义login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Redirect tyl</title>
    <script>
        function redirectToSubmit() {
            // 动态获取用户信息,api,
            const userEmail = "zmm@t.c";
            const userName =  "zmm";
            // 设置用户信息到 Cookie
            document.cookie = `X-User-Email=${userEmail}; Path=/;`;
            document.cookie = `X-User-Name=${userName}; Path=/;`;

            window.location.href = "http://owl.xyz.com";

    </script>
</head>
<body>
<h1>Redirect index</h1>
<button onclick="redirectToSubmit()">Go to index</button>
</body>
</html>

完毕。

插入分割线,折腾的全过程:

问题1:为啥在nginx中配置静态常量的参数,就能单点成功,变成动态从地址栏取 $arg_parameter就失败呢

location / {
    
    
        proxy_pass http://127.0.0.1:3000;  # 后端服务地址
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        
        # 添加自定义请求头
                # 失败 ,一直报授权错误                 
                # Your provider has not provided a trusted header. Please contact your administrator for assistance.
        #proxy_set_header X-User-Email $arg_email;
        #proxy_set_header X-User-Name $arg_name;
        # 添加自定义请求头
                # 成功
        proxy_set_header X-User-Email "zmm@t.c";
        proxy_set_header X-User-Name "zmm";
        
    }

按说语法不可能有错,浏览器访问地址:http://owl.tyl.com/auth?name=xxx&email=xxx@tt.com.cn

尝试了无数次,从一开始就是卡在这个问题上,兜了一个大圈,压根儿就不是-e ENABLE_OAUTH_SIGNUP=true的事情

后来想办法日志打出来

1.最开始以为是语法问题,没拿到相关的变量,甚至写了个SpringBoot后端,打印日志发现没错

2.后来又想办法在nginx日志中打印出来

# 配置访问日志格式

# 配置访问日志格式
    log_format custom_format '$remote_addr - $remote_user [$time_local] "$request" '
                          '$status $body_bytes_sent "$http_referer" '
                          '"$http_user_agent" "$http_x_forwarded_for" '
                          'Request-URI=$request_uri '
                          'X-User-Email=$arg_email '
                          'X-User-Name=$arg_name '
                          'Accept=$http_accept '
                          'Content-Type=$http_content_type '
                          'User-Agent=$http_user_agent '
                          'X-Real-IP=$http_x_real_ip '
                          'X-Forwarded-For=$http_x_forwarded_for '
                          'X-Forwarded-Proto=$http_x_forwarded_proto'
                  'cookie: "$http_cookie"';

发现只有零星几个日志中正常拿到了参数X-User-Name的值,大量都是 X-User-Name= -

3.这个时候仍然以为是语法错误

4.千辛万苦,日志一遍一遍看

日志就不放了

于是第一个转机出现了

识到真正问题出在从页面点击链接到后面真正的跳转过程中请求头没有往下带,跳转过程中丢了

这个时候就得想办法保持会话,gpt告诉我用cookie。

于是各种折腾,想到了一个办法,既然cookie可行,那就用以下思路:

1.当发现请求地址携带参数 email 和name时,将其放置到 会话cookie中,后续所有的请求获得该cookie,并在所有请求将其放入请求头X-User-Email 和X-User-Name中,允许跨站访问,在nginx日志中将cookie的值以及X-User-Email X-User-Name打印出来

搞出来第一个配置文件。

但是新问题又来了,这个思路下,用户没法注销或者登出啊,在一个浏览器上永远只有一个用户,除非openwebui默认的auth机制失效,那就得另想办法了。

登出时日志如下,因为按照以上逻辑,所有请求都会读取cookie,并将cookie放入header中,可以看到auth被触发了。

于是又各种看日志,找到了sign out相关的api,于是在该请求里面将cookie清除即可解决。