认证提供者
认证提供者是 DVHA 中负责处理用户身份验证和授权的核心组件。它提供了一个统一的接口来处理登录、登出、注册、密码重置等认证流程,支持多种认证方式和多管理端独立认证。
什么是认证提供者?
认证提供者是一个实现了特定接口的对象,它定义了如何处理用户的认证流程。DVHA 通过认证提供者来执行所有的认证操作,包括:
- 用户登录 (login)
- 用户登出 (logout)
- 认证检查 (check)
- 用户注册 (register)
- 忘记密码 (forgotPassword)
- 重置密码 (updatePassword)
- 错误处理 (onError)
- 权限验证 (can)
简单认证提供者
DVHA 内置了 simpleAuthProvider
,适用于开发和测试:
typescript
import { simpleAuthProvider } from '@duxweb/dvha-core'
const config: IConfig = {
authProvider: simpleAuthProvider(),
// ... 其他配置
}
// 或者使用自定义配置
const authProvider = simpleAuthProvider({
apiPath: {
login: '/login', // 默认登录接口路径
check: '/check', // 默认认证检查路径
logout: '/logout', // 默认登出接口路径
register: '/register', // 默认注册接口路径
forgotPassword: '/forgot-password', // 默认忘记密码路径
updatePassword: '/update-password' // 默认重置密码路径
},
routePath: {
login: '/login', // 登录页面路径
index: '/' // 登录成功后跳转路径
},
dataProviderName: 'default' // 指定使用的数据提供者名称
})
简单认证提供者配置选项
typescript
interface ISimpleAuthProviderProps {
apiPath?: {
login?: string // 登录接口路径
check?: string // 认证检查路径
logout?: string // 登出接口路径
register?: string // 注册接口路径
forgotPassword?: string // 忘记密码路径
updatePassword?: string // 重置密码路径
}
routePath?: {
login?: string // 登录页面路径
index?: string // 登录成功后跳转路径
}
dataProviderName?: string // 数据提供者名称
}
TIP
simpleAuthProvider
是一个基于 Axios 和标准认证流程的实现,支持基本的登录、登出和认证检查功能,适合快速开始和原型开发。它会自动处理 401 错误并触发登出,支持权限数组和对象两种格式。
认证提供者接口
typescript
interface IAuthProvider {
// 用户登录
login: (params: any, manage: IManageHook) => Promise<IAuthLoginResponse>
// 用户登出
logout: (params?: any, manage?: IManageHook) => Promise<IAuthLogoutResponse>
// 用户注册(可选)
register?: (params: any, manage?: IManageHook) => Promise<IAuthLoginResponse>
// 忘记密码(可选)
forgotPassword?: (params: any, manage?: IManageHook) => Promise<IAuthActionResponse>
// 重置密码(可选)
updatePassword?: (params: any, manage?: IManageHook) => Promise<IAuthActionResponse>
// 认证检查(可选)
check?: (params?: any, manage?: IManageHook, auth?: IUserState) => Promise<IAuthCheckResponse>
// 权限检查(可选)
can?: (name: string, params?: any, manage?: IManageHook, auth?: IUserState) => boolean
// 错误处理
onError: (error?: IDataProviderError) => Promise<IAuthErrorResponse>
}
接口变更
在最新版本中:
check
方法现在接受auth
参数,可以基于当前用户状态进行认证检查register
、forgotPassword
、updatePassword
和can
方法都是可选的- 如果不需要某些功能,可以不实现对应的方法
参数说明
通用参数
每个认证提供者方法都接收以下参数:
- params: 请求参数对象,包含具体的操作数据
- manage: 当前管理端实例,提供 API URL 构建等功能
- auth: (仅 check 和 can 方法)当前用户认证状态
登录参数
typescript
// 登录参数示例
interface LoginParams {
username: string // 用户名
password: string // 密码
captcha?: string // 验证码(可选)
rememberMe?: boolean // 记住登录状态(可选)
[key: string]: any // 其他自定义字段
}
注册参数
typescript
// 注册参数示例
interface RegisterParams {
username: string // 用户名
email: string // 邮箱
password: string // 密码
confirmPassword: string // 确认密码
[key: string]: any // 其他自定义字段
}
密码重置参数
typescript
// 忘记密码参数示例
interface ForgotPasswordParams {
email: string // 邮箱地址
}
// 重置密码参数示例
interface UpdatePasswordParams {
token: string // 重置令牌
password: string // 新密码
confirmPassword: string // 确认新密码
}
返回格式
基础响应格式
typescript
interface IAuthActionResponse {
success: boolean // 操作是否成功
message?: string // 响应消息
redirectTo?: string // 重定向地址
[key: string]: unknown // 其他自定义字段
}
登录响应格式
typescript
interface IAuthLoginResponse extends IAuthActionResponse {
data?: IUserState // 用户状态数据
}
检查响应格式
typescript
interface IAuthCheckResponse extends IAuthActionResponse {
data?: IUserState // 用户状态数据
logout?: boolean // 是否需要登出
}
登出响应格式
typescript
interface IAuthLogoutResponse extends IAuthActionResponse {
logout?: boolean // 是否需要清除状态
}
错误响应格式
typescript
interface IAuthErrorResponse {
logout?: boolean // 是否需要登出
redirectTo?: string // 重定向地址
error?: IDataProviderError // 统一错误信息
}
用户状态格式
typescript
interface IUserState {
token?: string // 认证令牌
id?: number // 用户 ID
info?: Record<string, any> // 用户信息
permission?: any // 用户权限(数组或对象格式)
[key: string]: any // 其他自定义字段
}
响应示例
登录成功响应
json
{
"success": true,
"message": "登录成功",
"redirectTo": "/admin",
"data": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"id": 1,
"permission": ["user.read", "user.write"],
"info": {
"name": "John Doe",
"email": "john@example.com",
"avatar": "https://example.com/avatar.jpg"
}
}
}
登录失败响应
json
{
"success": false,
"message": "用户名或密码错误"
}
认证检查成功响应
json
{
"success": true,
"message": "认证有效",
"logout": false,
"data": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"id": 1,
"info": {
"name": "John Doe",
"email": "john@example.com"
}
}
}
认证检查失败响应
json
{
"success": false,
"message": "认证已过期",
"logout": true,
"redirectTo": "/login"
}
登出响应
json
{
"success": true,
"message": "登出成功",
"redirectTo": "/login"
}
配置认证提供者
基本配置
typescript
import type { IConfig } from '@duxweb/dvha-core'
import { simpleAuthProvider } from '@duxweb/dvha-core'
const config: IConfig = {
manages: [
{
name: 'admin',
title: '管理后台',
routePrefix: '/admin',
// ... 其他配置
}
],
authProvider: simpleAuthProvider(), // 使用简单认证提供者
}
自定义认证提供者
typescript
import type { IAuthProvider } from '@duxweb/dvha-core'
const customAuthProvider: IAuthProvider = {
login: async (params, manage) => {
// 您的登录逻辑
// 使用 manage.getApiUrl('/login') 构建登录 URL
return {
success: true,
message: '登录成功',
redirectTo: '/',
data: {
token: 'your-token',
id: 1,
info: { /* 用户信息 */ }
}
}
},
check: async (params, manage, auth) => {
// 您的认证检查逻辑
// 可以使用当前用户状态 auth 进行检查
return {
success: true,
logout: false,
data: { /* 用户状态 */ }
}
},
logout: async (params, manage) => {
// 您的登出逻辑
return {
success: true,
redirectTo: '/login'
}
},
// 可选:用户注册功能
register: async (params, manage) => {
// 您的注册逻辑
return {
success: true,
message: '注册成功',
redirectTo: '/',
data: {
token: 'new-user-token',
id: 2,
info: { /* 新用户信息 */ }
}
}
},
// 可选:忘记密码功能
forgotPassword: async (params, manage) => {
// 您的忘记密码逻辑
return {
success: true,
message: '重置邮件已发送',
redirectTo: '/login'
}
},
// 可选:重置密码功能
updatePassword: async (params, manage) => {
// 您的重置密码逻辑
return {
success: true,
message: '密码重置成功',
redirectTo: '/login'
}
},
// 可选:权限检查功能
can: (name, params, manage, auth) => {
// 您的权限检查逻辑
if (!auth?.permission) {
return true // 如果没有权限配置,默认允许访问
}
// 数组形式的权限检查
if (Array.isArray(auth.permission)) {
return auth.permission.includes(name)
}
// 对象形式的权限检查
if (typeof auth.permission === 'object') {
return auth.permission[name] !== false
}
return true
},
onError: async (error) => {
// 您的错误处理逻辑
if (error?.status === 401) {
return {
logout: true,
redirectTo: '/login',
error
}
}
return { logout: false, error }
}
}
const config: IConfig = {
authProvider: customAuthProvider,
// ... 其他配置
}
最小化认证提供者
如果只需要基本的登录、登出和认证检查功能:
typescript
const minimalAuthProvider: IAuthProvider = {
login: async (params, manage) => {
// 实现登录逻辑
return {
success: true,
data: { token: 'user-token', id: 1 }
}
},
logout: async (params, manage) => {
// 实现登出逻辑
return {
success: true,
redirectTo: '/login'
}
},
onError: async (error) => {
// 实现错误处理逻辑
return {
logout: error?.status === 401,
redirectTo: error?.status === 401 ? '/login' : undefined,
error
}
}
// 注意:check、register、forgotPassword、updatePassword 和 can 方法是可选的
// 如果不需要这些功能,可以不实现
}
多管理端认证提供者
不同的管理端可以使用不同的认证提供者:
typescript
const config: IConfig = {
manages: [
{
name: 'admin',
authProvider: simpleAuthProvider({
apiPath: {
login: '/admin/login',
check: '/admin/check'
},
routePath: {
login: '/admin/login',
index: '/admin'
}
}), // 管理端专用
// ... 其他配置
},
{
name: 'merchant',
authProvider: simpleAuthProvider({
apiPath: {
login: '/merchant/login',
check: '/merchant/check'
},
routePath: {
login: '/merchant/login',
index: '/merchant'
}
}), // 商户端专用
// ... 其他配置
}
],
authProvider: simpleAuthProvider(), // 全局后备
}
URL 构建
在认证提供者中,使用 manage.getApiUrl()
方法构建完整的 API URL:
typescript
// 登录接口
const loginUrl = manage.getApiUrl('/login', 'default')
// 结果: https://api.example.com/admin/login
// 认证检查接口
const checkUrl = manage.getApiUrl('/check', 'default')
// 结果: https://api.example.com/admin/check
路由守卫
DVHA 自动为需要认证的路由添加守卫,通过 meta.authorization
控制:
typescript
const routes = [
{
name: 'admin.login',
path: 'login',
component: () => import('./pages/login.vue'),
meta: {
authorization: false, // 不需要认证
}
},
{
name: 'admin.dashboard',
path: 'dashboard',
component: () => import('./pages/dashboard.vue'),
// meta.authorization 默认为 true,需要认证
}
]
错误处理
onError
方法用于处理全局的认证错误:
typescript
onError: async (error?: IDataProviderError) => {
// 401 未授权 - 需要重新登录
if (error?.status === 401) {
return {
logout: true,
redirectTo: '/login',
error
}
}
// 403 权限不足 - 可选择是否登出
if (error?.status === 403) {
return {
logout: false, // 不登出,显示权限不足提示
error
}
}
// 其他错误
return {
logout: false,
error
}
}
安全建议
Token 管理
- 建议将 token 存储在 httpOnly cookie 中以提高安全性
- 实现 token 自动刷新机制
- 设置合理的 token 过期时间
认证检查
- 在应用启动时执行认证检查
- 定期检查 token 有效性
- 自动判断过期时间并返回新的 Token
- 在 API 请求失败时自动处理认证错误
权限检查
DVHA 支持基于权限的访问控制,通过认证提供者的 can
方法实现权限检查。
权限检查方法
typescript
can?: (name: string, params?: any, manage?: IManageHook, auth?: IUserState) => boolean
参数说明:
name
: 权限名称或路由名称params
: 可选的权限参数manage
: 当前管理端实例auth
: 当前用户认证信息
权限数据格式
权限数据可以是数组或对象格式:
json
// 数组格式 - 简单权限列表
{
"permission": ["user.read", "user.write", "post.manage"]
}
// 对象格式 - 复杂权限配置
{
"permission": {
"user.read": true,
"user.write": true,
"user.delete": false,
"post.manage": true
}
}
简单认证提供者的权限检查
内置的 simpleAuthProvider
实现了以下权限检查逻辑:
typescript
can: (name: string, params?: any, manage?: IManageHook, auth?: IUserState): boolean => {
// 如果没有权限配置或权限为空,默认允许访问
if (!auth?.permission
|| (Array.isArray(auth?.permission) && auth?.permission?.length === 0)
|| (typeof auth?.permission === 'object' && Object.keys(auth?.permission).length === 0)) {
return true
}
// 数组形式权限检查 - 检查权限列表中是否包含指定权限
if (Array.isArray(auth?.permission) && !auth?.permission?.includes(name)) {
return false
}
// 对象形式权限检查 - 检查权限对象中指定权限是否为 false
if (typeof auth?.permission === 'object' && auth?.permission[name] === false) {
return false
}
return true
}
权限检查实现示例
typescript
// 简单权限检查
can: (name, params, manage, auth) => {
if (!auth?.permission) {
return false
}
// 数组形式权限检查
if (Array.isArray(auth.permission)) {
return auth.permission.includes(name)
}
// 对象形式权限检查
if (typeof auth.permission === 'object') {
return auth.permission[name] === true
}
return false
}
// 复杂权限检查(支持通配符)
can: (name, params, manage, auth) => {
if (!auth?.permission || !Array.isArray(auth.permission)) {
return false
}
// 检查完全匹配
if (auth.permission.includes(name)) {
return true
}
// 检查通配符权限
return auth.permission.some((permission) => {
if (permission.endsWith('.*')) {
const prefix = permission.slice(0, -2)
return name.startsWith(`${prefix}.`)
}
return false
})
}
// 基于角色的权限检查
can: (name, params, manage, auth) => {
const userRole = auth?.info?.role
const rolePermissions = {
admin: ['*'], // 管理员拥有所有权限
editor: ['post.*', 'user.read'],
viewer: ['*.read']
}
const permissions = rolePermissions[userRole] || []
return permissions.some((permission) => {
if (permission === '*')
return true
if (permission.endsWith('.*')) {
return name.startsWith(`${permission.slice(0, -2)}.`)
}
if (permission.endsWith('.read')) {
return name.endsWith('.read')
}
return permission === name
})
}
路由权限控制
路由可以通过 meta.can
字段控制访问权限,不设置默认为 true
:
typescript
const routes = [
{
name: 'admin.users',
path: 'users',
component: () => import('./pages/users.vue'),
meta: {
can: true, // 使用路由名称进行权限检查
// 或者指定具体权限名称
// can: 'user.manage'
}
}
]
下一步
了解如何在组件中使用认证功能:
- 🔑 用户登录 (useLogin) - 实现登录功能
- 🚪 用户登出 (useLogout) - 实现登出功能
- ✅ 认证检查 (useCheck) - 检查认证状态
- 📝 用户注册 (useRegister) - 实现注册功能
- 🔒 获取认证信息 (useGetAuth) - 获取当前用户信息
- 🛡️ 权限检查 (useCan) - 检查用户权限