mirror of
https://18126008609:longquanjian123@gitee.com/feigong123/aurask.git
synced 2026-04-19 16:18:24 +00:00
Remove LY SSO sign-in flow
All checks were successful
aurask-release / build-and-deploy (push) Successful in 1m52s
All checks were successful
aurask-release / build-and-deploy (push) Successful in 1m52s
This commit is contained in:
parent
c44746a5a8
commit
4e2639ea43
@ -10,7 +10,7 @@ Aurask 当前处于 **可运行 MVP / 初版门户** 阶段,已覆盖:
|
|||||||
- Python 模块化后端
|
- Python 模块化后端
|
||||||
- 标准库 HTTP Gateway
|
- 标准库 HTTP Gateway
|
||||||
- 租户、用户、API Key、Session
|
- 租户、用户、API Key、Session
|
||||||
- `LY SSO` / Google 登录入口
|
- Google 登录入口
|
||||||
- 首次登录自动创建独立 workspace
|
- 首次登录自动创建独立 workspace
|
||||||
- 配额 / TBU / 订单 / 支付闭环
|
- 配额 / TBU / 订单 / 支付闭环
|
||||||
- 工作流模板编排
|
- 工作流模板编排
|
||||||
@ -92,7 +92,6 @@ Browser
|
|||||||
未登录:
|
未登录:
|
||||||
|
|
||||||
- 渲染 `/signin`
|
- 渲染 `/signin`
|
||||||
- 提供 `Use LY SSO`
|
|
||||||
- 提供 `Continue with Google`
|
- 提供 `Continue with Google`
|
||||||
|
|
||||||
已登录:
|
已登录:
|
||||||
@ -107,11 +106,7 @@ Browser
|
|||||||
|
|
||||||
当前支持:
|
当前支持:
|
||||||
|
|
||||||
1. `LY SSO`
|
1. Google
|
||||||
- 以按钮形式进入
|
|
||||||
- 当前实现为配置驱动的本地接入层
|
|
||||||
- 通过 `AURASK_LY_SSO_USERNAME` / `AURASK_LY_SSO_PASSWORD` 控制
|
|
||||||
2. Google
|
|
||||||
- 通过 `AURASK_GOOGLE_CLIENT_ID` 开启
|
- 通过 `AURASK_GOOGLE_CLIENT_ID` 开启
|
||||||
- 首次注册后自动开通独立 tenant + user + workspace
|
- 首次注册后自动开通独立 tenant + user + workspace
|
||||||
|
|
||||||
@ -153,7 +148,7 @@ Browser
|
|||||||
- 公网域名
|
- 公网域名
|
||||||
- API 地址
|
- API 地址
|
||||||
- Langflow / AnythingLLM 嵌入地址
|
- Langflow / AnythingLLM 嵌入地址
|
||||||
- `LY SSO` / Google 开关
|
- Google 开关
|
||||||
- DevCloud 镜像 / NodePort 默认值
|
- DevCloud 镜像 / NodePort 默认值
|
||||||
|
|
||||||
### `knowledge_base.py`
|
### `knowledge_base.py`
|
||||||
@ -180,7 +175,6 @@ Browser
|
|||||||
GET /health
|
GET /health
|
||||||
GET /plans
|
GET /plans
|
||||||
GET /auth/config
|
GET /auth/config
|
||||||
POST /auth/ly-sso/login
|
|
||||||
POST /auth/google/login
|
POST /auth/google/login
|
||||||
POST /demo/bootstrap
|
POST /demo/bootstrap
|
||||||
POST /tenants
|
POST /tenants
|
||||||
@ -307,7 +301,6 @@ python -m unittest discover -s tests -v
|
|||||||
|
|
||||||
- MVP 核心业务闭环
|
- MVP 核心业务闭环
|
||||||
- 桥接配置契约
|
- 桥接配置契约
|
||||||
- `LY SSO` 登录
|
|
||||||
- Google 首次登录建 workspace
|
- Google 首次登录建 workspace
|
||||||
- Session 认证
|
- Session 认证
|
||||||
|
|
||||||
|
|||||||
@ -10,8 +10,7 @@ Aurask 当前是一个按产品边界拆分的首版实现,根目录保持为
|
|||||||
当前版本已经补齐了用户门户登录闭环:
|
当前版本已经补齐了用户门户登录闭环:
|
||||||
|
|
||||||
- `/signin` 风格化登录页
|
- `/signin` 风格化登录页
|
||||||
- `LY SSO` 登录入口
|
- Google 首次注册/登录后自动创建独立 workspace
|
||||||
- Google 首次注册/登录后自动创建用户独立 workspace
|
|
||||||
- 登录后双标签页工作台:
|
- 登录后双标签页工作台:
|
||||||
- `Workflows` 内嵌 `Langflow`
|
- `Workflows` 内嵌 `Langflow`
|
||||||
- `Knowledge Base` 内嵌 `AnythingLLM`
|
- `Knowledge Base` 内嵌 `AnythingLLM`
|
||||||
@ -42,7 +41,6 @@ py -3 -m aurask demo --reset
|
|||||||
- `GET /health`
|
- `GET /health`
|
||||||
- `GET /plans`
|
- `GET /plans`
|
||||||
- `GET /auth/config`
|
- `GET /auth/config`
|
||||||
- `POST /auth/ly-sso/login`
|
|
||||||
- `POST /auth/google/login`
|
- `POST /auth/google/login`
|
||||||
- `POST /demo/bootstrap`
|
- `POST /demo/bootstrap`
|
||||||
- `POST /tenants`
|
- `POST /tenants`
|
||||||
@ -77,9 +75,6 @@ AURASK_PUBLIC_BASE_URL=https://aurask.xyz
|
|||||||
AURASK_PUBLIC_API_BASE_URL=https://aurask.xyz/api
|
AURASK_PUBLIC_API_BASE_URL=https://aurask.xyz/api
|
||||||
AURASK_PUBLIC_LANGFLOW_URL=https://aurask.xyz/runtime/langflow/
|
AURASK_PUBLIC_LANGFLOW_URL=https://aurask.xyz/runtime/langflow/
|
||||||
AURASK_PUBLIC_ANYTHINGLLM_URL=https://aurask.xyz/runtime/anythingllm/
|
AURASK_PUBLIC_ANYTHINGLLM_URL=https://aurask.xyz/runtime/anythingllm/
|
||||||
AURASK_LY_SSO_ENABLED=true
|
|
||||||
AURASK_LY_SSO_USERNAME=ly-xujian1
|
|
||||||
AURASK_LY_SSO_PASSWORD=<inject-secret>
|
|
||||||
AURASK_GOOGLE_ENABLED=true
|
AURASK_GOOGLE_ENABLED=true
|
||||||
AURASK_GOOGLE_CLIENT_ID=<google-client-id>
|
AURASK_GOOGLE_CLIENT_ID=<google-client-id>
|
||||||
AURASK_SESSION_TTL_DAYS=7
|
AURASK_SESSION_TTL_DAYS=7
|
||||||
@ -124,7 +119,7 @@ cmd /c "py -3 -m unittest discover -s tests -v"
|
|||||||
|
|
||||||
- MVP 业务闭环
|
- MVP 业务闭环
|
||||||
- PostgreSQL / PGVector / Redis / AnythingLLM / Langflow 桥接契约
|
- PostgreSQL / PGVector / Redis / AnythingLLM / Langflow 桥接契约
|
||||||
- `LY SSO` / Google 登录与 session
|
- Google 登录与 session
|
||||||
|
|
||||||
## 相关文档
|
## 相关文档
|
||||||
|
|
||||||
|
|||||||
@ -9,7 +9,7 @@
|
|||||||
- 租户、用户、API Key、Session:`api/aurask/auth.py`
|
- 租户、用户、API Key、Session:`api/aurask/auth.py`
|
||||||
- 套餐、订单、支付、TBU:`api/aurask/plans.py`、`api/aurask/billing.py`、`api/aurask/quota.py`
|
- 套餐、订单、支付、TBU:`api/aurask/plans.py`、`api/aurask/billing.py`、`api/aurask/quota.py`
|
||||||
- 工作流编排:`api/aurask/orchestrator.py`
|
- 工作流编排:`api/aurask/orchestrator.py`
|
||||||
- AnythingLLM workspace / 文档接入:`api/aurask/knowledge_base.py`
|
- AnythingLLM workspace / 文档接入门面:`api/aurask/knowledge_base.py`
|
||||||
- PostgreSQL / PGVector / Redis / AnythingLLM / Langflow 桥接:`api/aurask/bridges/`
|
- PostgreSQL / PGVector / Redis / AnythingLLM / Langflow 桥接:`api/aurask/bridges/`
|
||||||
- 门户站点配置:`api/aurask/site_config.py`
|
- 门户站点配置:`api/aurask/site_config.py`
|
||||||
|
|
||||||
@ -22,7 +22,7 @@ Aurask 现在支持两类 Bearer Token:
|
|||||||
- 由创建租户/用户或 demo bootstrap 返回
|
- 由创建租户/用户或 demo bootstrap 返回
|
||||||
2. Session Token
|
2. Session Token
|
||||||
- 适用于 `protal/` 登录态
|
- 适用于 `protal/` 登录态
|
||||||
- 由 `LY SSO` 或 Google 登录接口签发
|
- 由 Google 登录接口签发
|
||||||
|
|
||||||
## 公开接口
|
## 公开接口
|
||||||
|
|
||||||
@ -30,7 +30,6 @@ Aurask 现在支持两类 Bearer Token:
|
|||||||
GET /health
|
GET /health
|
||||||
GET /plans
|
GET /plans
|
||||||
GET /auth/config
|
GET /auth/config
|
||||||
POST /auth/ly-sso/login
|
|
||||||
POST /auth/google/login
|
POST /auth/google/login
|
||||||
POST /demo/bootstrap
|
POST /demo/bootstrap
|
||||||
POST /tenants
|
POST /tenants
|
||||||
@ -60,7 +59,7 @@ GET /admin/bridge-status
|
|||||||
|
|
||||||
- 公网站点地址
|
- 公网站点地址
|
||||||
- API 地址
|
- API 地址
|
||||||
- `LY SSO` / Google 开关
|
- Google 开关
|
||||||
- Langflow / AnythingLLM iframe 地址
|
- Langflow / AnythingLLM iframe 地址
|
||||||
- DevCloud 对齐后的镜像与 NodePort 默认值
|
- DevCloud 对齐后的镜像与 NodePort 默认值
|
||||||
|
|
||||||
@ -73,11 +72,6 @@ AURASK_PUBLIC_BASE_URL=https://aurask.xyz
|
|||||||
AURASK_PUBLIC_API_BASE_URL=https://aurask.xyz/api
|
AURASK_PUBLIC_API_BASE_URL=https://aurask.xyz/api
|
||||||
AURASK_PUBLIC_LANGFLOW_URL=https://aurask.xyz/runtime/langflow/
|
AURASK_PUBLIC_LANGFLOW_URL=https://aurask.xyz/runtime/langflow/
|
||||||
AURASK_PUBLIC_ANYTHINGLLM_URL=https://aurask.xyz/runtime/anythingllm/
|
AURASK_PUBLIC_ANYTHINGLLM_URL=https://aurask.xyz/runtime/anythingllm/
|
||||||
AURASK_LY_SSO_ENABLED=true
|
|
||||||
AURASK_LY_SSO_LOGIN_URL=
|
|
||||||
AURASK_LY_SSO_USERNAME=ly-xujian1
|
|
||||||
AURASK_LY_SSO_PASSWORD=<ly-sso-password>
|
|
||||||
AURASK_LY_SSO_EMAIL_DOMAIN=ly.szlanyou.local
|
|
||||||
AURASK_GOOGLE_ENABLED=true
|
AURASK_GOOGLE_ENABLED=true
|
||||||
AURASK_GOOGLE_CLIENT_ID=<google-client-id>
|
AURASK_GOOGLE_CLIENT_ID=<google-client-id>
|
||||||
AURASK_GOOGLE_TOKENINFO_URL=https://oauth2.googleapis.com/tokeninfo
|
AURASK_GOOGLE_TOKENINFO_URL=https://oauth2.googleapis.com/tokeninfo
|
||||||
|
|||||||
@ -50,10 +50,6 @@ def make_handler(app: AuraskApp):
|
|||||||
if method == "GET" and path == "/auth/config":
|
if method == "GET" and path == "/auth/config":
|
||||||
self._send(200, app.public_auth_config())
|
self._send(200, app.public_auth_config())
|
||||||
return
|
return
|
||||||
if method == "POST" and path == "/auth/ly-sso/login":
|
|
||||||
body = self._read_json()
|
|
||||||
self._send(200, app.login_with_ly_sso(username=body.get("username", ""), password=body.get("password", "")))
|
|
||||||
return
|
|
||||||
if method == "POST" and path == "/auth/google/login":
|
if method == "POST" and path == "/auth/google/login":
|
||||||
body = self._read_json()
|
body = self._read_json()
|
||||||
self._send(200, app.login_with_google(id_token=body.get("id_token", "")))
|
self._send(200, app.login_with_google(id_token=body.get("id_token", "")))
|
||||||
|
|||||||
@ -54,22 +54,6 @@ class AuraskApp:
|
|||||||
def public_auth_config(self) -> dict:
|
def public_auth_config(self) -> dict:
|
||||||
return self.site_config.public_dict()
|
return self.site_config.public_dict()
|
||||||
|
|
||||||
def login_with_ly_sso(self, *, username: str, password: str) -> dict:
|
|
||||||
if not self.site_config.ly_sso_enabled:
|
|
||||||
raise AuthError("LY SSO is not enabled")
|
|
||||||
if not self.site_config.ly_sso_password:
|
|
||||||
raise AuthError("LY SSO password secret is not configured")
|
|
||||||
if username != self.site_config.ly_sso_username or password != self.site_config.ly_sso_password:
|
|
||||||
raise AuthError("invalid LY SSO credentials")
|
|
||||||
email = os.getenv("AURASK_LY_SSO_EMAIL", f"{username}@{self.site_config.ly_sso_email_domain}")
|
|
||||||
return self._sign_in_external_identity(
|
|
||||||
provider="ly_sso",
|
|
||||||
subject=username,
|
|
||||||
email=email,
|
|
||||||
display_name=username,
|
|
||||||
avatar_url="",
|
|
||||||
)
|
|
||||||
|
|
||||||
def login_with_google(self, *, id_token: str) -> dict:
|
def login_with_google(self, *, id_token: str) -> dict:
|
||||||
claims = self._verify_google_id_token(id_token)
|
claims = self._verify_google_id_token(id_token)
|
||||||
email = claims.get("email", "").strip().lower()
|
email = claims.get("email", "").strip().lower()
|
||||||
|
|||||||
@ -17,11 +17,6 @@ class SiteConfig:
|
|||||||
public_api_base_url: str
|
public_api_base_url: str
|
||||||
langflow_embed_url: str
|
langflow_embed_url: str
|
||||||
anythingllm_embed_url: str
|
anythingllm_embed_url: str
|
||||||
ly_sso_enabled: bool
|
|
||||||
ly_sso_login_url: str
|
|
||||||
ly_sso_username: str
|
|
||||||
ly_sso_password: str
|
|
||||||
ly_sso_email_domain: str
|
|
||||||
google_enabled: bool
|
google_enabled: bool
|
||||||
google_client_id: str
|
google_client_id: str
|
||||||
google_tokeninfo_url: str
|
google_tokeninfo_url: str
|
||||||
@ -40,11 +35,6 @@ class SiteConfig:
|
|||||||
public_api_base_url=os.getenv("AURASK_PUBLIC_API_BASE_URL", f"{public_base_url}/api").rstrip("/"),
|
public_api_base_url=os.getenv("AURASK_PUBLIC_API_BASE_URL", f"{public_base_url}/api").rstrip("/"),
|
||||||
langflow_embed_url=os.getenv("AURASK_PUBLIC_LANGFLOW_URL", f"{public_base_url}/runtime/langflow/"),
|
langflow_embed_url=os.getenv("AURASK_PUBLIC_LANGFLOW_URL", f"{public_base_url}/runtime/langflow/"),
|
||||||
anythingllm_embed_url=os.getenv("AURASK_PUBLIC_ANYTHINGLLM_URL", f"{public_base_url}/runtime/anythingllm/"),
|
anythingllm_embed_url=os.getenv("AURASK_PUBLIC_ANYTHINGLLM_URL", f"{public_base_url}/runtime/anythingllm/"),
|
||||||
ly_sso_enabled=_enabled("AURASK_LY_SSO_ENABLED", True),
|
|
||||||
ly_sso_login_url=os.getenv("AURASK_LY_SSO_LOGIN_URL", ""),
|
|
||||||
ly_sso_username=os.getenv("AURASK_LY_SSO_USERNAME", "ly-xujian1"),
|
|
||||||
ly_sso_password=os.getenv("AURASK_LY_SSO_PASSWORD", ""),
|
|
||||||
ly_sso_email_domain=os.getenv("AURASK_LY_SSO_EMAIL_DOMAIN", "ly.szlanyou.local"),
|
|
||||||
google_enabled=_enabled("AURASK_GOOGLE_ENABLED", bool(os.getenv("AURASK_GOOGLE_CLIENT_ID", ""))),
|
google_enabled=_enabled("AURASK_GOOGLE_ENABLED", bool(os.getenv("AURASK_GOOGLE_CLIENT_ID", ""))),
|
||||||
google_client_id=os.getenv("AURASK_GOOGLE_CLIENT_ID", ""),
|
google_client_id=os.getenv("AURASK_GOOGLE_CLIENT_ID", ""),
|
||||||
google_tokeninfo_url=os.getenv("AURASK_GOOGLE_TOKENINFO_URL", "https://oauth2.googleapis.com/tokeninfo"),
|
google_tokeninfo_url=os.getenv("AURASK_GOOGLE_TOKENINFO_URL", "https://oauth2.googleapis.com/tokeninfo"),
|
||||||
@ -61,11 +51,6 @@ class SiteConfig:
|
|||||||
"public_base_url": self.public_base_url,
|
"public_base_url": self.public_base_url,
|
||||||
"public_api_base_url": self.public_api_base_url,
|
"public_api_base_url": self.public_api_base_url,
|
||||||
"auth": {
|
"auth": {
|
||||||
"ly_sso": {
|
|
||||||
"enabled": self.ly_sso_enabled,
|
|
||||||
"login_url": self.ly_sso_login_url,
|
|
||||||
"username_hint": self.ly_sso_username,
|
|
||||||
},
|
|
||||||
"google": {
|
"google": {
|
||||||
"enabled": self.google_enabled,
|
"enabled": self.google_enabled,
|
||||||
"client_id": self.google_client_id,
|
"client_id": self.google_client_id,
|
||||||
|
|||||||
@ -7,15 +7,6 @@ GET http://127.0.0.1:8080/plans
|
|||||||
### Portal auth config
|
### Portal auth config
|
||||||
GET http://127.0.0.1:8080/auth/config
|
GET http://127.0.0.1:8080/auth/config
|
||||||
|
|
||||||
### LY SSO login
|
|
||||||
POST http://127.0.0.1:8080/auth/ly-sso/login
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"username": "ly-xujian1",
|
|
||||||
"password": "replace-with-env-password"
|
|
||||||
}
|
|
||||||
|
|
||||||
### Google login
|
### Google login
|
||||||
POST http://127.0.0.1:8080/auth/google/login
|
POST http://127.0.0.1:8080/auth/google/login
|
||||||
Content-Type: application/json
|
Content-Type: application/json
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
本文档基于当前仓库与 DevCloud 现网结构,兼顾两部分目标:
|
本文档基于当前仓库与 DevCloud 现网结构,兼顾两部分目标:
|
||||||
|
|
||||||
- 保留已落地的 DevCloud `base + production overlay` 部署方式
|
- 保留已落地的 DevCloud `base + production overlay` 部署方式
|
||||||
- 纳入本次新增的门户登录流、`LY SSO` / Google、Langflow / AnythingLLM 嵌入配置
|
- 纳入本次新增的门户登录流、Google 登录、Langflow / AnythingLLM 嵌入配置
|
||||||
|
|
||||||
## 目录结构
|
## 目录结构
|
||||||
|
|
||||||
@ -95,8 +95,6 @@ deploy/k3s/
|
|||||||
- `AURASK_DEVCLOUD_WEB_IMAGE=registry.mydevcloud.love/devcloud/aurask-web:latest`
|
- `AURASK_DEVCLOUD_WEB_IMAGE=registry.mydevcloud.love/devcloud/aurask-web:latest`
|
||||||
- `AURASK_DEVCLOUD_API_NODE_URL=http://45.113.2.55:30091`
|
- `AURASK_DEVCLOUD_API_NODE_URL=http://45.113.2.55:30091`
|
||||||
- `AURASK_DEVCLOUD_WEB_NODE_URL=http://45.113.2.55:30090`
|
- `AURASK_DEVCLOUD_WEB_NODE_URL=http://45.113.2.55:30090`
|
||||||
- `AURASK_LY_SSO_ENABLED=true`
|
|
||||||
- `AURASK_LY_SSO_USERNAME=ly-xujian1`
|
|
||||||
- `AURASK_GOOGLE_ENABLED=true`
|
- `AURASK_GOOGLE_ENABLED=true`
|
||||||
- `AURASK_SESSION_TTL_DAYS=7`
|
- `AURASK_SESSION_TTL_DAYS=7`
|
||||||
|
|
||||||
@ -107,7 +105,6 @@ deploy/k3s/
|
|||||||
- `AURASK_DATABASE_URL`
|
- `AURASK_DATABASE_URL`
|
||||||
- `AURASK_ANYTHINGLLM_API_KEY`
|
- `AURASK_ANYTHINGLLM_API_KEY`
|
||||||
- `AURASK_LANGFLOW_API_KEY`
|
- `AURASK_LANGFLOW_API_KEY`
|
||||||
- `AURASK_LY_SSO_PASSWORD`
|
|
||||||
- `AURASK_GOOGLE_CLIENT_ID`
|
- `AURASK_GOOGLE_CLIENT_ID`
|
||||||
|
|
||||||
说明:
|
说明:
|
||||||
@ -122,7 +119,7 @@ deploy/k3s/
|
|||||||
职责:
|
职责:
|
||||||
|
|
||||||
- API Gateway
|
- API Gateway
|
||||||
- `LY SSO` / Google 登录
|
- Google 登录
|
||||||
- Session 签发与校验
|
- Session 签发与校验
|
||||||
- 配额、订单、支付、工作流入口
|
- 配额、订单、支付、工作流入口
|
||||||
- 返回门户配置与嵌入 URL
|
- 返回门户配置与嵌入 URL
|
||||||
|
|||||||
@ -21,9 +21,6 @@ data:
|
|||||||
AURASK_REDIS_WORKFLOW_QUEUE: aurask:workflow-runs
|
AURASK_REDIS_WORKFLOW_QUEUE: aurask:workflow-runs
|
||||||
AURASK_ANYTHINGLLM_BASE_URL: http://anythingllm.aurask-runtime.svc.cluster.local:3001
|
AURASK_ANYTHINGLLM_BASE_URL: http://anythingllm.aurask-runtime.svc.cluster.local:3001
|
||||||
AURASK_LANGFLOW_BASE_URL: http://langflow-runtime.aurask-runtime.svc.cluster.local:7860
|
AURASK_LANGFLOW_BASE_URL: http://langflow-runtime.aurask-runtime.svc.cluster.local:7860
|
||||||
AURASK_LY_SSO_ENABLED: "true"
|
|
||||||
AURASK_LY_SSO_USERNAME: ly-xujian1
|
|
||||||
AURASK_LY_SSO_EMAIL_DOMAIN: ly.szlanyou.local
|
|
||||||
AURASK_GOOGLE_ENABLED: "true"
|
AURASK_GOOGLE_ENABLED: "true"
|
||||||
AURASK_SESSION_TTL_DAYS: "7"
|
AURASK_SESSION_TTL_DAYS: "7"
|
||||||
AURASK_CORS_ALLOW_ORIGIN: https://aurask.xyz
|
AURASK_CORS_ALLOW_ORIGIN: https://aurask.xyz
|
||||||
|
|||||||
@ -8,5 +8,4 @@ stringData:
|
|||||||
AURASK_DATABASE_URL: postgresql://aurask:<postgres-password>@postgres.aurask-data.svc.cluster.local:5432/aurask
|
AURASK_DATABASE_URL: postgresql://aurask:<postgres-password>@postgres.aurask-data.svc.cluster.local:5432/aurask
|
||||||
AURASK_ANYTHINGLLM_API_KEY: <anythingllm-api-key>
|
AURASK_ANYTHINGLLM_API_KEY: <anythingllm-api-key>
|
||||||
AURASK_LANGFLOW_API_KEY: <langflow-api-key>
|
AURASK_LANGFLOW_API_KEY: <langflow-api-key>
|
||||||
AURASK_LY_SSO_PASSWORD: <ly-sso-password>
|
|
||||||
AURASK_GOOGLE_CLIENT_ID: <google-oauth-client-id>
|
AURASK_GOOGLE_CLIENT_ID: <google-oauth-client-id>
|
||||||
|
|||||||
@ -5,7 +5,6 @@
|
|||||||
## 当前页面能力
|
## 当前页面能力
|
||||||
|
|
||||||
- 未登录时渲染 `/signin` 风格登录页
|
- 未登录时渲染 `/signin` 风格登录页
|
||||||
- 支持 `LY SSO` 登录按钮与本地凭据提交
|
|
||||||
- 支持 Google 登录入口
|
- 支持 Google 登录入口
|
||||||
- 新用户首次登录自动创建独立 workspace
|
- 新用户首次登录自动创建独立 workspace
|
||||||
- 登录后显示:
|
- 登录后显示:
|
||||||
@ -18,7 +17,6 @@
|
|||||||
门户依赖以下 API:
|
门户依赖以下 API:
|
||||||
|
|
||||||
- `GET /auth/config`
|
- `GET /auth/config`
|
||||||
- `POST /auth/ly-sso/login`
|
|
||||||
- `POST /auth/google/login`
|
- `POST /auth/google/login`
|
||||||
- `GET /auth/session`
|
- `GET /auth/session`
|
||||||
- `POST /auth/logout`
|
- `POST /auth/logout`
|
||||||
|
|||||||
@ -8,7 +8,6 @@ const state = {
|
|||||||
sessionToken: window.localStorage.getItem(STORAGE_KEY) || "",
|
sessionToken: window.localStorage.getItem(STORAGE_KEY) || "",
|
||||||
profile: null,
|
profile: null,
|
||||||
activeTab: window.localStorage.getItem(TAB_KEY) || "workflows",
|
activeTab: window.localStorage.getItem(TAB_KEY) || "workflows",
|
||||||
lyFormOpen: false,
|
|
||||||
loading: true,
|
loading: true,
|
||||||
error: "",
|
error: "",
|
||||||
};
|
};
|
||||||
@ -127,31 +126,6 @@ async function bootstrap() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function submitLySso(event) {
|
|
||||||
event.preventDefault();
|
|
||||||
state.error = "";
|
|
||||||
render();
|
|
||||||
const form = new FormData(event.currentTarget);
|
|
||||||
try {
|
|
||||||
const payload = await request("/auth/ly-sso/login", {
|
|
||||||
method: "POST",
|
|
||||||
body: {
|
|
||||||
username: String(form.get("username") || "").trim(),
|
|
||||||
password: String(form.get("password") || ""),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
persistSession(payload.token);
|
|
||||||
state.profile = payload;
|
|
||||||
state.lyFormOpen = false;
|
|
||||||
ensureDashboardRoute();
|
|
||||||
} catch (error) {
|
|
||||||
state.error = error.message || "LY SSO sign-in failed";
|
|
||||||
} finally {
|
|
||||||
render();
|
|
||||||
mountGoogleButton();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function signInWithGoogle(idToken) {
|
async function signInWithGoogle(idToken) {
|
||||||
state.error = "";
|
state.error = "";
|
||||||
render();
|
render();
|
||||||
@ -177,7 +151,6 @@ async function logout() {
|
|||||||
}
|
}
|
||||||
persistSession("");
|
persistSession("");
|
||||||
state.profile = null;
|
state.profile = null;
|
||||||
state.lyFormOpen = false;
|
|
||||||
ensureSigninRoute();
|
ensureSigninRoute();
|
||||||
render();
|
render();
|
||||||
mountGoogleButton();
|
mountGoogleButton();
|
||||||
@ -213,7 +186,6 @@ function renderStatusPills() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function renderSignin() {
|
function renderSignin() {
|
||||||
const lyConfig = state.config?.auth?.ly_sso || {};
|
|
||||||
const googleConfig = state.config?.auth?.google || {};
|
const googleConfig = state.config?.auth?.google || {};
|
||||||
const googleEnabled = Boolean(googleConfig.enabled && googleConfig.client_id);
|
const googleEnabled = Boolean(googleConfig.enabled && googleConfig.client_id);
|
||||||
app.innerHTML = `
|
app.innerHTML = `
|
||||||
@ -231,37 +203,14 @@ function renderSignin() {
|
|||||||
<div class="signin-header">
|
<div class="signin-header">
|
||||||
<p class="section-kicker">Welcome back</p>
|
<p class="section-kicker">Welcome back</p>
|
||||||
<h2>Sign in to Aurask</h2>
|
<h2>Sign in to Aurask</h2>
|
||||||
<p>Use your organization account first, or enable Google one-tap registration for self-serve users.</p>
|
<p>Continue with Google to access your workspace or create a new one on first sign-in.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="signin-actions">
|
${googleEnabled ? '<div id="googleButton" class="google-box"></div>' : '<div class="signin-actions"><button class="auth-btn auth-btn-secondary" type="button" disabled>Continue with Google</button></div>'}
|
||||||
<button id="lyButton" class="auth-btn auth-btn-primary" type="button">Use LY SSO</button>
|
|
||||||
<button id="googleFallbackButton" class="auth-btn auth-btn-secondary" type="button" ${googleEnabled ? "" : "disabled"}>
|
|
||||||
Continue with Google
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div id="googleButton" class="google-box ${googleEnabled ? "" : "is-hidden"}"></div>
|
|
||||||
${
|
${
|
||||||
googleEnabled
|
googleEnabled
|
||||||
? '<p class="signin-tip">Google new-user login provisions a dedicated Aurask workspace on first sign-in.</p>'
|
? '<p class="signin-tip">Google new-user login provisions a dedicated Aurask workspace on first sign-in.</p>'
|
||||||
: '<p class="signin-tip">Set `AURASK_GOOGLE_CLIENT_ID` to enable Google one-tap registration.</p>'
|
: '<p class="signin-tip">Set `AURASK_GOOGLE_CLIENT_ID` to enable Google one-tap registration.</p>'
|
||||||
}
|
}
|
||||||
${
|
|
||||||
state.lyFormOpen
|
|
||||||
? `
|
|
||||||
<form id="lyForm" class="ly-form">
|
|
||||||
<label>
|
|
||||||
Username
|
|
||||||
<input name="username" value="${escapeHtml(lyConfig.username_hint || "ly-xujian1")}" autocomplete="username" />
|
|
||||||
</label>
|
|
||||||
<label>
|
|
||||||
Password
|
|
||||||
<input name="password" type="password" autocomplete="current-password" placeholder="Enter LY SSO password" />
|
|
||||||
</label>
|
|
||||||
<button class="auth-btn auth-btn-primary" type="submit">Sign in with LY SSO</button>
|
|
||||||
</form>
|
|
||||||
`
|
|
||||||
: ""
|
|
||||||
}
|
|
||||||
${state.error ? `<p class="message error">${escapeHtml(state.error)}</p>` : ""}
|
${state.error ? `<p class="message error">${escapeHtml(state.error)}</p>` : ""}
|
||||||
<div class="signin-footer">
|
<div class="signin-footer">
|
||||||
<span>Need a first workspace?</span>
|
<span>Need a first workspace?</span>
|
||||||
@ -270,21 +219,6 @@ function renderSignin() {
|
|||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
document.querySelector("#lyButton")?.addEventListener("click", () => {
|
|
||||||
if (lyConfig.login_url) {
|
|
||||||
window.location.href = lyConfig.login_url;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
state.lyFormOpen = !state.lyFormOpen;
|
|
||||||
render();
|
|
||||||
mountGoogleButton();
|
|
||||||
});
|
|
||||||
|
|
||||||
document.querySelector("#lyForm")?.addEventListener("submit", submitLySso);
|
|
||||||
document.querySelector("#googleFallbackButton")?.addEventListener("click", () => {
|
|
||||||
document.querySelector("#googleButton")?.scrollIntoView({ behavior: "smooth", block: "center" });
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderDashboard() {
|
function renderDashboard() {
|
||||||
|
|||||||
@ -15,7 +15,6 @@ from aurask.app import create_app
|
|||||||
class AuthSessionTests(unittest.TestCase):
|
class AuthSessionTests(unittest.TestCase):
|
||||||
def setUp(self) -> None:
|
def setUp(self) -> None:
|
||||||
self.env_keys = [
|
self.env_keys = [
|
||||||
"AURASK_LY_SSO_PASSWORD",
|
|
||||||
"AURASK_GOOGLE_ENABLED",
|
"AURASK_GOOGLE_ENABLED",
|
||||||
"AURASK_GOOGLE_ALLOW_UNVERIFIED_ID_TOKEN",
|
"AURASK_GOOGLE_ALLOW_UNVERIFIED_ID_TOKEN",
|
||||||
"AURASK_GOOGLE_CLIENT_ID",
|
"AURASK_GOOGLE_CLIENT_ID",
|
||||||
@ -29,18 +28,6 @@ class AuthSessionTests(unittest.TestCase):
|
|||||||
else:
|
else:
|
||||||
os.environ[key] = value
|
os.environ[key] = value
|
||||||
|
|
||||||
def test_ly_sso_login_creates_session_and_workspace(self) -> None:
|
|
||||||
os.environ["AURASK_LY_SSO_PASSWORD"] = "local-secret"
|
|
||||||
app = create_app(None, reset=True)
|
|
||||||
|
|
||||||
payload = app.login_with_ly_sso(username="ly-xujian1", password="local-secret")
|
|
||||||
context = app.auth.authenticate(f"Bearer {payload['token']}")
|
|
||||||
|
|
||||||
self.assertEqual(context["token_type"], "session")
|
|
||||||
self.assertEqual(payload["workspace"]["tenant_id"], payload["tenant"]["id"])
|
|
||||||
self.assertEqual(payload["quota"]["plan_code"], "free_trial")
|
|
||||||
self.assertEqual(len(app.list_workspaces(payload["tenant"]["id"])), 1)
|
|
||||||
|
|
||||||
def test_google_first_login_reuses_workspace_after_registration(self) -> None:
|
def test_google_first_login_reuses_workspace_after_registration(self) -> None:
|
||||||
os.environ["AURASK_GOOGLE_ENABLED"] = "true"
|
os.environ["AURASK_GOOGLE_ENABLED"] = "true"
|
||||||
os.environ["AURASK_GOOGLE_ALLOW_UNVERIFIED_ID_TOKEN"] = "true"
|
os.environ["AURASK_GOOGLE_ALLOW_UNVERIFIED_ID_TOKEN"] = "true"
|
||||||
@ -62,6 +49,7 @@ class AuthSessionTests(unittest.TestCase):
|
|||||||
self.assertFalse(second_login["is_new_user"])
|
self.assertFalse(second_login["is_new_user"])
|
||||||
self.assertEqual(first_login["workspace"]["id"], second_login["workspace"]["id"])
|
self.assertEqual(first_login["workspace"]["id"], second_login["workspace"]["id"])
|
||||||
self.assertEqual(len(app.list_workspaces(first_login["tenant"]["id"])), 1)
|
self.assertEqual(len(app.list_workspaces(first_login["tenant"]["id"])), 1)
|
||||||
|
self.assertEqual(app.auth.authenticate(f"Bearer {first_login['token']}")["token_type"], "session")
|
||||||
|
|
||||||
def _fake_google_token(self, claims: dict) -> str:
|
def _fake_google_token(self, claims: dict) -> str:
|
||||||
header = self._base64url({"alg": "none", "typ": "JWT"})
|
header = self._base64url({"alg": "none", "typ": "JWT"})
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user