chainlit身份验证方案oauth2.0及常用社交应用账户集成

chainlit身份验证方案oauth2.0及常用社交应用账户集成

阅读原文

建议阅读原文,始终查看最新文档版本,获得最佳阅读体验:《chainlit身份验证方案oauth2.0及常用社交应用账户集成》

本文摘要

本文详细说明了如何将chainlit与Microsoft AD(LDAP)集成,以便于企业用户通过域账号登录到chainlit,另外,还简要介绍了两个功能类似的开源项目lobechat和librechat。

chainlit简介

官网:Overview - Chainlit

github网址:Chainlit/chainlit: Build Conversational AI in minutes ⚡️

chainlit是一个用于快速构建AI对话式聊天机器人的开源python库,其最大的特点是,可以很方便的构建类似于chatGPT那样的前端页面

请至钉钉文档查看附件《chainlit演示视频.mp4》

类似的开源项目

Lobe Chat

lobe-chat/README.zh-CN.md at main · lobehub/lobe-chat

LobeHub - LobeChat:个人 LLM 效能工具,超越 ChatGPT / OLLaMA 使用体验

lobechat是现代化设计的开源 ChatGPT/LLMs 聊天应用与开发框架支持语音合成、多模态、可扩展的(function call)插件系统,一键免费拥有你自己的 ChatGPT/Gemini/Claude/Ollama 应用

lobechat也是支持OAuth2.0的

lobechat的github stars数远高于librechat和chainlit,高达6万多。

请至钉钉文档查看附件《lobechat演示视频.webm》

LibreChat

librechat.ai/docs        danny-avila/LibreChat: Enhanced ChatGPT Clone: Features Agents, DeepSeek, Anthropic, AWS, OpenAI, Assistants API, Azure, Groq, o1, GPT-4o, Mistral, OpenRouter, Vertex AI, Gemini, Artifacts, AI model switching, message search, Code Interpreter, langchain, DALL-E-3, OpenAPI Actions, Functions, Secure Multi-User Auth, Presets, open-source for self-hosting. Active project.

官方介绍视频:https://youtu.be/ilfwGQtJNlI

LibreChat 是一款面向所有人工智能对话的终极开源应用程序,它完全可定制且兼容任何AI服务提供商——所有这些功能都集成在一个时尚流畅的界面中

LibreChat原生支持LDAP,同时也支持OAuth2.0

image.png

chainlit支持的身份验证提供商

参考资料:Overview - Chainlit

chainlit支持这三种身份认证方式:

image.png

其中OAuth又包括了以下几种,可以看到,支持的OAuth providers是非常多的,几乎包含了所有的社交账号,而keycloak本身也支持很多平台。

image.png

安装chainlit

参考资料:Installation - Chainlit

Linux系统

首先要安装python和pip,此过程省略

注意,下面几行命令是在ubuntu desktop 24.04系统上运行的,Windows系统命令有所区别

#创建虚拟环境
python3 -m venv chainlit
#激活虚拟环境
source ./chainlit/bin/activate
#用pip安装chainlit包
pip install --upgrade chainlit

image.png

image.png

Windows系统,trae(vs code)

先通过trae(用vs code或cursor也是可以的)创建一个空的app.py文件,然后通过命令面板创建虚拟环境

image.png

成功创建虚拟环境后,就可以在资源管理中看到自动生成了.env文件夹

image.png

激活虚拟环境

.venv\Scripts\activate

image.png

检查当前python解释器是不是虚拟环境中的解释器,如果不是,务必选择虚拟环境中的解释器

image.png

用pip安装chainlit包,时间会比较长,因为国内下载包会比较慢

pip install --upgrade chainlit

用github验证身份

创建一个github app

参考资料:OAuth - Chainlit

注册 GitHub 应用 - GitHub 文档

点击此链接,然后创建一个github app

下图是我已经创建好的一个github app

关键是callback url、client secret(可以直接生成)

Request user authorization (OAuth) during installation这个一定要勾选。

webhook不用勾选

private key也是必须的,直接生成即可,网页会提示的

image.png

安装github app

注册好github app后,还要安装此github app,很简单,点击install app,然后右侧会显示待安装和已安装的github app,下图是我已经安装的github app

image.png

验证

启动chainlit app

chainlit run .\text_to_SQL.py -d -w

text_to_SQL.py代码如下:

import os
from openai import AsyncOpenAI
from chainlit.oauth_providers import OAuthProvider
import chainlit as cl

import httpx
from fastapi import HTTPException
from chainlit.user import User

import json
cl.instrument_openai()

""" import os

# 手动加载.env文件
from dotenv import load_dotenv
load_dotenv() """

# 打印环境变量
""" print(os.getenv("OAUTH_KEYCLOAK_BASE_URL"))
print(os.getenv("OAUTH_KEYCLOAK_REALM"))
print(os.getenv("OAUTH_KEYCLOAK_CLIENT_ID"))
print(os.getenv("OAUTH_KEYCLOAK_CLIENT_SECRET"))
print(os.getenv("OAUTH_KEYCLOAK_NAME")) """

#user_env = cl.user_session.get("env") #从.env文件中获取环境变量
# 从环境变量中获取API KEY
api_key = os.getenv("OPENAI_API_KEY")
api_key = "<此处替换为你的api_key>"
print(os.getenv("OPENAI_API_KEY")) 

if api_key is None:
    raise ValueError("OPENAI_API_KEY environment variable is not set.")

client = AsyncOpenAI(
    api_key=api_key,
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"
)


# 优化后的模板,让指令更清晰
template = """SQL tables (and columns):
* Customers(customer_id, signup_date)
* Streaming(customer_id, video_id, watch_date, watch_minutes)

Generate a well - written SQL query to {input} and return the query wrapped in triple backticks (```):
```"""


settings = {
    "model": "qwen-plus",
    "temperature": 0,
    "max_tokens": 500,
    "top_p": 1,
    "frequency_penalty": 0,
    "presence_penalty": 0,
    # 可以尝试去掉 stop 参数
    # "stop": ["```"],
}



@cl.set_starters
async def starters():
    return [
       cl.Starter(
           label=">50 minutes watched",
           message="Compute the number of customers who watched more than 50 minutes of video this month."
       )
    ]

@cl.on_message
async def main(message: cl.Message):
    try:
        stream = await client.chat.completions.create(
            messages=[
                {
                    "role": "user",
                    "content": template.format(input=message.content),
                }
            ], stream=True, **settings
        )

        msg = await cl.Message(content="", language="sql").send()

        async for part in stream:
            if token := part.choices[0].delta.content or "":
                await msg.stream_token(token)

        await msg.update()
    except Exception as e:
        # 打印详细的错误信息
        print(f"Error occurred: {e}")
        error_msg = await cl.Message(content=f"An error occurred: {e}").send()


from typing import Dict, Optional



@cl.oauth_callback
def oauth_callback(
  provider_id: str,
  token: str,
  raw_user_data: Dict[str, str],
  default_user: cl.User,
) -> Optional[cl.User]:
  return default_user

.env文件如下

image.png

DASHSCOPE_API_KEY=<此处替换为你的api_key>
OPENAI_API_KEY=<此处替换为你的api_key>
#下面的环境变量值,可以在github app中查到
OAUTH_GITHUB_CLIENT_ID=<此处替换为你的GITHUB_CLIENT_ID>
OAUTH_GITHUB_CLIENT_SECRET=<此处替换为你的GITHUB_CLIENT_SECRET>

会自动打开默认浏览器,自动打开网页,网址为http://localhost:8000

如下图,点击“继续使用github”,然后会跳转到github的登录界面,提示需要授权,完成授权后,网页会自动跳转回chainlit页面

image.png

可以看到,成功登录了

image.png

问聊天机器人,也输出了回答

image.png

下面是chainlit部分日志

