授权服务(@uniboot/auth) ​

与框架无关的 OAuth 2.0 登录状态机与路由权限守卫,将 登录 一文中的授权中心跳转、换票、路由拦截沉淀为可复用能力。账号资料、忘记密码等由 @uniboot/admin 负责。

能力导出说明
OAuth 状态机createOAuthAuthServicestate 防伪、code 换票、401 刷新、解析 expiresIn
路由权限守卫setupAuthPermissionGuard未登录重定向、OAuth 回调、清 query、动态路由、白名单
登录 APIcreateAuthApi本地登录 / 登出(可拆 login / logout 客户端)
页面组件AuthLoginPage本地登录表单(不走 SSO 整页跳转时用)

类型以 XxxLike 描述宿主 router / user,不直接依赖具体版本的 vue-router。peerDependencies:vue、vue-i18n、uniboot-ui。dependencies:@uniboot/request。

Auth 模板接入 ​

三服务地址均需配置(与 用户服务 一致):

环境变量含义鉴权侧用法
APP_PUBLIC_API_URL业务系统默认 request;经网关聚合 OAuth 时,换票 / 刷新也绑此客户端
APP_PUBLIC_AUTH_SERVICE_URL授权服务Bundle → authHttp(登出、直连授权能力)
APP_PUBLIC_ADMIN_SERVICE_URL用户服务Bundle → adminHttp(见 admin 文档)
APP_PUBLIC_CLIENT_IDOAuth 客户端 IDcreateOAuthAuthService.clientId(必填,未配置会抛错)

模板职责拆分:

文件职责
src/utils/request.ts创建客户端;bindOAuthHttp(request) 尽早绑定
src/setup/auth-runtime.tsHTTP 公共配置、OAuth、setupPermissionGuard、401 刷新
src/router/guard/permission.ts调用 setupPermissionGuard
src/install/plugins/uniboot-admin.tssetupUnibootAdmin(见 用户服务)
ts
// src/utils/request.ts(节选)
const request = createHttpClient({ baseURL, ...httpCommonOptions })
bindOAuthHttp(request) // 首屏并行 401 前即可刷新

export const { adminApi, userApi, roleApi, authHttp, adminHttp } =
  createUnibootAdminHttpBundle({
    authServiceUrl,
    adminServiceUrl,
    http: httpCommonOptions, // 与业务 request 共用同一 refreshToken 函数引用
  })
ts
// src/setup/auth-runtime.ts(节选)
oauthAuthService = createOAuthAuthService({
  authServiceUrl: config.authServiceUrl,
  appBase: config.appBase,
  redirectUri: config.redirectUri,
  clientId: config.clientId, // 必填
  http, // 须能打到 /oauth/token 与 /oauth/refresh_token(网关场景 = 业务 request)
  tokenPath: '/oauth/token',
  refreshTokenPath: '/oauth/refresh_token',
  // authorizePath: '/oauth/authorize', // 标准授权端点;默认 '/login'
  // getAuthorizeLang: () => (locale === 'zh-CN' ? 'zh_CN' : 'en_US'),
})

setupAuthPermissionGuard({
  router,
  oauth: oauthAuthService,
  useAuthServiceLogin: Boolean(config.authServiceUrl?.trim()),
  user: createAuthPermissionUserBridge(),
  // 可选:本地 token 已过期时仍允许用 URL 中的 code 换票
  // isAccessTokenValid: () => Date.now() < expiresTimestamp,
  // 可选:无菜单但需改初始密码时不要踢 403
  // resolveEmptyRoutesFallback: () => INDEX_ROUTE_NAME,
  // loginPath / whiteList / dynamicRoutes / progress / feedback ...
})

refreshHttpAccessToken(HTTP 401 拦截器)与守卫共用同一个 oauthAuthService。多个 createHttpClient(业务 / auth / admin)应传入同一个 refreshToken 函数引用,由 @uniboot/request 跨实例合并并发刷新。须在 createRouter 之后、app.use(router) 之前注册守卫。

createOAuthAuthService ​

把「统一授权中心登录」拆成纯函数,中间状态默认写入 sessionStorage(可换 OAuthStorageLike)。

参数 ​

名称说明类型默认值
authServiceUrl授权中心地址(拼授权跳转 URL)string—
appBase应用基础路径,用于推导 redirectUristring—
redirectUri回调地址;未传按 ${origin}${appBase} 推导string按 appBase 推导
clientIdOAuth 客户端 ID(必填,空则抛错)string—
scope授权范围string'user_info'
http换票 / 刷新用的 HTTP 客户端object—
tokenPath换票路径string'/oauth/token'
refreshTokenPath刷新路径string'/oauth/refresh_token'
authorizePath授权入口路径string'/login'
state防伪校验值stringOAUTH_FIXED_STATE('STATE')
allowFixedStateFallbacksession 无 state 时是否回退到固定 statebooleantrue
getAuthorizeLang追加授权 URL 的 langfunction—
storage中间状态存储objectsessionStorage
getOrigin推导 redirectUri 时取源function() => location.origin

http 绑哪个客户端?

  • 经业务网关转发 /oauth/token、/oauth/refresh_token:传业务 request(Auth 模板默认)。
  • 直连授权服务:传 Bundle 的 authHttp(baseURL = APP_PUBLIC_AUTH_SERVICE_URL)。
  • 登出一般走 authHttp(见 createAuthApi.logoutHttp),与换票客户端可以不同。

返回值 ​

