simplify oidc callback result payload
This commit is contained in:
+13
-11
@@ -34,9 +34,9 @@
|
||||
- 若用户不存在,则自动创建本地账号和默认租户;
|
||||
- 最终签发 WeKnora 自己的本地 JWT(`token` / `refresh_token`)。
|
||||
4. 后端不会直接把登录结果放在 query string 中,而是:
|
||||
- 将结果 JSON 序列化后再做 base64url 编码;
|
||||
- 将登录结果 JSON( `success`、`token`、`refresh_token` 等字段)序列化后再做 base64url 编码;
|
||||
- 以 `#oidc_result=...` 的形式重定向回前端;
|
||||
- 前端在 `App.vue` 中统一解析 hash,完成登录态持久化。
|
||||
- 前端在 `App.vue` 中统一解析 hash,再调用 `/api/v1/auth/me` 补全用户和租户信息。
|
||||
|
||||
因此,**OIDC Provider 的 token 只用于后端换取用户身份,本项目真正的业务访问凭证仍然是 WeKnora 自己签发的 JWT**。
|
||||
|
||||
@@ -93,7 +93,9 @@ sequenceDiagram
|
||||
BE-->>FE: 302 到 /#oidc_result=...
|
||||
|
||||
FE->>FE: App.vue 解析 hash
|
||||
FE->>FE: 写入 authStore/token/tenant
|
||||
FE->>BE: GET /api/v1/auth/me
|
||||
BE-->>FE: { user, tenant }
|
||||
FE->>FE: 写入 authStore/token/user/tenant
|
||||
FE-->>U: 跳转 /platform/knowledge-bases
|
||||
```
|
||||
|
||||
@@ -120,7 +122,7 @@ flowchart TD
|
||||
M -- 是 --> O[使用现有用户]
|
||||
N --> P[签发 WeKnora JWT]
|
||||
O --> P
|
||||
P --> Q[编码为 oidc_result]
|
||||
P --> Q[编码最小必要登录结果为 oidc_result]
|
||||
Q --> R[302 重定向到前端首页 hash]
|
||||
```
|
||||
|
||||
@@ -422,12 +424,12 @@ GenerateTokens(ctx, user)
|
||||
|
||||
并写入本地 `auth_tokens` 存储(通过 `tokenRepo.CreateToken`)。
|
||||
|
||||
最终后端还会查询当前用户所属租户,并返回:
|
||||
最终后端会返回 OIDC 回调载荷,其中包含:
|
||||
|
||||
- `user`
|
||||
- `tenant`
|
||||
- `token`
|
||||
- `refresh_token`
|
||||
- `success`
|
||||
- `message`
|
||||
- `is_new_user`
|
||||
|
||||
这一步意味着:
|
||||
@@ -502,10 +504,10 @@ window.location.hash
|
||||
|
||||
1. base64url 解码并反序列化;
|
||||
2. 如果 `response.success=true`:
|
||||
- 写入 `authStore.setUser(...)`
|
||||
- 写入 `authStore.setToken(...)`
|
||||
- 写入 `authStore.setRefreshToken(...)`
|
||||
- 写入 `authStore.setTenant(...)`
|
||||
- 先写入 `authStore.setToken(...)`
|
||||
- 再写入 `authStore.setRefreshToken(...)`
|
||||
- 随后调用 `/api/v1/auth/me`
|
||||
- 用 `/auth/me` 返回的 `user` / `tenant` 执行 `authStore.setUser(...)` 与 `authStore.setTenant(...)`
|
||||
3. 最终跳转到:
|
||||
|
||||
```text
|
||||
|
||||
+44
-24
@@ -5,6 +5,7 @@ import { useI18n } from 'vue-i18n'
|
||||
import { MessagePlugin } from 'tdesign-vue-next'
|
||||
import ManualKnowledgeEditor from '@/components/manual-knowledge-editor.vue'
|
||||
import { useAuthStore } from '@/stores/auth'
|
||||
import { getCurrentUser } from '@/api/auth'
|
||||
|
||||
// TDesign locale configs
|
||||
import enUSConfig from 'tdesign-vue-next/esm/locale/en_US'
|
||||
@@ -37,32 +38,50 @@ const clearOIDCCallbackState = (path = '/') => {
|
||||
window.history.replaceState({}, document.title, path)
|
||||
}
|
||||
|
||||
const persistOIDCLoginResponse = async (response: any) => {
|
||||
if (response.user && response.tenant && response.token) {
|
||||
authStore.setUser({
|
||||
id: response.user.id || '',
|
||||
username: response.user.username || '',
|
||||
email: response.user.email || '',
|
||||
avatar: response.user.avatar,
|
||||
tenant_id: String(response.tenant.id) || '',
|
||||
can_access_all_tenants: response.user.can_access_all_tenants || false,
|
||||
created_at: response.user.created_at || new Date().toISOString(),
|
||||
updated_at: response.user.updated_at || new Date().toISOString()
|
||||
})
|
||||
authStore.setToken(response.token)
|
||||
if (response.refresh_token) {
|
||||
authStore.setRefreshToken(response.refresh_token)
|
||||
}
|
||||
authStore.setTenant({
|
||||
id: String(response.tenant.id) || '',
|
||||
name: response.tenant.name || '',
|
||||
api_key: response.tenant.api_key || '',
|
||||
owner_id: response.user.id || '',
|
||||
created_at: response.tenant.created_at || new Date().toISOString(),
|
||||
updated_at: response.tenant.updated_at || new Date().toISOString()
|
||||
})
|
||||
const syncOIDCUserContext = async () => {
|
||||
const currentUserResponse = await getCurrentUser()
|
||||
if (!currentUserResponse.success || !currentUserResponse.data?.user || !currentUserResponse.data?.tenant) {
|
||||
throw new Error(currentUserResponse.message || 'Failed to get user information')
|
||||
}
|
||||
|
||||
const { user, tenant } = currentUserResponse.data
|
||||
authStore.setUser({
|
||||
id: user.id || '',
|
||||
username: user.username || '',
|
||||
email: user.email || '',
|
||||
avatar: user.avatar,
|
||||
tenant_id: String(user.tenant_id || tenant.id || ''),
|
||||
can_access_all_tenants: user.can_access_all_tenants || false,
|
||||
created_at: user.created_at || new Date().toISOString(),
|
||||
updated_at: user.updated_at || new Date().toISOString()
|
||||
})
|
||||
authStore.setTenant({
|
||||
id: String(tenant.id) || '',
|
||||
name: tenant.name || '',
|
||||
api_key: tenant.api_key || '',
|
||||
owner_id: tenant.owner_id || user.id || '',
|
||||
description: tenant.description,
|
||||
status: tenant.status,
|
||||
business: tenant.business,
|
||||
storage_quota: tenant.storage_quota,
|
||||
storage_used: tenant.storage_used,
|
||||
created_at: tenant.created_at || new Date().toISOString(),
|
||||
updated_at: tenant.updated_at || new Date().toISOString()
|
||||
})
|
||||
}
|
||||
|
||||
const persistOIDCLoginResponse = async (response: any) => {
|
||||
if (!response.token) {
|
||||
throw new Error(response.message || 'OIDC login failed')
|
||||
}
|
||||
|
||||
authStore.setToken(response.token)
|
||||
if (response.refresh_token) {
|
||||
authStore.setRefreshToken(response.refresh_token)
|
||||
}
|
||||
|
||||
await syncOIDCUserContext()
|
||||
|
||||
await nextTick()
|
||||
router.replace('/platform/knowledge-bases')
|
||||
}
|
||||
@@ -106,6 +125,7 @@ const handleGlobalOIDCCallback = async () => {
|
||||
MessagePlugin.error(response.message || 'OIDC login failed')
|
||||
} catch (error: any) {
|
||||
console.error('Global OIDC callback handling failed:', error)
|
||||
authStore.logout()
|
||||
clearOIDCCallbackState('/login')
|
||||
await router.replace('/login')
|
||||
MessagePlugin.error(error.message || 'OIDC login failed')
|
||||
|
||||
@@ -306,16 +306,9 @@ func (s *userService) LoginWithOIDC(ctx context.Context, code, redirectURI strin
|
||||
return nil, fmt.Errorf("failed to generate local tokens: %w", err)
|
||||
}
|
||||
|
||||
tenant, err := s.tenantService.GetTenantByID(ctx, user.TenantID)
|
||||
if err != nil {
|
||||
logger.Warnf(ctx, "Failed to get tenant info after OIDC login: %v", err)
|
||||
}
|
||||
|
||||
return &types.OIDCCallbackResponse{
|
||||
Success: true,
|
||||
Message: "Login successful",
|
||||
User: user,
|
||||
Tenant: tenant,
|
||||
Message: "登录成功",
|
||||
Token: accessToken,
|
||||
RefreshToken: refreshToken,
|
||||
IsNewUser: isNewUser,
|
||||
|
||||
Reference in New Issue
Block a user