2025-06-11 11:13:30 - HTTP Request: GET https://api.github.com/user "HTTP/1.1 200 OK"
2025-06-11 11:13:31 - HTTP Request: GET https://api.github.com/user/emails "HTTP/1.1 200 OK"
INFO:     127.0.0.1:60250 - "GET /auth/oauth/github/callback?code=c57134e83b9aa8f9411b&state=im0fiESYJ7wlUrS%24%2FpJ%40t%40%3ER03DsRQRG HTTP/1.1" 302 Found
INFO:     127.0.0.1:60250 - "GET /login/callback?success=True HTTP/1.1" 200 OK
INFO:     127.0.0.1:60250 - "GET /auth/config HTTP/1.1" 200 OK
INFO:     127.0.0.1:60249 - "GET /user HTTP/1.1" 200 OK
INFO:     127.0.0.1:60252 - "GET /project/translations?language=zh-CN& HTTP/1.1" 200 OK
2025-06-11 11:13:31 - Translated markdown file for zh-CN not found. Defaulting to chainlit.md.
INFO:     127.0.0.1:60252 - "GET /project/settings?language=zh-CN& HTTP/1.1" 200 OK
INFO:     127.0.0.1:60252 - "POST /set-session-cookie HTTP/1.1" 200 OK
INFO:     127.0.0.1:60252 - "GET /ws/socket.io/?EIO=4&transport=polling&t=PTS-eSY HTTP/1.1" 200 OK
INFO:     127.0.0.1:60252 - "POST /ws/socket.io/?EIO=4&transport=polling&t=PTS-eSk&sid=BhVCTPSnvJ-ahsFyAAAE HTTP/1.1" 200 OK
INFO:     127.0.0.1:60249 - "GET /ws/socket.io/?EIO=4&transport=polling&t=PTS-eSl&sid=BhVCTPSnvJ-ahsFyAAAE HTTP/1.1" 200 OK
INFO:     127.0.0.1:60249 - "POST /ws/socket.io/?EIO=4&transport=polling&t=PTS-eTB&sid=BhVCTPSnvJ-ahsFyAAAE HTTP/1.1" 200 OK
INFO:     127.0.0.1:60252 - "GET /ws/socket.io/?EIO=4&transport=polling&t=PTS-eTA&sid=BhVCTPSnvJ-ahsFyAAAE HTTP/1.1" 200 OK
INFO:     127.0.0.1:60252 - "GET /ws/socket.io/?EIO=4&transport=polling&t=PTS-eTd&sid=BhVCTPSnvJ-ahsFyAAAE HTTP/1.1" 200 OK
INFO:     ('127.0.0.1', 60344) - "WebSocket /ws/socket.io/?EIO=4&transport=websocket&sid=BhVCTPSnvJ-ahsFyAAAE" [accepted]
INFO:     127.0.0.1:60252 - "GET /ws/socket.io/?EIO=4&transport=polling&t=PTS-eTm&sid=BhVCTPSnvJ-ahsFyAAAE HTTP/1.1" 200 OK
INFO:     127.0.0.1:60452 - "GET /user HTTP/1.1" 200 OK
INFO:     127.0.0.1:60453 - "GET /project/translations?language=zh-CN& HTTP/1.1" 200 OK
INFO:     127.0.0.1:60456 - "GET /user HTTP/1.1" 200 OK
INFO:     127.0.0.1:60456 - "GET /project/translations?language=zh-CN& HTTP/1.1" 200 OK
INFO:     127.0.0.1:60484 - "GET /user HTTP/1.1" 200 OK
INFO:     127.0.0.1:60484 - "GET /project/translations?language=zh-CN& HTTP/1.1" 200 OK
INFO:     127.0.0.1:60529 - "GET /user HTTP/1.1" 200 OK
INFO:     127.0.0.1:60529 - "GET /project/translations?language=zh-CN& HTTP/1.1" 200 OK
INFO:     127.0.0.1:60629 - "GET /user HTTP/1.1" 200 OK
INFO:     127.0.0.1:60630 - "GET /project/translations?language=zh-CN& HTTP/1.1" 200 OK
2025-06-11 11:14:44 - HTTP Request: POST https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions "HTTP/1.1 200 OK"
INFO:     127.0.0.1:60630 - "GET /user HTTP/1.1" 200 OK

关于https的特别说明

github的安全策略要求生产环境下,callback url必须使用https

但是开发环境下,可以使用http,不过callback url中的ip地址必须是localhost或127.0.0.1

image.png

keycloak–LDAP

部署keycloak

最简单的方法是用docker部署

docker run -p 8080:8080 -e KC_BOOTSTRAP_ADMIN_USERNAME=admin -e KC_BOOTSTRAP_ADMIN_PASSWORD=admin --dns=192.168.124.7 docker.1ms.run/keycloak/keycloak:26.2.5 start-dev

注意,这种方式,只适用于实验环境,生产环境尽量用helm部署,且必须用https

添加一个LDAP provider

访问keycloak,网址为:http://your_serverIP:8080

默认的用户名和密码都是admin

image.png

下面是一个示例:

screencapture-172-16-0-9-8080-admin-master-console-2025-03-13-10_51_31.png

验证ldap连接性

image.pngimage.png

创建一个新的client

image.pngimage.png

参考资料:OAuth - Chainlit

官方文档,对于redirect URLs的说明如下,其实关键是callback前的字符,这个是可以自定义的,我设置的是chainlit-keycloak

You have the option of changing the id of your Keycloak provider, which by default is keycloak. This is useful if you want to display a more appropriate name on your login page. Use the OAUTH_KEYCLOAK_NAME environment variable to set the name. Don’t choose an id that conflicts with any of the other Oauth providers.