名称说明类型
buildAuthorizeHref生成授权中心 URL,并写入 statefunction
rememberReturnPath记忆登录前地址function
takeAndClearReturnPath取出并清除返回地址function
getLoginState读取已写入的 state(可回退固定值)function
exchangeAuthorizationCodecode 换令牌对(含可选 expiresIn)function
refreshAccessTokenrefresh token 换新令牌对function
clearLoginSessionMarkers清理 state / 返回地址function

OAuthTokenPair:{ accessToken, refreshToken?, expiresIn? }(expiresIn 为秒)。

另导出工具:stripOAuthCallbackFromBrowserUrl、isLikelyOAuthAuthorizeCallback、omitOAuthCallbackQuery、OAUTH_CALLBACK_QUERY_KEYS。

实现细节

  • 换票 / 刷新统一:data 传参 + withToken: false + isTransformResponse: false + errorTip: false,避免默认解包失败或全局 tip 与守卫双重提示。
  • 未显式传 state 时用固定值 'STATE';allowFixedStateFallback 默认开启,兼容换票后清 session、用户浏览器后退再登录。
  • 令牌解析兼容 access_token / accessToken、expires_in / expiresIn、顶层或嵌套在 result / data。

setupAuthPermissionGuard ​

组装 router.beforeEach:访问拦截 → 授权中心 → 回调换票 → 动态路由。

参数 ​

名称说明类型默认值
router满足 AuthPermissionRouterLike 即可object—
usertoken / 用户信息 / 路由表适配器object—
dynamicRoutes首页路由、路由名、首个可用路由查找object—
loginPath登录页路径string—
indexPath首页路径string—
error403Path无权限页路径string—
whiteList免登录白名单array—
titledocument.title 回退string / function—
useAuthServiceLogin是否整页跳转授权中心booleanfalse
oauthcreateOAuthAuthService 实例object—
isAccessTokenValid本地 token 是否仍可用;返回 false 时即使有字符串也会走换票function有 token 即视为可用
resolveEmptyRoutesFallback无可用菜单时的兜底路由名(如强制改密)function—
afterUserLoaded拉完用户信息后的可选重定向function—
tabs动态路由挂载后设置多标签路由名object—
progress进度条钩子object—
feedback错误提示object—
redirectTo跳转授权中心functionwindow.location.href
isExternal外链判断,动态挂载时跳过function匹配 http(s): / mailto: / tel:

AuthPermissionUserLike 额外可选:setRefreshToken、setExpiresIn(expiresInSeconds)。

执行流程 ​

  1. OAuth 回调:URL 有 code 且本地无可用 token(isAccessTokenValid)→ 校验 error / state → 换票写 token / refresh / expiresIn → 清地址栏 OAuth query → takeAndClearReturnPath 跳回。
  2. 已登录仍带 OAuth query:code+state 同时存在时 Router replace 清掉,避免敏感参数残留。
  3. 白名单:放行;若目标是 loginPath 且启用了 useAuthServiceLogin,记忆 redirect 后跳转授权中心。
  4. 已登录:有用户信息则放行;否则 loadUserInfo → 可选 afterUserLoaded → 挂动态路由;无菜单时先问 resolveEmptyRoutesFallback,仍无则清登录态去 403。
  5. 未登录且未启用 OAuth:跳转本地登录页并带 redirect。
  6. 未登录且启用 OAuth:记忆地址后整页跳转授权中心,next(false)。

createAuthApi ​

本地表单登录或 SSO 登出。注意默认路径语义不同:login 偏业务网关,logout 偏授权服务,必要时拆两个 HTTP 客户端。

参数 ​

名称说明类型默认值
http本地密码登录所用 HTTPobject—
logoutHttp登出所用 HTTP;默认与 http 相同objecthttp
paths部分覆盖 defaultAuthApiPathsobjectlogin: '/auth/login'、logout: '/oauth/logout'
logoutMethod登出方法string'get'
getToken登出时手动带 Bearer(配合内部 withToken: false)function—

方法 ​

名称说明类型
loginwithToken/errorTip/transform 均关闭,便于宿主自行解包function
logout默认 GET;不过期刷新;可带手动 Authorizationfunction
ts
import { createAuthApi } from '@uniboot/auth'
import { authHttp } from '@/utils/request'
import { getToken } from '@/utils/auth'

const authApi = createAuthApi({
  http: authHttp, // 若本地登录走网关,这里应传业务 request
  logoutHttp: authHttp,
  getToken,
})

export function logout() {
  return authApi.logout()
}

useLoginAccount({ api }) 把 LoginPage 表单值映射为登录请求(trim 用户名并透传验证码)。

AuthLoginPage ​

不启用 useAuthServiceLogin、在前端渲染登录表单时使用。内部已接 useLoginAccount;写 token、跳转仍由宿主在 onFinish 中完成。Auth 模板默认 SSO,不引用该组件。

属性 ​

名称说明类型默认值
apicreateAuthApi 实例object—
logoLogo URLstring—
illustration插画 URLstring—
onFinish登录成功回调;result 为 api.login 返回值function—
showCaptcha是否展示验证码booleanfalse
getCaptcha获取验证码function—
initialValues初始表单值object—

事件 / 插槽 ​

名称说明
language-change语言切换
#actions / #footer表单下方 / 左侧底部

i18n ​

mergeUnibootAuthLocales(i18n) 合并 authLocaleZhCn / authLocaleEn 到 zh_CN/zh-CN、en_US/en-US。命名空间为 unibootAuth.login.*。Auth 模板在 uniboot-admin 安装插件里与 admin 文案一并处理;账号域更多文案见 @uniboot/admin。