认证

XinAdmin 使用 Laravel Sanctum 实现基于 Token 的 API 认证。

认证概览

特性说明
认证驱动Sanctum Personal Access Token
Token 传输Authorization: Bearer {token} 请求头
Token 存储前端 localStorage
Token 过期默认 3 天,勾选"记住我"则永不过期
密码哈希bcrypt,12 轮加密 (BCRYPT_ROUNDS=12)

登录流程

用户输入凭证 → POST /system/login
  ├── 验证用户名密码 (Auth::guard('sys_users')->attempt())
  ├── 获取用户权限列表 (access() 方法)
  ├── 生成 Sanctum Token (createToken)
  └── 返回 token + 权限数组

前端收到响应
  ├── localStorage.setItem('token', token)
  ├── 调用 GET /system/info 获取用户信息 + 权限
  └── 存储到 Zustand auth store

Token 验证流程

每次 API 请求的后端处理链:

请求进入
  ├── AllowCrossDomainMiddleware (CORS)
  ├── LanguageMiddleware (语言检测)
  ├── auth:sanctum          → 验证 Bearer Token 有效性
  ├── authGuard             → 验证 Token 的 tokenable_type 匹配用户模型
  └── abilities:{key}       → 验证 Token 的 abilities 包含所需权限

自定义 Token 模型

XinAdmin 扩展了 Sanctum 的 PersonalAccessToken,关键实现:

  • 使用独立数据表 sys_access_token
  • 超级管理员(用户 ID = 1)始终通过所有能力检查
  • 支持通配符权限 *(超级管理员角色专用)
// SysAccessToken::can()
public function can($ability)
{
    // 超级管理员通过所有检查
    if ($this->tokenable_id === 1) {
        return true;
    }
    // 检查是否拥有 * 通配符权限
    if (in_array('*', $this->abilities)) {
        return true;
    }
    return array_key_exists($ability, array_flip($this->abilities));
}

登录审计

LoginLogMiddleware 记录每次登录操作到 sys_login_record 表:

记录项说明
User-Agent用户代理字符串
IP 地址登录 IP
浏览器/OS解析后的浏览器类型和操作系统
地理位置通过 ipinfo.io API 查询
登录状态成功 / 失败

前端登录保护

保护机制说明
入口检查App.tsx 启动时检查 localStorage 中是否存在 token,若无则重定向到 /login
401 处理Axios 响应拦截器拦截 401 状态码,自动清除本地 token 并跳转登录页
Token 附加存储在 localStorage,每次请求通过 Axios 拦截器自动附加到 Authorization
登出调用 POST /system/logout 后清除本地所有存储

Axios 拦截器

// 请求拦截器:自动附加 Token
instance.interceptors.request.use((config) => {
  const token = localStorage.getItem('token');
  if (token) {
    config.headers['Authorization'] = `Bearer ${token}`;
  }
  return config;
});

// 响应拦截器:处理 401
instance.interceptors.response.use(
  (response) => response,
  (error) => {
    if (error.response?.status === 401) {
      localStorage.removeItem('token');
      window.location.href = '/login';
    }
    return Promise.reject(error);
  }
);

密码安全

配置说明
哈希算法bcrypt
加密轮数BCRYPT_ROUNDS=12(可在 .env 中调整)
密码规则最少 6 位,最多 20 位,仅允许字母数字和横线
修改密码需验证旧密码,使用 password_verify() + Hash::make()