feat: 企业微信OAuth静默登录
- 新增 GET /api/wecom/oauth-url 和 /api/wecom/oauth-callback - OAuth回调返回HTML页面直接写localStorage(避坑企微webview 307重定向不可靠) - 菜单URL改为OAuth静默授权链接(snsapi_base + agentid) - redirect目标编码到state参数中(避坑redirect_uri不允许自定义query) - wecom_userid大小写不敏感匹配 - 前端路由守卫处理 ?token= 自动登录(fallback) - Login.vue企微环境检测自动跳OAuth - setup-menu同步更新为OAuth链接 Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -80,6 +80,28 @@ const router = createRouter({
|
||||
|
||||
router.beforeEach((to, _from, next) => {
|
||||
const auth = useAuthStore()
|
||||
|
||||
// Handle WeChat Work OAuth silent login callback: ?token=JWT
|
||||
const tokenParam = to.query.token as string
|
||||
if (tokenParam) {
|
||||
// Save token to auth store (the JWT contains user_id, name, role, theme)
|
||||
try {
|
||||
const payload = JSON.parse(atob(tokenParam.split('.')[1]))
|
||||
auth.saveLogin({
|
||||
access_token: tokenParam,
|
||||
user_id: payload.user_id,
|
||||
name: payload.name,
|
||||
role: payload.role,
|
||||
theme: payload.theme,
|
||||
})
|
||||
} catch (_) { /* invalid token, ignore */ }
|
||||
// Remove token from URL
|
||||
const cleanQuery = { ...to.query }
|
||||
delete cleanQuery.token
|
||||
next({ path: to.path, query: cleanQuery, replace: true })
|
||||
return
|
||||
}
|
||||
|
||||
if (to.meta.public) {
|
||||
next()
|
||||
return
|
||||
|
||||
@@ -9,6 +9,11 @@ const route = useRoute()
|
||||
const auth = useAuthStore()
|
||||
const loading = ref(false)
|
||||
|
||||
function isWecom(): boolean {
|
||||
const ua = navigator.userAgent || ''
|
||||
return /wxwork/i.test(ua)
|
||||
}
|
||||
|
||||
function isMobileDevice(): boolean {
|
||||
const ua = navigator.userAgent || ''
|
||||
return /Android|iPhone|iPad|iPod|webOS/i.test(ua) || window.innerWidth < 768
|
||||
@@ -80,6 +85,16 @@ onMounted(async () => {
|
||||
return
|
||||
}
|
||||
|
||||
// ── WeChat Work silent login: redirect to OAuth (no user interaction needed) ──
|
||||
if (isWecom()) {
|
||||
const targetPath = (route.query.redirect as string) || '/m'
|
||||
const endpoint = import.meta.env.VITE_CASDOOR_ENDPOINT || ''
|
||||
// In production, the backend builds the OAuth URL; use the API
|
||||
const apiBase = window.location.origin
|
||||
window.location.href = `${apiBase}/api/wecom/oauth-url?redirect=${encodeURIComponent(targetPath)}`
|
||||
return
|
||||
}
|
||||
|
||||
// ── Auto-redirect to Casdoor (no button needed) ──
|
||||
loading.value = true
|
||||
goCasdoorLogin()
|
||||
|
||||
Reference in New Issue
Block a user