The callback URL for your client should be: CHAINLIT_URL/auth/oauth/ O A U T H _ K E Y C L O A K _ N A M E / c a l l b a c k .   I f   y o u r   C h a i n l i t   a p p   i s   h o s t e d   a t   l o c a l h o s t : 8000 ,   y o u   s h o u l d   u s e [ h t t p : / / l o c a l h o s t : 8000 / a u t h / o a u t h / {OAUTH\_KEYCLOAK\_NAME}/callback. If your Chainlit app is hosted at localhost:8000, you should use[http://localhost:8000/auth/oauth/ OAUTH_KEYCLOAK_NAME/callbackIf your Chainlit app is hosted at localhost:8000, you should use[http://localhost:8000/auth/oauth/{OAUTH_KEYCLOAK_NAME}/callback](http://localhost:8000/auth/oauth/${OAUTH_KEYCLOAK_NAME}/callback).

image.png

这里,redirect URLs使用ip地址也是可以的,只是运行chainlit时,需要指定–host参数,如果不指定,则默认是在localhost上监听的

chainlit.exe run .\text_to_SQL.py -d -h -w --host 192.168.124.11

image.png

设置chainlit环境变量(.env文件)

特别说明:OAUTH_KEYCLOAK_CLIENT_SECRET这个环境变量的值可以在keycloak中直接复制:client–credentials–client secret

OAUTH_KEYCLOAK_CLIENT_SECRET和CHAINLIT_AUTH_SECRET的值要保持一致,另外千万注意,不要在=号两边加上空格,也不要对环境变量的值用双引号,这会导致实际的环境变量值发生变化,从而导致chainlit身份认证出现问题。不要在环境变量值的后面加上#号,因为这会赋值给环境变量,如果要对.env文件进行注释,请在单独的行中进行注释。

# OAUTH_KEYCLOAK_BASE_URL = "http://10.65.37.239:8080"
DASHSCOPE_API_KEY=<此处替换为你的api_key>
OPENAI_API_KEY=<此处替换为你的api_key>

OAUTH_KEYCLOAK_BASE_URL=http://10.65.37.239:8080
#OAUTH_KEYCLOAK_REALM的值就是keycloak中的REALM名,keycloak中默认的REALM是master,但是也可以再新建REALM
OAUTH_KEYCLOAK_REALM = "master"
OAUTH_KEYCLOAK_CLIENT_ID = "chainlit-client"
#下面这个环境变量的值可以在keycloak中直接复制:client--credentials--client secret
#OAUTH_KEYCLOAK_CLIENT_SECRET和CHAINLIT_AUTH_SECRET的值要保持一致,另外千万注意,不要在=号两边加上空格,也不要对环境变量的值用双引号,这会导致实际的环境变量值发生变化,从而导致chainlit身份认证出现问题。不要在环境变量值的后面加上#号,因为这会赋值给环境变量,如果要对.env文件进行注释,请在单独的行中进行注释。
OAUTH_KEYCLOAK_CLIENT_SECRET=7M7FzG7pVNe0RA84C75cgWk0VHzCCLm6
# CHAINLIT_AUTH_SECRET="F3rrs1vky1*MU9~ron_p1ntNfu2Rv1GiSWgl1p:$=>Yl0cRFubC?2=I1=$uCBLVS"
CHAINLIT_AUTH_SECRET=7M7FzG7pVNe0RA84C75cgWk0VHzCCLm6
#OAUTH_KEYCLOAK_NAME的值可以自己设置,如果不设置,默认为keycloak
OAUTH_KEYCLOAK_NAME = "chainlit-keycloak"

image.png

image.png

编写chainlit主程序逻辑代码

import os
from openai import AsyncOpenAI
from chainlit.oauth_providers import OAuthProvider
import chainlit as cl

import httpx
from fastapi import HTTPException
from chainlit.user import User

import json
cl.instrument_openai()

""" import os

# 手动加载.env文件
from dotenv import load_dotenv
load_dotenv() """

# 打印环境变量
print(os.getenv("OAUTH_KEYCLOAK_BASE_URL"))
print(os.getenv("OAUTH_KEYCLOAK_REALM"))
print(os.getenv("OAUTH_KEYCLOAK_CLIENT_ID"))
print(os.getenv("OAUTH_KEYCLOAK_CLIENT_SECRET"))
print(os.getenv("OAUTH_KEYCLOAK_NAME"))
print(os.getenv("CHAINLIT_AUTH_SECRET"))
#user_env = cl.user_session.get("env") #从.env文件中获取环境变量
# 从环境变量中获取API KEY
api_key = os.getenv("OPENAI_API_KEY")

print(os.getenv("OPENAI_API_KEY")) 

if api_key is None:
    raise ValueError("OPENAI_API_KEY environment variable is not set.")

client = AsyncOpenAI(
    api_key=api_key,
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"
)


# 优化后的模板,让指令更清晰
template = """SQL tables (and columns):
* Customers(customer_id, signup_date)
* Streaming(customer_id, video_id, watch_date, watch_minutes)

Generate a well - written SQL query to {input} and return the query wrapped in triple backticks (```):
```"""


settings = {
    "model": "qwen-plus",
    "temperature": 0,
    "max_tokens": 500,
    "top_p": 1,
    "frequency_penalty": 0,
    "presence_penalty": 0,
    # 可以尝试去掉 stop 参数
    # "stop": ["```"],
}



@cl.set_starters
async def starters():
    return [
       cl.Starter(
           label=">50 minutes watched",
           message="Compute the number of customers who watched more than 50 minutes of video this month."
       )
    ]

@cl.on_message
async def main(message: cl.Message):
    try:
        stream = await client.chat.completions.create(
            messages=[
                {
                    "role": "user",
                    "content": template.format(input=message.content),
                }
            ], stream=True, **settings
        )

        msg = await cl.Message(content="", language="sql").send()

        async for part in stream:
            if token := part.choices[0].delta.content or "":
                await msg.stream_token(token)

        await msg.update()
    except Exception as e:
        # 打印详细的错误信息
        print(f"Error occurred: {e}")
        error_msg = await cl.Message(content=f"An error occurred: {e}").send()


from typing import Dict, Optional


# 下面部分的代码很重要,这部分代码的含义是允许所有经过身份验证的用户登录到chainlit
@cl.oauth_callback
def oauth_callback(
  provider_id: str,
  token: str,
  raw_user_data: Dict[str, str],
  default_user: cl.User,
) -> Optional[cl.User]:
  return default_user

启动chainlit并验证登录

chainlit run .\text_to_SQL.py -d -w

浏览器会自动打开chainlit网站

设置了身份验证后,必须要登录才能真正使用chainlit,这里点击“继续使用chainlit-keycloak”

image.png

网页跳转到了keycloak的登录页面

这里,我先用一个合法的用户登录,就是之前添加的Microsoft AD中的用户

image.png

其实keycloak中的这些用户都是可以登录的,可以看到,其中很多用户是通过LDAP同步过来的

image.png

成功登录

image.png

与chainlit应用对话,也是正常的:

image.png

再试一下,一个不存在的用户登录,会发生什么:

image.png

无法登陆

image.png

查看keycloak的日志,可以看到提示没有找到此用户error="user_not_found"

2025-06-11 06:50:53,645 WARN  [org.keycloak.events] (executor-thread-65) type="LOGIN_ERROR", realmId="c62613af-801b-459c-9302-0871e049403a", realmName="master", clientId="chainlit-client", userId="null", ipAddress="192.168.124.11", error="user_not_found", auth_method="openid-connect", auth_type="code", redirect_uri="http://localhost:8000/auth/oauth/chainlit-keycloak/callback", code_id="f6d377ce-62b1-4cd5-8326-018216b3071c", username="david"

完整的keycloak日志

仔细看下面的日志,会发现出现了几次报错:error="invalid_client_credentials",这是因为chainlit的.env文件中的环境变量设置有误,我之前在=号两边加上了空格,还有引号,甚至还在环境变量的值的后面用#进行了注释,这都是错误的,导致环境变量赋值错误,从而出现了这个报错。所以一定要注意.env文件的最佳实践:

不要有空格;

不要在值的两边加双引号;

决不能在值的末尾用#进行注释,应该另外加一行进行注释。

docker run -p 8080:8080 -e KC_BOOTSTRAP_ADMIN_USERNAME=admin -e KC_BOOTSTRAP_ADMIN_PASSWORD=admin --dns=192.168.124.7 docker.1ms.run/keycloak/keycloak:26.2.5 start-dev
Updating the configuration and installing your custom providers, if any. Please wait.
2025-06-11 04:54:29,743 INFO  [io.quarkus.deployment.QuarkusAugmentor] (main) Quarkus augmentation completed in 61147ms
Running the server in development mode. DO NOT use this configuration in production.
2025-06-11 04:54:42,967 INFO  [org.keycloak.quarkus.runtime.storage.database.liquibase.QuarkusJpaUpdaterProvider] (main) Initializing database schema. Using changelog META-INF/jpa-changelog-master.xml
2025-06-11 04:54:51,606 INFO  [org.keycloak.quarkus.runtime.storage.infinispan.CacheManagerFactory] (main) Starting Infinispan embedded cache manager
2025-06-11 04:54:51,755 INFO  [org.keycloak.quarkus.runtime.storage.infinispan.CacheManagerFactory] (main) JGroups JDBC_PING discovery enabled.
2025-06-11 04:54:52,043 INFO  [org.infinispan.CONTAINER] (main) Virtual threads support enabled
2025-06-11 04:54:52,486 INFO  [org.infinispan.CONTAINER] (main) ISPN000556: Starting user marshaller 'org.infinispan.commons.marshall.ImmutableProtoStreamMarshaller'
2025-06-11 04:54:53,452 INFO  [org.keycloak.connections.infinispan.DefaultInfinispanConnectionProviderFactory] (main) Node name: node_700622, Site name: null
2025-06-11 04:54:54,049 INFO  [org.keycloak.services] (main) KC-SERVICES0050: Initializing master realm
2025-06-11 04:54:58,037 INFO  [org.keycloak.services] (main) KC-SERVICES0077: Created temporary admin user with username admin
2025-06-11 04:54:58,376 INFO  [io.quarkus] (main) Keycloak 26.2.5 on JVM (powered by Quarkus 3.20.1) started in 28.079s. Listening on: http://0.0.0.0:8080
2025-06-11 04:54:58,377 INFO  [io.quarkus] (main) Profile dev activated.
2025-06-11 04:54:58,377 INFO  [io.quarkus] (main) Installed features: [agroal, cdi, hibernate-orm, jdbc-h2, keycloak, narayana-jta, opentelemetry, reactive-routes, rest, rest-jackson, smallrye-context-propagation, vertx]
2025-06-11 04:55:27,371 WARN  [org.keycloak.cookie.DefaultCookieProvider] (executor-thread-3) Non-secure context detected; cookies are not secured, and will not be available in cross-origin POST requests
2025-06-11 04:55:28,271 WARN  [org.keycloak.cookie.DefaultCookieProvider] (executor-thread-1) Non-secure context detected; cookies are not secured, and will not be available in cross-origin POST requests
2025-06-11 04:55:31,313 WARN  [org.keycloak.cookie.DefaultCookieProvider] (executor-thread-4) Non-secure context detected; cookies are not secured, and will not be available in cross-origin POST requests
2025-06-11 05:02:50,657 INFO  [org.keycloak.storage.ldap.LDAPIdentityStoreRegistry] (executor-thread-15) Creating new LDAP Store for the LDAP storage provider: 'ldap', LDAP Configuration: {fullSyncPeriod=[604800], pagination=[true], connectionTrace=[false], startTls=[false], connectionPooling=[true], usersDn=[OU=myse,DC=dltornado2,DC=com], cachePolicy=[DEFAULT], useKerberosForPasswordAuthentication=[false], importEnabled=[true], enabled=[true], changedSyncPeriod=[86400], bindDn=[CN=adm,OU=myse,DC=dltornado2,DC=com], usernameLDAPAttribute=[cn], vendor=[ad], uuidLDAPAttribute=[objectGUID], allowKerberosAuthentication=[false], connectionUrl=[ldap://dc-t.dltornado2.com:389], syncRegistrations=[true], authType=[simple], krbPrincipalAttribute=[userPrincipalName], searchScope=[2], useTruststoreSpi=[always], usePasswordModifyExtendedOp=[false], trustEmail=[false], userObjectClasses=[person, organizationalPerson, user], removeInvalidUsersEnabled=[true], rdnLDAPAttribute=[cn], editMode=[WRITABLE], validatePasswordPolicy=[false]}, binaryAttributes: []
2025-06-11 05:06:38,983 WARN  [org.keycloak.cookie.DefaultCookieProvider] (executor-thread-15) Non-secure context detected; cookies are not secured, and will not be available in cross-origin POST requests
2025-06-11 05:06:48,097 WARN  [org.keycloak.cookie.DefaultCookieProvider] (executor-thread-22) Non-secure context detected; cookies are not secured, and will not be available in cross-origin POST requests
2025-06-11 05:06:49,529 WARN  [org.keycloak.events] (executor-thread-22) type="CODE_TO_TOKEN_ERROR", realmId="c62613af-801b-459c-9302-0871e049403a", realmName="master", clientId="chainlit-client", userId="null", ipAddress="192.168.124.11", error="invalid_client_credentials", grant_type="authorization_code"
2025-06-11 05:09:53,486 WARN  [org.keycloak.cookie.DefaultCookieProvider] (executor-thread-22) Non-secure context detected; cookies are not secured, and will not be available in cross-origin POST requests
2025-06-11 05:10:00,019 WARN  [org.keycloak.cookie.DefaultCookieProvider] (executor-thread-24) Non-secure context detected; cookies are not secured, and will not be available in cross-origin POST requests
2025-06-11 05:10:01,581 WARN  [org.keycloak.events] (executor-thread-24) type="CODE_TO_TOKEN_ERROR", realmId="c62613af-801b-459c-9302-0871e049403a", realmName="master", clientId="chainlit-client", userId="null", ipAddress="192.168.124.11", error="invalid_client_credentials", grant_type="authorization_code"
2025-06-11 05:44:49,771 WARN  [org.keycloak.cookie.DefaultCookieProvider] (executor-thread-24) Non-secure context detected; cookies are not secured, and will not be available in cross-origin POST requests
2025-06-11 05:44:59,211 WARN  [org.keycloak.cookie.DefaultCookieProvider] (executor-thread-29) Non-secure context detected; cookies are not secured, and will not be available in cross-origin POST requests
2025-06-11 05:45:00,915 WARN  [org.keycloak.events] (executor-thread-29) type="CODE_TO_TOKEN_ERROR", realmId="c62613af-801b-459c-9302-0871e049403a", realmName="master", clientId="chainlit-client", userId="null", ipAddress="192.168.124.11", error="invalid_client_credentials", grant_type="authorization_code"
2025-06-11 05:45:51,892 WARN  [org.keycloak.events] (executor-thread-29) type="REFRESH_TOKEN_ERROR", realmId="c62613af-801b-459c-9302-0871e049403a", realmName="master", clientId="security-admin-console", userId="null", ipAddress="192.168.124.11", error="invalid_token", reason="Token is not active", grant_type="refresh_token", client_auth_method="client-secret"
2025-06-11 05:45:51,934 WARN  [org.keycloak.cookie.DefaultCookieProvider] (executor-thread-29) Non-secure context detected; cookies are not secured, and will not be available in cross-origin POST requests
2025-06-11 05:45:54,749 WARN  [org.keycloak.cookie.DefaultCookieProvider] (executor-thread-33) Non-secure context detected; cookies are not secured, and will not be available in cross-origin POST requests
2025-06-11 05:52:04,838 WARN  [org.keycloak.cookie.DefaultCookieProvider] (executor-thread-35) Non-secure context detected; cookies are not secured, and will not be available in cross-origin POST requests
2025-06-11 05:52:23,253 WARN  [org.keycloak.cookie.DefaultCookieProvider] (executor-thread-37) Non-secure context detected; cookies are not secured, and will not be available in cross-origin POST requests
2025-06-11 05:52:24,413 WARN  [org.keycloak.events] (executor-thread-37) type="CODE_TO_TOKEN_ERROR", realmId="c62613af-801b-459c-9302-0871e049403a", realmName="master", clientId="chainlit-client", userId="null", ipAddress="192.168.124.11", error="invalid_client_credentials", grant_type="authorization_code"
2025-06-11 05:57:47,864 WARN  [org.keycloak.cookie.DefaultCookieProvider] (executor-thread-37) Non-secure context detected; cookies are not secured, and will not be available in cross-origin POST requests
2025-06-11 05:57:54,214 WARN  [org.keycloak.cookie.DefaultCookieProvider] (executor-thread-42) Non-secure context detected; cookies are not secured, and will not be available in cross-origin POST requests
2025-06-11 06:21:30,489 WARN  [org.keycloak.events] (executor-thread-42) type="REFRESH_TOKEN_ERROR", realmId="c62613af-801b-459c-9302-0871e049403a", realmName="master", clientId="security-admin-console", userId="null", ipAddress="192.168.124.11", error="invalid_token", reason="Token is not active", grant_type="refresh_token", client_auth_method="client-secret"
2025-06-11 06:21:30,545 WARN  [org.keycloak.cookie.DefaultCookieProvider] (executor-thread-42) Non-secure context detected; cookies are not secured, and will not be available in cross-origin POST requests
2025-06-11 06:21:33,628 WARN  [org.keycloak.cookie.DefaultCookieProvider] (executor-thread-42) Non-secure context detected; cookies are not secured, and will not be available in cross-origin POST requests
2025-06-11 06:24:10,345 INFO  [org.keycloak.storage.ldap.LDAPStorageProviderFactory] (executor-thread-53) Sync all users from LDAP to local store: realm: c62613af-801b-459c-9302-0871e049403a, federation provider: ldap
2025-06-11 06:24:10,477 INFO  [org.keycloak.storage.ldap.LDAPStorageProviderFactory] (executor-thread-53) Sync all users finished: 0 imported users, 10 updated users
2025-06-11 06:24:12,997 INFO  [org.keycloak.storage.ldap.LDAPIdentityStoreRegistry] (executor-thread-53) Creating new LDAP Store for the LDAP storage provider: 'ldap', LDAP Configuration: {pagination=[true], fullSyncPeriod=[604800], connectionTrace=[false], startTls=[false], usersDn=[OU=myse,DC=dltornado2,DC=com], connectionPooling=[true], cachePolicy=[DEFAULT], useKerberosForPasswordAuthentication=[false], importEnabled=[true], enabled=[true], usernameLDAPAttribute=[cn], bindDn=[CN=adm,OU=myse,DC=dltornado2,DC=com], changedSyncPeriod=[86400], lastSync=[1749623050], vendor=[ad], uuidLDAPAttribute=[objectGUID], connectionUrl=[ldap://dc-t.dltornado2.com:389], allowKerberosAuthentication=[false], syncRegistrations=[true], authType=[simple], krbPrincipalAttribute=[userPrincipalName], searchScope=[2], useTruststoreSpi=[always], usePasswordModifyExtendedOp=[false], trustEmail=[false], userObjectClasses=[person, organizationalPerson, user], removeInvalidUsersEnabled=[true], rdnLDAPAttribute=[cn], editMode=[WRITABLE], validatePasswordPolicy=[false]}, binaryAttributes: []
2025-06-11 06:32:03,056 WARN  [org.keycloak.cookie.DefaultCookieProvider] (executor-thread-53) Non-secure context detected; cookies are not secured, and will not be available in cross-origin POST requests
2025-06-11 06:32:06,748 WARN  [org.keycloak.cookie.DefaultCookieProvider] (executor-thread-53) Non-secure context detected; cookies are not secured, and will not be available in cross-origin POST requests
2025-06-11 06:46:32,652 WARN  [org.keycloak.cookie.DefaultCookieProvider] (executor-thread-58) Non-secure context detected; cookies are not secured, and will not be available in cross-origin POST requests
2025-06-11 06:46:52,782 WARN  [org.keycloak.cookie.DefaultCookieProvider] (executor-thread-58) Non-secure context detected; cookies are not secured, and will not be available in cross-origin POST requests
2025-06-11 06:47:37,201 WARN  [org.keycloak.cookie.DefaultCookieProvider] (executor-thread-60) Non-secure context detected; cookies are not secured, and will not be available in cross-origin POST requests
2025-06-11 06:48:49,050 WARN  [org.keycloak.cookie.DefaultCookieProvider] (executor-thread-60) Non-secure context detected; cookies are not secured, and will not be available in cross-origin POST requests
2025-06-11 06:49:03,145 WARN  [org.keycloak.cookie.DefaultCookieProvider] (executor-thread-60) Non-secure context detected; cookies are not secured, and will not be available in cross-origin POST requests
2025-06-11 06:49:20,683 WARN  [org.keycloak.cookie.DefaultCookieProvider] (executor-thread-60) Non-secure context detected; cookies are not secured, and will not be available in cross-origin POST requests
2025-06-11 06:50:53,552 WARN  [org.keycloak.cookie.DefaultCookieProvider] (executor-thread-65) Non-secure context detected; cookies are not secured, and will not be available in cross-origin POST requests
2025-06-11 06:50:53,645 WARN  [org.keycloak.events] (executor-thread-65) type="LOGIN_ERROR", realmId="c62613af-801b-459c-9302-0871e049403a", realmName="master", clientId="chainlit-client", userId="null", ipAddress="192.168.124.11", error="user_not_found", auth_method="openid-connect", auth_type="code", redirect_uri="http://localhost:8000/auth/oauth/chainlit-keycloak/callback", code_id="f6d377ce-62b1-4cd5-8326-018216b3071c", username="david"

除了上述详细日志,还可以在keycloak的webUI上查看每个用户的登录日志:

image.png

完整的chainlit日志

chainlit.exe run .\text_to_SQL.py -d -h -w                                                                                                    
2025-06-11 13:57:25 - Loaded .env file
http://10.65.37.239:8080
master
chainlit-client
7M7FzG7pVNe0RA84C75cgWk0VHzCCLm6
chainlit-keycloak
7M7FzG7pVNe0RA84C75cgWk0VHzCCLm6
sk-189ff68fba9d4ff884e718d8338ee075
INFO:     Started server process [10032]
INFO:     Waiting for application startup.
2025-06-11 13:57:29 - Your app is available at http://localhost:8000
INFO:     Application startup complete.
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO:     127.0.0.1:50307 - "GET / HTTP/1.1" 200 OK
INFO:     127.0.0.1:50307 - "GET /assets/index-B28WSRhf.js HTTP/1.1" 200 OK
INFO:     127.0.0.1:50307 - "GET /assets/index-BIhgNEQJ.css HTTP/1.1" 200 OK
INFO:     127.0.0.1:50307 - "GET /auth/config HTTP/1.1" 200 OK
INFO:     127.0.0.1:50315 - "GET /user HTTP/1.1" 401 Unauthorized
INFO:     127.0.0.1:50317 - "GET /project/translations?language=zh-CN& HTTP/1.1" 200 OK
INFO:     127.0.0.1:50317 - "GET /favicon HTTP/1.1" 200 OK
INFO:     127.0.0.1:50317 - "GET /login HTTP/1.1" 200 OK
INFO:     127.0.0.1:50317 - "GET /logo?theme=dark& HTTP/1.1" 200 OK
INFO:     127.0.0.1:50317 - "GET /user HTTP/1.1" 401 Unauthorized
INFO:     127.0.0.1:50315 - "GET /auth/config HTTP/1.1" 200 OK
INFO:     127.0.0.1:50307 - "GET /project/translations?language=zh-CN& HTTP/1.1" 200 OK
INFO:     127.0.0.1:50307 - "GET /auth/oauth/chainlit-keycloak HTTP/1.1" 307 Temporary Redirect
2025-06-11 13:57:56 - HTTP Request: POST http://10.65.37.239:8080/realms/master/protocol/openid-connect/token "HTTP/1.1 200 OK"
2025-06-11 13:57:57 - HTTP Request: GET http://10.65.37.239:8080/realms/master/protocol/openid-connect/userinfo "HTTP/1.1 200 OK"
INFO:     127.0.0.1:50415 - "GET /auth/oauth/chainlit-keycloak/callback?state=Ybg2D%24nMym%3DZoriieZzb%3As.KhI6%24xJvZ&session_state=e18c6678-3ab1-40a7-b029-feae13ffd730&iss=http%3A%2F%2F10.65.37.239%3A8080%2Frealms%2Fmaster&code=f69f3b5b-3a47-4dbc-9582-cbdba4c74040.e18c6678-3ab1-40a7-b029-feae13ffd730.c2cb61ae-c661-4d8f-a30c-eaa54c053c70 HTTP/1.1" 302 Found
INFO:     127.0.0.1:50415 - "GET /login/callback?success=True HTTP/1.1" 200 OK
INFO:     127.0.0.1:50415 - "GET /user HTTP/1.1" 200 OK
INFO:     127.0.0.1:50418 - "GET /auth/config HTTP/1.1" 200 OK
INFO:     127.0.0.1:50415 - "GET /project/translations?language=zh-CN& HTTP/1.1" 200 OK
2025-06-11 13:57:57 - Translated markdown file for zh-CN not found. Defaulting to chainlit.md.
INFO:     127.0.0.1:50415 - "GET /project/settings?language=zh-CN& HTTP/1.1" 200 OK
INFO:     127.0.0.1:50415 - "POST /set-session-cookie HTTP/1.1" 200 OK
INFO:     127.0.0.1:50415 - "GET /ws/socket.io/?EIO=4&transport=polling&t=PTTaHAw HTTP/1.1" 200 OK
INFO:     127.0.0.1:50415 - "POST /ws/socket.io/?EIO=4&transport=polling&t=PTTaHB2&sid=f5Q7w8XTp-P5DNFCAAAA HTTP/1.1" 200 OK
INFO:     127.0.0.1:50418 - "GET /ws/socket.io/?EIO=4&transport=polling&t=PTTaHB4&sid=f5Q7w8XTp-P5DNFCAAAA HTTP/1.1" 200 OK
INFO:     127.0.0.1:50415 - "POST /ws/socket.io/?EIO=4&transport=polling&t=PTTaHBC.0&sid=f5Q7w8XTp-P5DNFCAAAA HTTP/1.1" 200 OK
INFO:     127.0.0.1:50418 - "GET /ws/socket.io/?EIO=4&transport=polling&t=PTTaHBC&sid=f5Q7w8XTp-P5DNFCAAAA HTTP/1.1" 200 OK
INFO:     127.0.0.1:50418 - "GET /ws/socket.io/?EIO=4&transport=polling&t=PTTaHBN&sid=f5Q7w8XTp-P5DNFCAAAA HTTP/1.1" 200 OK
INFO:     ('127.0.0.1', 50457) - "WebSocket /ws/socket.io/?EIO=4&transport=websocket&sid=f5Q7w8XTp-P5DNFCAAAA" [accepted]
INFO:     127.0.0.1:50418 - "GET /ws/socket.io/?EIO=4&transport=polling&t=PTTaHBR&sid=f5Q7w8XTp-P5DNFCAAAA HTTP/1.1" 200 OK
INFO:     127.0.0.1:50447 - "GET /user HTTP/1.1" 200 OK
2025-06-11 13:58:07 - HTTP Request: POST https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions "HTTP/1.1 200 OK"
INFO:     127.0.0.1:50447 - "GET /avatars/Assistant HTTP/1.1" 200 OK
INFO:     127.0.0.1:50447 - "GET /avatars/qwen-plus HTTP/1.1" 200 OK
INFO:     127.0.0.1:50447 - "GET /user HTTP/1.1" 200 OK
INFO:     127.0.0.1:50447 - "GET /user HTTP/1.1" 200 OK
INFO:     127.0.0.1:63226 - "GET /user HTTP/1.1" 200 OK
INFO:     127.0.0.1:63227 - "GET /project/translations?language=zh-CN& HTTP/1.1" 200 OK
INFO:     127.0.0.1:63227 - "POST /logout HTTP/1.1" 200 OK
INFO:     127.0.0.1:63227 - "GET / HTTP/1.1" 200 OK
INFO:     127.0.0.1:63227 - "GET /auth/config HTTP/1.1" 200 OK
INFO:     127.0.0.1:63226 - "GET /user HTTP/1.1" 401 Unauthorized
INFO:     127.0.0.1:63229 - "GET /project/translations?language=zh-CN& HTTP/1.1" 200 OK
INFO:     127.0.0.1:63229 - "GET /login HTTP/1.1" 200 OK
INFO:     127.0.0.1:63229 - "GET /auth/config HTTP/1.1" 200 OK
INFO:     127.0.0.1:63226 - "GET /user HTTP/1.1" 401 Unauthorized
INFO:     127.0.0.1:63227 - "GET /project/translations?language=zh-CN& HTTP/1.1" 200 OK
INFO:     127.0.0.1:63368 - "GET /user HTTP/1.1" 401 Unauthorized
INFO:     127.0.0.1:63369 - "GET /user HTTP/1.1" 401 Unauthorized
INFO:     127.0.0.1:63369 - "GET /project/translations?language=zh-CN& HTTP/1.1" 200 OK
INFO:     127.0.0.1:63852 - "GET /user HTTP/1.1" 401 Unauthorized
INFO:     127.0.0.1:51541 - "GET /user HTTP/1.1" 401 Unauthorized
INFO:     127.0.0.1:51542 - "GET /project/translations?language=zh-CN& HTTP/1.1" 200 OK
INFO:     127.0.0.1:51542 - "GET /auth/oauth/chainlit-keycloak HTTP/1.1" 307 Temporary Redirect
2025-06-11 14:32:08 - HTTP Request: POST http://10.65.37.239:8080/realms/master/protocol/openid-connect/token "HTTP/1.1 200 OK"
2025-06-11 14:32:09 - HTTP Request: GET http://10.65.37.239:8080/realms/master/protocol/openid-connect/userinfo "HTTP/1.1 200 OK"
INFO:     127.0.0.1:51542 - "GET /auth/oauth/chainlit-keycloak/callback?state=V4iDQ*AhZKYUZkhQ81RUTKLUylfRi8Sd&session_state=69b670fa-4777-49e8-984c-53f774f5f450&iss=http%3A%2F%2F10.65.37.239%3A8080%2Frealms%2Fmaster&code=5fad669e-18f6-4bf1-852e-1c4a9be86a93.69b670fa-4777-49e8-984c-53f774f5f450.c2cb61ae-c661-4d8f-a30c-eaa54c053c70 HTTP/1.1" 302 Found
INFO:     127.0.0.1:51542 - "GET /login/callback?success=True HTTP/1.1" 200 OK
INFO:     127.0.0.1:51542 - "GET /auth/config HTTP/1.1" 200 OK
INFO:     127.0.0.1:51543 - "GET /user HTTP/1.1" 200 OK
INFO:     127.0.0.1:51542 - "GET /project/translations?language=zh-CN& HTTP/1.1" 200 OK
2025-06-11 14:32:09 - Translated markdown file for zh-CN not found. Defaulting to chainlit.md.
INFO:     127.0.0.1:51542 - "GET /project/settings?language=zh-CN& HTTP/1.1" 200 OK
INFO:     127.0.0.1:51542 - "POST /set-session-cookie HTTP/1.1" 200 OK
INFO:     127.0.0.1:51542 - "GET /ws/socket.io/?EIO=4&transport=polling&t=PTTi68I HTTP/1.1" 200 OK
INFO:     127.0.0.1:51542 - "POST /ws/socket.io/?EIO=4&transport=polling&t=PTTi68Q&sid=wZYwx15PyFRbphgYAAAC HTTP/1.1" 200 OK
INFO:     127.0.0.1:51543 - "GET /ws/socket.io/?EIO=4&transport=polling&t=PTTi68R&sid=wZYwx15PyFRbphgYAAAC HTTP/1.1" 200 OK
INFO:     127.0.0.1:51542 - "POST /ws/socket.io/?EIO=4&transport=polling&t=PTTi68Z&sid=wZYwx15PyFRbphgYAAAC HTTP/1.1" 200 OK
INFO:     127.0.0.1:51543 - "GET /ws/socket.io/?EIO=4&transport=polling&t=PTTi68Y&sid=wZYwx15PyFRbphgYAAAC HTTP/1.1" 200 OK
INFO:     127.0.0.1:51543 - "GET /ws/socket.io/?EIO=4&transport=polling&t=PTTi68g&sid=wZYwx15PyFRbphgYAAAC HTTP/1.1" 200 OK
INFO:     ('127.0.0.1', 51637) - "WebSocket /ws/socket.io/?EIO=4&transport=websocket&sid=wZYwx15PyFRbphgYAAAC" [accepted]
INFO:     127.0.0.1:51543 - "GET /ws/socket.io/?EIO=4&transport=polling&t=PTTi68m&sid=wZYwx15PyFRbphgYAAAC HTTP/1.1" 200 OK
2025-06-11 14:44:53 - 1 change detected
2025-06-11 14:44:53 - File modified: text_to_SQL.py. Reloading app...
http://10.65.37.239:8080
master
chainlit-client
7M7FzG7pVNe0RA84C75cgWk0VHzCCLm6
chainlit-keycloak
7M7FzG7pVNe0RA84C75cgWk0VHzCCLm6
sk-189ff68fba9d4ff884e718d8338ee075
INFO:     127.0.0.1:58914 - "GET / HTTP/1.1" 200 OK
INFO:     127.0.0.1:58914 - "GET /auth/config HTTP/1.1" 200 OK
INFO:     127.0.0.1:58916 - "GET /user HTTP/1.1" 200 OK
INFO:     127.0.0.1:58914 - "GET /project/translations?language=zh-CN& HTTP/1.1" 200 OK
2025-06-11 14:44:56 - Translated markdown file for zh-CN not found. Defaulting to chainlit.md.
INFO:     127.0.0.1:58914 - "GET /project/settings?language=zh-CN& HTTP/1.1" 200 OK
INFO:     127.0.0.1:58914 - "POST /set-session-cookie HTTP/1.1" 200 OK
INFO:     127.0.0.1:58914 - "GET /ws/socket.io/?EIO=4&transport=polling&t=PTTl1O7 HTTP/1.1" 200 OK
INFO:     127.0.0.1:58914 - "POST /ws/socket.io/?EIO=4&transport=polling&t=PTTl1OP&sid=t0Y2a0u2A4dUwnWBAAAE HTTP/1.1" 200 OK
INFO:     127.0.0.1:58916 - "GET /ws/socket.io/?EIO=4&transport=polling&t=PTTl1OQ&sid=t0Y2a0u2A4dUwnWBAAAE HTTP/1.1" 200 OK
INFO:     127.0.0.1:58914 - "POST /ws/socket.io/?EIO=4&transport=polling&t=PTTl1Ob&sid=t0Y2a0u2A4dUwnWBAAAE HTTP/1.1" 200 OK
INFO:     127.0.0.1:58916 - "GET /ws/socket.io/?EIO=4&transport=polling&t=PTTl1OZ&sid=t0Y2a0u2A4dUwnWBAAAE HTTP/1.1" 200 OK
INFO:     127.0.0.1:58916 - "GET /ws/socket.io/?EIO=4&transport=polling&t=PTTl1Ot&sid=t0Y2a0u2A4dUwnWBAAAE HTTP/1.1" 200 OK
INFO:     ('127.0.0.1', 58938) - "WebSocket /ws/socket.io/?EIO=4&transport=websocket&sid=t0Y2a0u2A4dUwnWBAAAE" [accepted]
INFO:     127.0.0.1:58916 - "GET /ws/socket.io/?EIO=4&transport=polling&t=PTTl1Ow&sid=t0Y2a0u2A4dUwnWBAAAE HTTP/1.1" 200 OK
INFO:     127.0.0.1:58928 - "GET /user HTTP/1.1" 200 OK
INFO:     127.0.0.1:58928 - "GET /project/translations?language=zh-CN& HTTP/1.1" 200 OK
INFO:     127.0.0.1:58928 - "POST /logout HTTP/1.1" 200 OK
INFO:     127.0.0.1:58928 - "GET / HTTP/1.1" 200 OK
INFO:     127.0.0.1:58928 - "GET /auth/config HTTP/1.1" 200 OK
INFO:     127.0.0.1:59260 - "GET /user HTTP/1.1" 401 Unauthorized
INFO:     127.0.0.1:58928 - "GET /project/translations?language=zh-CN& HTTP/1.1" 200 OK
INFO:     127.0.0.1:58928 - "GET /login HTTP/1.1" 200 OK
INFO:     127.0.0.1:58928 - "GET /auth/config HTTP/1.1" 200 OK
INFO:     127.0.0.1:59260 - "GET /user HTTP/1.1" 401 Unauthorized
INFO:     127.0.0.1:58928 - "GET /project/translations?language=zh-CN& HTTP/1.1" 200 OK
INFO:     127.0.0.1:58928 - "GET /user HTTP/1.1" 401 Unauthorized
INFO:     127.0.0.1:59260 - "GET /project/translations?language=zh-CN& HTTP/1.1" 200 OK
INFO:     127.0.0.1:59303 - "GET /user HTTP/1.1" 401 Unauthorized
INFO:     127.0.0.1:59303 - "GET /user HTTP/1.1" 401 Unauthorized
INFO:     127.0.0.1:59304 - "GET /user HTTP/1.1" 401 Unauthorized
INFO:     127.0.0.1:59304 - "GET /project/translations?language=zh-CN& HTTP/1.1" 200 OK
INFO:     127.0.0.1:59622 - "GET /user HTTP/1.1" 401 Unauthorized
INFO:     127.0.0.1:59822 - "GET /user HTTP/1.1" 401 Unauthorized
INFO:     127.0.0.1:59824 - "GET /project/translations?language=zh-CN& HTTP/1.1" 200 OK
INFO:     127.0.0.1:59824 - "GET /auth/oauth/chainlit-keycloak HTTP/1.1" 307 Temporary Redirect
2025-06-11 14:46:34 - HTTP Request: POST http://10.65.37.239:8080/realms/master/protocol/openid-connect/token "HTTP/1.1 200 OK"
2025-06-11 14:46:35 - HTTP Request: GET http://10.65.37.239:8080/realms/master/protocol/openid-connect/userinfo "HTTP/1.1 200 OK"
INFO:     127.0.0.1:59824 - "GET /auth/oauth/chainlit-keycloak/callback?state=cCWkfkL%3Dle0F*%3DJBdhzyBPc4M5qypDZv&session_state=69b670fa-4777-49e8-984c-53f774f5f450&iss=http%3A%2F%2F10.65.37.239%3A8080%2Frealms%2Fmaster&code=bc7de006-a3e9-452e-ab20-5efad0951d93.69b670fa-4777-49e8-984c-53f774f5f450.c2cb61ae-c661-4d8f-a30c-eaa54c053c70 HTTP/1.1" 302 Found
INFO:     127.0.0.1:59824 - "GET /login/callback?success=True HTTP/1.1" 200 OK
INFO:     127.0.0.1:59824 - "GET /auth/config HTTP/1.1" 200 OK
INFO:     127.0.0.1:59822 - "GET /user HTTP/1.1" 200 OK
INFO:     127.0.0.1:59825 - "GET /project/translations?language=zh-CN& HTTP/1.1" 200 OK
2025-06-11 14:46:35 - Translated markdown file for zh-CN not found. Defaulting to chainlit.md.
INFO:     127.0.0.1:59825 - "GET /project/settings?language=zh-CN& HTTP/1.1" 200 OK
INFO:     127.0.0.1:59825 - "POST /set-session-cookie HTTP/1.1" 200 OK
INFO:     127.0.0.1:59825 - "GET /ws/socket.io/?EIO=4&transport=polling&t=PTTlPWk HTTP/1.1" 200 OK
INFO:     127.0.0.1:59825 - "POST /ws/socket.io/?EIO=4&transport=polling&t=PTTlPWt&sid=gs65c01bGM9t5p8gAAAG HTTP/1.1" 200 OK
INFO:     127.0.0.1:59822 - "GET /ws/socket.io/?EIO=4&transport=polling&t=PTTlPWu&sid=gs65c01bGM9t5p8gAAAG HTTP/1.1" 200 OK
INFO:     127.0.0.1:59825 - "POST /ws/socket.io/?EIO=4&transport=polling&t=PTTlPW_&sid=gs65c01bGM9t5p8gAAAG HTTP/1.1" 200 OK
INFO:     127.0.0.1:59822 - "GET /ws/socket.io/?EIO=4&transport=polling&t=PTTlPW-&sid=gs65c01bGM9t5p8gAAAG HTTP/1.1" 200 OK
INFO:     127.0.0.1:59822 - "GET /ws/socket.io/?EIO=4&transport=polling&t=PTTlPXA&sid=gs65c01bGM9t5p8gAAAG HTTP/1.1" 200 OK
INFO:     ('127.0.0.1', 59850) - "WebSocket /ws/socket.io/?EIO=4&transport=websocket&sid=gs65c01bGM9t5p8gAAAG" [accepted]
INFO:     127.0.0.1:59822 - "GET /ws/socket.io/?EIO=4&transport=polling&t=PTTlPXF&sid=gs65c01bGM9t5p8gAAAG HTTP/1.1" 200 OK
INFO:     127.0.0.1:59919 - "GET / HTTP/1.1" 200 OK
INFO:     127.0.0.1:59919 - "GET /assets/index-B28WSRhf.js HTTP/1.1" 200 OK
INFO:     127.0.0.1:59919 - "GET /assets/index-BIhgNEQJ.css HTTP/1.1" 200 OK
INFO:     127.0.0.1:59919 - "GET /auth/config HTTP/1.1" 200 OK
INFO:     127.0.0.1:59928 - "GET /user HTTP/1.1" 401 Unauthorized
INFO:     127.0.0.1:59929 - "GET /project/translations?language=zh-CN& HTTP/1.1" 200 OK
INFO:     127.0.0.1:59929 - "GET /favicon HTTP/1.1" 200 OK
INFO:     127.0.0.1:59929 - "GET /login HTTP/1.1" 200 OK
INFO:     127.0.0.1:59929 - "GET /logo?theme=dark& HTTP/1.1" 200 OK
INFO:     127.0.0.1:59929 - "GET /user HTTP/1.1" 401 Unauthorized
INFO:     127.0.0.1:59928 - "GET /auth/config HTTP/1.1" 200 OK
INFO:     127.0.0.1:59919 - "GET /project/translations?language=zh-CN& HTTP/1.1" 200 OK
INFO:     127.0.0.1:59919 - "GET /auth/oauth/chainlit-keycloak HTTP/1.1" 307 Temporary Redirect
2025-06-11 14:47:39 - HTTP Request: POST http://10.65.37.239:8080/realms/master/protocol/openid-connect/token "HTTP/1.1 200 OK"
2025-06-11 14:47:40 - HTTP Request: GET http://10.65.37.239:8080/realms/master/protocol/openid-connect/userinfo "HTTP/1.1 200 OK"
INFO:     127.0.0.1:60114 - "GET /auth/oauth/chainlit-keycloak/callback?state=Rx%25Hr.uNEG~Y%24V9l%3EY7wrsVR3%3E_n1%24-F&session_state=a453c204-b018-40f2-984a-7913ca83b2c9&iss=http%3A%2F%2F10.65.37.239%3A8080%2Frealms%2Fmaster&code=e0dcca7c-1f7c-40ec-806a-f50f8aac61cd.a453c204-b018-40f2-984a-7913ca83b2c9.c2cb61ae-c661-4d8f-a30c-eaa54c053c70 HTTP/1.1" 302 Found
INFO:     127.0.0.1:60114 - "GET /login/callback?success=True HTTP/1.1" 200 OK
INFO:     127.0.0.1:60114 - "GET /auth/config HTTP/1.1" 200 OK
INFO:     127.0.0.1:60115 - "GET /user HTTP/1.1" 200 OK
INFO:     127.0.0.1:60114 - "GET /project/translations?language=zh-CN& HTTP/1.1" 200 OK
2025-06-11 14:47:40 - Translated markdown file for zh-CN not found. Defaulting to chainlit.md.
INFO:     127.0.0.1:60114 - "GET /project/settings?language=zh-CN& HTTP/1.1" 200 OK
INFO:     127.0.0.1:60114 - "POST /set-session-cookie HTTP/1.1" 200 OK
INFO:     127.0.0.1:60114 - "GET /ws/socket.io/?EIO=4&transport=polling&t=PTTlfO2 HTTP/1.1" 200 OK
INFO:     127.0.0.1:60114 - "POST /ws/socket.io/?EIO=4&transport=polling&t=PTTlfOC&sid=W9MFmv3qqXgFxzDlAAAI HTTP/1.1" 200 OK
INFO:     127.0.0.1:60115 - "GET /ws/socket.io/?EIO=4&transport=polling&t=PTTlfOD&sid=W9MFmv3qqXgFxzDlAAAI HTTP/1.1" 200 OK
INFO:     127.0.0.1:60114 - "POST /ws/socket.io/?EIO=4&transport=polling&t=PTTlfOJ&sid=W9MFmv3qqXgFxzDlAAAI HTTP/1.1" 200 OK
INFO:     127.0.0.1:60115 - "GET /ws/socket.io/?EIO=4&transport=polling&t=PTTlfOI&sid=W9MFmv3qqXgFxzDlAAAI HTTP/1.1" 200 OK
INFO:     127.0.0.1:60115 - "GET /ws/socket.io/?EIO=4&transport=polling&t=PTTlfOT&sid=W9MFmv3qqXgFxzDlAAAI HTTP/1.1" 200 OK
INFO:     ('127.0.0.1', 60128) - "WebSocket /ws/socket.io/?EIO=4&transport=websocket&sid=W9MFmv3qqXgFxzDlAAAI" [accepted]
INFO:     127.0.0.1:60115 - "GET /ws/socket.io/?EIO=4&transport=polling&t=PTTlfOX&sid=W9MFmv3qqXgFxzDlAAAI HTTP/1.1" 200 OK
INFO:     127.0.0.1:60126 - "GET /user HTTP/1.1" 200 OK
INFO:     127.0.0.1:60126 - "GET /project/translations?language=zh-CN& HTTP/1.1" 200 OK
INFO:     127.0.0.1:60228 - "GET /user HTTP/1.1" 200 OK
INFO:     127.0.0.1:60228 - "GET /project/translations?language=zh-CN& HTTP/1.1" 200 OK
INFO:     127.0.0.1:60271 - "GET /user HTTP/1.1" 200 OK
2025-06-11 14:48:10 - Retrying request to /chat/completions in 0.487590 seconds
2025-06-11 14:48:16 - Retrying request to /chat/completions in 0.839006 seconds
2025-06-11 14:48:17 - HTTP Request: POST https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions "HTTP/1.1 200 OK"
INFO:     127.0.0.1:60357 - "GET /avatars/Assistant HTTP/1.1" 200 OK
INFO:     127.0.0.1:60357 - "GET /avatars/qwen-plus HTTP/1.1" 200 OK
INFO:     127.0.0.1:60357 - "GET /user HTTP/1.1" 200 OK
INFO:     127.0.0.1:60358 - "GET /project/translations?language=zh-CN& HTTP/1.1" 200 OK
INFO:     127.0.0.1:60410 - "GET /user HTTP/1.1" 200 OK
INFO:     127.0.0.1:60411 - "GET /project/translations?language=zh-CN& HTTP/1.1" 200 OK
INFO:     127.0.0.1:60415 - "GET /user HTTP/1.1" 200 OK
INFO:     127.0.0.1:60415 - "GET /project/translations?language=zh-CN& HTTP/1.1" 200 OK
INFO:     127.0.0.1:60415 - "POST /logout HTTP/1.1" 200 OK
INFO:     127.0.0.1:60415 - "GET / HTTP/1.1" 200 OK
INFO:     127.0.0.1:60415 - "GET /auth/config HTTP/1.1" 200 OK
INFO:     127.0.0.1:60479 - "GET /user HTTP/1.1" 401 Unauthorized
INFO:     127.0.0.1:60415 - "GET /project/translations?language=zh-CN& HTTP/1.1" 200 OK
INFO:     127.0.0.1:60415 - "GET /login HTTP/1.1" 200 OK
INFO:     127.0.0.1:60415 - "GET /user HTTP/1.1" 401 Unauthorized
INFO:     127.0.0.1:60479 - "GET /auth/config HTTP/1.1" 200 OK
INFO:     127.0.0.1:60415 - "GET /project/translations?language=zh-CN& HTTP/1.1" 200 OK
INFO:     127.0.0.1:60415 - "GET /auth/oauth/chainlit-keycloak HTTP/1.1" 307 Temporary Redirect
2025-06-11 14:48:50 - HTTP Request: POST http://10.65.37.239:8080/realms/master/protocol/openid-connect/token "HTTP/1.1 200 OK"
2025-06-11 14:48:51 - HTTP Request: GET http://10.65.37.239:8080/realms/master/protocol/openid-connect/userinfo "HTTP/1.1 200 OK"
INFO:     127.0.0.1:60415 - "GET /auth/oauth/chainlit-keycloak/callback?state=GRv%3DyZw2%2Fj%3EFR%3E%3A%25TLuHbPK~4u%3EHMx%25G&session_state=a453c204-b018-40f2-984a-7913ca83b2c9&iss=http%3A%2F%2F10.65.37.239%3A8080%2Frealms%2Fmaster&code=c89ad3dd-6042-4e94-9e51-d7aa962b6af7.a453c204-b018-40f2-984a-7913ca83b2c9.c2cb61ae-c661-4d8f-a30c-eaa54c053c70 HTTP/1.1" 302 Found
INFO:     127.0.0.1:60415 - "GET /login/callback?success=True HTTP/1.1" 200 OK
INFO:     127.0.0.1:60415 - "GET /auth/config HTTP/1.1" 200 OK
INFO:     127.0.0.1:60479 - "GET /user HTTP/1.1" 200 OK
INFO:     127.0.0.1:60482 - "GET /project/translations?language=zh-CN& HTTP/1.1" 200 OK
2025-06-11 14:48:51 - Translated markdown file for zh-CN not found. Defaulting to chainlit.md.
INFO:     127.0.0.1:60482 - "GET /project/settings?language=zh-CN& HTTP/1.1" 200 OK
INFO:     127.0.0.1:60482 - "POST /set-session-cookie HTTP/1.1" 200 OK
INFO:     127.0.0.1:60482 - "GET /ws/socket.io/?EIO=4&transport=polling&t=PTTlwmQ HTTP/1.1" 200 OK
INFO:     127.0.0.1:60482 - "POST /ws/socket.io/?EIO=4&transport=polling&t=PTTlwmY&sid=f7_nQWRj5C-PiHVEAAAK HTTP/1.1" 200 OK
INFO:     127.0.0.1:60479 - "GET /ws/socket.io/?EIO=4&transport=polling&t=PTTlwmY.0&sid=f7_nQWRj5C-PiHVEAAAK HTTP/1.1" 200 OK
INFO:     127.0.0.1:60482 - "POST /ws/socket.io/?EIO=4&transport=polling&t=PTTlwmf&sid=f7_nQWRj5C-PiHVEAAAK HTTP/1.1" 200 OK
INFO:     127.0.0.1:60479 - "GET /ws/socket.io/?EIO=4&transport=polling&t=PTTlwme&sid=f7_nQWRj5C-PiHVEAAAK HTTP/1.1" 200 OK
INFO:     127.0.0.1:60479 - "GET /ws/socket.io/?EIO=4&transport=polling&t=PTTlwmm&sid=f7_nQWRj5C-PiHVEAAAK HTTP/1.1" 200 OK
INFO:     ('127.0.0.1', 60526) - "WebSocket /ws/socket.io/?EIO=4&transport=websocket&sid=f7_nQWRj5C-PiHVEAAAK" [accepted]
INFO:     127.0.0.1:60479 - "GET /ws/socket.io/?EIO=4&transport=polling&t=PTTlwmq&sid=f7_nQWRj5C-PiHVEAAAK HTTP/1.1" 200 OK
INFO:     127.0.0.1:60491 - "POST /logout HTTP/1.1" 200 OK
INFO:     127.0.0.1:60491 - "GET / HTTP/1.1" 200 OK
INFO:     127.0.0.1:60491 - "GET /auth/config HTTP/1.1" 200 OK
INFO:     127.0.0.1:60491 - "GET /user HTTP/1.1" 401 Unauthorized
INFO:     127.0.0.1:60491 - "GET /project/translations?language=zh-CN& HTTP/1.1" 200 OK
INFO:     127.0.0.1:60491 - "GET /login HTTP/1.1" 200 OK
INFO:     127.0.0.1:60491 - "GET /auth/config HTTP/1.1" 200 OK
INFO:     127.0.0.1:60491 - "GET /user HTTP/1.1" 401 Unauthorized
INFO:     127.0.0.1:60491 - "GET /project/translations?language=zh-CN& HTTP/1.1" 200 OK
INFO:     127.0.0.1:60491 - "GET /auth/oauth/chainlit-keycloak HTTP/1.1" 307 Temporary Redirect
2025-06-11 14:49:04 - HTTP Request: POST http://10.65.37.239:8080/realms/master/protocol/openid-connect/token "HTTP/1.1 200 OK"
2025-06-11 14:49:05 - HTTP Request: GET http://10.65.37.239:8080/realms/master/protocol/openid-connect/userinfo "HTTP/1.1 200 OK"
INFO:     127.0.0.1:60491 - "GET /auth/oauth/chainlit-keycloak/callback?state=Vgz7P%5E4m%2C%3AhO6DZckA8s7z7qc*Bx%240l.&session_state=a453c204-b018-40f2-984a-7913ca83b2c9&iss=http%3A%2F%2F10.65.37.239%3A8080%2Frealms%2Fmaster&code=01eee904-48cc-44f8-a2d1-9e9b2070a6f3.a453c204-b018-40f2-984a-7913ca83b2c9.c2cb61ae-c661-4d8f-a30c-eaa54c053c70 HTTP/1.1" 302 Found
INFO:     127.0.0.1:60491 - "GET /login/callback?success=True HTTP/1.1" 200 OK
INFO:     127.0.0.1:60491 - "GET /user HTTP/1.1" 200 OK
INFO:     127.0.0.1:60567 - "GET /auth/config HTTP/1.1" 200 OK
INFO:     127.0.0.1:60568 - "GET /project/translations?language=zh-CN& HTTP/1.1" 200 OK
2025-06-11 14:49:05 - Translated markdown file for zh-CN not found. Defaulting to chainlit.md.
INFO:     127.0.0.1:60568 - "GET /project/settings?language=zh-CN& HTTP/1.1" 200 OK
INFO:     127.0.0.1:60568 - "POST /set-session-cookie HTTP/1.1" 200 OK
INFO:     127.0.0.1:60568 - "GET /ws/socket.io/?EIO=4&transport=polling&t=PTTl-BC HTTP/1.1" 200 OK
INFO:     127.0.0.1:60568 - "POST /ws/socket.io/?EIO=4&transport=polling&t=PTTl-BH&sid=2BgXYmAwfamF-B9gAAAM HTTP/1.1" 200 OK
INFO:     127.0.0.1:60567 - "GET /ws/socket.io/?EIO=4&transport=polling&t=PTTl-BI&sid=2BgXYmAwfamF-B9gAAAM HTTP/1.1" 200 OK
INFO:     127.0.0.1:60568 - "POST /ws/socket.io/?EIO=4&transport=polling&t=PTTl-BY.0&sid=2BgXYmAwfamF-B9gAAAM HTTP/1.1" 200 OK
INFO:     127.0.0.1:60567 - "GET /ws/socket.io/?EIO=4&transport=polling&t=PTTl-BY&sid=2BgXYmAwfamF-B9gAAAM HTTP/1.1" 200 OK
INFO:     127.0.0.1:60567 - "GET /ws/socket.io/?EIO=4&transport=polling&t=PTTl-Be&sid=2BgXYmAwfamF-B9gAAAM HTTP/1.1" 200 OK
INFO:     ('127.0.0.1', 60611) - "WebSocket /ws/socket.io/?EIO=4&transport=websocket&sid=2BgXYmAwfamF-B9gAAAM" [accepted]
INFO:     127.0.0.1:60567 - "GET /ws/socket.io/?EIO=4&transport=polling&t=PTTl-Bp&sid=2BgXYmAwfamF-B9gAAAM HTTP/1.1" 200 OK
INFO:     127.0.0.1:60668 - "GET / HTTP/1.1" 200 OK
INFO:     127.0.0.1:60668 - "GET /assets/index-B28WSRhf.js HTTP/1.1" 200 OK
INFO:     127.0.0.1:60668 - "GET /assets/index-BIhgNEQJ.css HTTP/1.1" 200 OK
INFO:     127.0.0.1:60668 - "GET /auth/config HTTP/1.1" 200 OK
INFO:     127.0.0.1:60675 - "GET /user HTTP/1.1" 401 Unauthorized
INFO:     127.0.0.1:60676 - "GET /project/translations?language=zh-CN& HTTP/1.1" 200 OK
INFO:     127.0.0.1:60676 - "GET /favicon HTTP/1.1" 200 OK
INFO:     127.0.0.1:60676 - "GET /login HTTP/1.1" 200 OK
INFO:     127.0.0.1:60676 - "GET /logo?theme=dark& HTTP/1.1" 200 OK
INFO:     127.0.0.1:60676 - "GET /user HTTP/1.1" 401 Unauthorized
INFO:     127.0.0.1:60675 - "GET /auth/config HTTP/1.1" 200 OK
INFO:     127.0.0.1:60668 - "GET /project/translations?language=zh-CN& HTTP/1.1" 200 OK
INFO:     127.0.0.1:60668 - "GET /auth/oauth/chainlit-keycloak HTTP/1.1" 307 Temporary Redirect
INFO:     Shutting down
INFO:     Waiting for application shutdown.

发现的问题

注销后,不会再次弹出登录页面

我单击sign out(退出登录)后,再次点击“继续使用chainlit-keycloak”,并没有弹出keycloak登录页面,而是直接自动登录了,登录的用户是上一次点击注销的用户

image.png

可能的解决方案:

我在官方文档中看到了这样一部分代码,或许可以解决此问题,没有验证过。

image.png

关于chainlit .env文件的特别说明

.env文件最佳实际

不要有空格;

不要在值的两边加双引号;

决不能在值的末尾用#进行注释,应该另外加一行进行注释。

下面这个.env文件是符合规范的:

# OAUTH_KEYCLOAK_BASE_URL = "http://10.65.37.239:8080"
DASHSCOPE_API_KEY=<此处替换为你的api_key>
OPENAI_API_KEY=<此处替换为你的api_key>

OAUTH_KEYCLOAK_BASE_URL=http://10.65.37.239:8080
#OAUTH_KEYCLOAK_REALM的值就是keycloak中的REALM名,keycloak中默认的REALM是master,但是也可以再新建REALM
OAUTH_KEYCLOAK_REALM = "master"
OAUTH_KEYCLOAK_CLIENT_ID = "chainlit-client"
#下面这个环境变量的值可以在keycloak中直接复制:client--credentials--client secret
#OAUTH_KEYCLOAK_CLIENT_SECRET和CHAINLIT_AUTH_SECRET的值要保持一致,另外千万注意,不要在=号两边加上空格,也不要对环境变量的值用双引号,这会导致实际的环境变量值发生变化,从而导致chainlit身份认证出现问题。不要在环境变量值的后面加上#号,因为这会赋值给环境变量,如果要对.env文件进行注释,请在单独的行中进行注释。
OAUTH_KEYCLOAK_CLIENT_SECRET=7M7FzG7pVNe0RA84C75cgWk0VHzCCLm6
# CHAINLIT_AUTH_SECRET="F3rrs1vky1*MU9~ron_p1ntNfu2Rv1GiSWgl1p:$=>Yl0cRFubC?2=I1=$uCBLVS"
CHAINLIT_AUTH_SECRET=7M7FzG7pVNe0RA84C75cgWk0VHzCCLm6
#OAUTH_KEYCLOAK_NAME的值可以自己设置,如果不设置,默认为keycloak
OAUTH_KEYCLOAK_NAME = "chainlit-keycloak"

下面这种做法完全错误,会导致环境变量赋值错误。

image.png

更改.env文件后,要新创建终端

我注意到,更改.env文件后,如果重新启动chainlit应用,则chainlit获取到的环境变量的值仍然是旧的,是错误的,需要再创建一个终端,再次运行chainlit,才能真正应用当前的.env文件

image.png

关注微信公众号“AI发烧友”,获取更多IT开发运维实用工具与技巧,还有很多AI技术文档!

梦幻智能logo-01(无水印).png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值