前一篇已经大致安装部署本地的open-webui的基础环境了,我们使用deepseek过程中,可能涉及到与已有系统的账号统一登录的情况。官方文档有一些关于如何对接的文档,稍显复杂,一时半会不太能掌握,自己就试着做一点简单的修改,实现一键登录需求。
大致思如如下:
- A系统有[email protected] 的账号,在A系统页面增加一个按钮,自动登录到B系统;
- B(open-webui)系统,前端通过url传递参数,然后提交到B系统后端;
- B系统后端校验参数,识别到系统也存在[email protected]的账号,然后后端带着传递的参数请求A系统,
- A系统校验参数合法,返回给B系统后端,
- B系统后端接受到返回,如果校验无误,结果返回给B系统前端
- B系统前端接收到后端返回结果,完成登录
大致流程如下:
作为示例,只做简单的md5校验
前端访问 http://127.0.0.1:8080/[email protected]
前端把 token和email两个参数传递到后端。
后端对email的md5值和token做比较完成用户的校验
这个是open-webui的标准登录页面。
我们参考这个页面的登录逻辑,做一下修改
前端部分
1 . 首先我们看下 open-webui/src/routes/auth/+page.svelte 文件
这个是前端的登录页,
关注下如下部分的代码
const signInHandler = async () => {
const sessionUser = await userSignIn(email, password).catch((error) => {
toast.error(`${error}`);
return null;
});await setSessionUser(sessionUser);
};
这个是用户登录的函数,
主要是通过userSignIn这个函数完成用的登录动作。
userSignIn函数在文件open-webui/src/lib/apis/auths/index.ts文件里实现的
export const userSignIn = async (email: string, password: string) => {
let error = null;const res = await fetch(`${WEBUI_API_BASE_URL}/auths/signin`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
credentials: 'include',
body: JSON.stringify({
email: email,
password: password
})
})
.then(async (res) => {
if (!res.ok) throw await res.json();
return res.json();
})
.catch((err) => {
console.log(err);error = err.detail;
return null;
});if (error) {
throw error;
}return res;
};
我们可以参考这部分代码,写出自己的实现如下:
在open-webui/src/routes/auth/+page.svelte文件的js部分增加如下代码
- #自定义登录函数
- const mySignIn = async () => {
- const params = new URLSearchParams(window.location.search);
- const token = params.get('token');
- const email = params.get('email');
-
- const sessionUser = await mySignIn (email, token).catch((error) => {
- return null;
- });
- await setSessionUser(sessionUser);
- };
-
- #从url里获取token、email两个参数,传递到函数userTokenSignIn里完成后台请求完成登录
-
- #onMount增加我们的函数
- onMount(async () => {
- await mySignIn ();
- ......
- });
在open-webui/src/lib/apis/auths/index.ts文件参考userSignIn函数增加mySignIn 函数:
只需要修改后端请求的URL,其他部分都是照抄
- export const mySignIn = async (email: string, token: string) => {
- let error = null;
-
- const res = await fetch(`${WEBUI_API_BASE_URL}/auths/mySignIn`, {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json'
- },
- credentials: 'include',
- body: JSON.stringify({
- email: email,
- token: token
- })
- }) .then(async (res) => {
- if (!res.ok) throw await res.json();
- return res.json();
- })
- .catch((err) => {
- error = err.detail;
- return null;
- });
-
- if (error) {
- throw error;
- }
- return res;
- };
前端部分大部分已经完成。
说明下:评论区有人要完整的文件代码,我上面贴的代码就是是新增的,其他的代码就是官网的代码;这里改代码不是问题,主要是编译环境的搭建弄起来费时间,还容易出各种问题。
后端部分
后端的登录在open-webui/backend/open_webui/routers/auths.py文件里面
首先看先之前的用户登录代码
############################
# SignIn
############################@router.post("/signin", response_model=SessionUserResponse)
async def signin(request: Request, response: Response, form_data: SigninForm):......
user = Auths.authenticate_user(form_data.email.lower(), form_data.password)......
主要是通过SigninForm接受参数,
然后通过 Auths.authenticate_user实现email和password的校验
这个部分代码在 open-webui/backend/open_webui/models/auths.py里实现
def authenticate_user(self, email: str, password: str) -> Optional[UserModel]:
log.info(f"authenticate_user: {email}")
try:
with get_db() as db:
auth = db.query(Auth).filter_by(email=email, active=True).first()
if auth:
if verify_password(password, auth.password):
user = Users.get_user_by_id(auth.id)
return user
else:
return None
else:
return None
except Exception:
return None
我们参考这两部分代码,不需要做太大的修改就可以实现我们的需求
在open-webui/backend/open_webui/routers/auths.py增加我们的实现mySignIn函数
只需要修改用户校验部分,其他部分都原封不动的照抄signin的函数
- ......
-
- from open_webui.models.auths import (
- AddUserForm,
- ApiKey,
- Auths,
- Token,
- LdapForm,
- SigninForm,
- MySigninForm, #引入自定义的表单接受
- SigninResponse,
- SignupForm,
- UpdatePasswordForm,
- UpdateProfileForm,
- UserResponse,
- )
-
- ############################
- # mySignIn
- #form_data用的是自定义的 MySigninForm
- #用户验证用的是自定义的 authenticate_user_mySignIn
- ############################
- @router.post("/mySignIn", response_model=SessionUserResponse)
-
- async def mySignIn(request: Request, response: Response, form_data: MySigninForm):
- ......
-
- user = Auths.authenticate_user_mySignIn(form_data.email.lower(), form_data.token)
-
- ......
#自定义的函数最后一行,错误提示,也可以自定义下,
#不改也可以,就是报错情况下,提示的是用户名或者密码错误,有点不完美
raise HTTPException(400, detail=ERROR_MESSAGES.INVALID_CRED)
增加自定义报错在文件open-webui/backend/open_webui/constants.py中修改
open-webui/backend/open_webui/models/auths.py里实现用户的校验函数
authenticate_user_mySignIn
还需要定义一个 MySigninForm 用于接受参数
- import hashlib #需要用到计算md5
- ......
-
- #自定义接受参数
- class MySigninForm(BaseModel):
- email: str
- token: str
- #自定义用户登录参数校验
- def authenticate_user_mySignIn(self, email: str, token: str) -> Optional[UserModel]:
- try:
- with get_db() as db:
- auth = db.query(Auth).filter_by(email=email, active=True).first()
- if auth:
- #校验token,这里只简单的做md5的校验
- md5hash = hashlib.md5(email.encode())
- md5_token = md5hash.hexdigest()
- if token == md5_token:
- user = Users.get_user_by_id(auth.id)
- return user
- else:
- return None
- else:
- return None
- except Exception:
- return None
- ......
至此这个简单的校验email的md5值的token登录方式就实现了
我们访问地址
http://127.0.0.1:8080/[email protected]
如果token是email的md5值。就可以实现用户自动登录
chrome浏览器,打开开发者工具->网络->Fetch/XHR;检查是否完成
关于修改后的部署
如果你是通过docker部署的open-webui,代码修改后需要如下操作:
前端编译后会成才一个build的目录,覆盖到docker里原先的build目录;
----------前端覆盖docker的build文件夹操作-----------
- 1.压缩前端编译后的build文件夹
-
- tar -czvf build.tar.gz ./build/
-
- 2,压缩文件复制到docker并解压缩
-
- #复制压缩文件到docker
- docker cp ./build.tar.gz open-webui:/app/backend/
- #进入docker
- docker exec -it open-webui /bin/bash
- #返回docker根目录、移动压缩文件到根目录
- cd ../
- mv ./backend/build.tar.gz ./
-
- #备份前端
- mv build build_b
-
- #解压缩前端
- tar -zxvf build.tar.gz ./
后端直接把修改的文件覆盖到docker里对应的文件;
然后重启docker。
最后总结下需要修改的几个文件
前端代码:
open-webui/src/routes/auth/+page.svelte
open-webui/src/lib/apis/auths/index.ts
后端代码:
open-webui/backend/open_webui/routers/auths.py
open-webui/backend/open_webui/models/auths.py
这4个文件修改就可以了。
---------------------------------------------------------------------------------------------
可以本地写一个python文件,用与生成email和token
-
- def create_md5_token(email):
- md5hash = hashlib.md5(email.encode())
- md5_token = md5hash.hexdigest()
-
- print("auth?token="+md5_token+"&email="+email)
-
- return md5_token
-
-
- emails = [
- ]
-
- for email in emails:
- create_md5_token(email)
---------------------------------------------------------------------------------------------
后续发现,前端代码的修改直接放在
open-webuib/src/routes/+layout.svelte
里实现更好,同时需要增加setSessionUser函数。
---------------------------------------------------------------------------------------------
至此,可以把这个链接集成到原有的系统,实现单点登录。
token的加密方式可以更复杂一些,加入一些其他参数
其他问题
如果您仅安装open webui,没有安装和配置olllama和deepSeek。自动登录后,登录成功页会卡住好久。请求会卡在获取模型的地方,一直到超时才会展示完整的页面。
请确保olllama和deepSeek已经安装并且配置好。
评论记录:
回复评论: