wuguofeng/webman-bouncer

Bouncer RBAC (roles & abilities) plugin for webman. Adapts silber/bouncer to webman's long-running process model with per-request state isolation.

Maintainers

Package info

github.com/wuguofeng/webman-bouncer

pkg:composer/wuguofeng/webman-bouncer

Transparency log

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.0 2026-08-06 08:17 UTC

This package is not auto-updated.

Last update: 2026-08-07 06:36:33 UTC


README

Silber\Bouncer(RBAC 角色与能力)的 webman 插件。 将 bouncer 适配到 webman 的长驻进程模型:每个请求独立的 Bouncer 实例(独立的剪贴板与缓存), 避免进程级静态状态串号与权限缓存过期问题。

特性

  • 100% 复用 silber/bouncer 原版 API:Bouncer::allow()/assign()/is()/can()/forbid()、模型 trait $user->can()/$user->isAn()
  • 每请求重建实例(request 缓存策略,ArrayStore),改权限即刻生效,无需手动 refresh()
  • 多租户 scope 支持:scope_resolver 每请求重置,防止租户串号。
  • 自动初始化 Illuminate 容器 + Eloquent(优先复用 webman/database 的连接池)。
  • 提供 php webman bouncer:install 一键建表。

安装

# 项目根目录
composer require wuguofeng/webman-bouncer -W

安装后插件配置自动拷贝到 config/plugin/wuguofeng/webman-bouncer/

配置

编辑 config/plugin/wuguofeng/webman-bouncer/app.php

return [
    'enable'        => true,
    'user_model'    => 'app\model\User',     // 你的 Eloquent 用户模型
    'user_resolver' => fn () => session()->get('user'),  // 每请求当前用户,匿名返回 null
    'cache'         => 'request',            // 'request' | 'none' | webman/cache store 名
    'scope_resolver'=> null,                 // 多租户:返回租户 id,或 null 关闭
    'tables'        => [],
];

缓存策略(cache

说明
'request'(默认) 每请求独立内存缓存(ArrayStore),改动即刻生效,无需手动刷新。推荐日常使用
'none' 完全禁用缓存,每次校验都查库
store 名(如 'file''redis' 跨请求/跨进程持久缓存,复用你项目的 config/cache.php(webman/cache)里的 store

使用跨请求缓存前先安装并配置 webman/cache:

composer require webman/cache
# redis store 还需: composer require webman/redis(并配置 config/redis.php)
# config/cache.php 中定义 stores,例如:
#   'file'  => ['driver' => 'file',  'path' => runtime_path('cache')],
#   'redis' => ['driver' => 'redis', 'connection' => 'default'],

跨请求缓存适合权限数据量大、校验频繁、变更低频的场景(首次校验少查库、后续全部命中缓存)。 代价是权限改动不即时生效,变更后需要手动失效:

use Webman\Bouncer\Bouncer;

Bouncer::refresh($user);   // 只清该用户的缓存(推荐,改动哪个用户就清哪个)
Bouncer::refresh();        // 清全部缓存(用户量大时较慢,慎用)

用户模型:

<?php
namespace app\model;

use Silber\Bouncer\Database\Concerns\Authorizable;
use Silber\Bouncer\Database\HasRolesAndAbilities;
use support\Model;

class User extends Model
{
    use HasRolesAndAbilities;
    use Authorizable;
}

建表:

php webman bouncer:install

使用

use Webman\Bouncer\Bouncer;

// 授权(幂等)
Bouncer::allow('admin')->to('edit-post');
Bouncer::assign('admin')->to($user);
Bouncer::allow($user)->toOwn(Post::class);

// 校验(门面)
Bouncer::can('edit-post');          // bool,针对当前请求用户
Bouncer::cannot('delete-post');
Bouncer::authorize('edit-post');    // 无权限抛 AuthorizationException

// 校验(模型 trait,走同一每请求实例)
$user->can('edit-post');
$user->isAn('admin');

中间件

config/plugin/wuguofeng/webman-bouncer/middleware.php 默认注册了 BouncerMiddleware(作用于所有请求), 保证请求处理器执行前已存在新鲜的 Bouncer 实例(trait 用法依赖它)。不需要可移除。

命令

命令 说明
php webman bouncer:install 创建 bouncer 四张表(abilities / roles / assigned_roles / permissions)

测试

composer test

前置:本地 MySQL(默认 127.0.0.1:3306,库 webman_bouncer_test,用户 bouncer / bouncer_pass), 可用环境变量覆盖:

环境变量 默认值
BOUNCER_TEST_DB_HOST 127.0.0.1
BOUNCER_TEST_DB_PORT 3306
BOUNCER_TEST_DB_NAME webman_bouncer_test
BOUNCER_TEST_DB_USER bouncer
BOUNCER_TEST_DB_PASS bouncer_pass
BOUNCER_TEST_CACHE requestrequest | none

bootstrap 自动建库建表(每次运行先清空重建),并把数据库与插件配置替换为 tests/config/ 下的 fixture。测试用 support\Context 模拟请求边界(Context::destroy()),确保每请求实例、租户 scope、剪贴板等状态不在用例间串号。

工作原理

webman 是长驻进程,进程级静态状态会跨请求残留。本插件把 bouncer 的全部可变状态 (Clipboard、缓存、租户 Scope)放进每请求实例(存于 support\Context,协程安全), 启动时只做进程级一次性配置(Illuminate 容器单例、Eloquent、用户模型映射、morph map):

请求 → BouncerMiddleware → Bouncer::instance()(惰性创建,存 Context)
     → 控制器/模型使用(同一实例,请求结束随 Context 销毁)

License

MIT