njeaner / symfrop
一个 Symfony 前端角色权限包。此包允许网站管理员管理用户角色权限
Requires
- php: ^8.1.0
- doctrine/annotations: ^1.13
- doctrine/doctrine-migrations-bundle: ^3.2
- doctrine/orm: ^2.12
- opis/closure: ^3.6
- symfony/config: ^6.1
- symfony/console: ^6.1
- symfony/dependency-injection: ^6.1
- symfony/form: ^6.1
- symfony/http-kernel: ^6.1
- symfony/security-bundle: ^6.1
- symfony/translation: ^6.1
- symfony/twig-bundle: ^6.1
- symfony/validator: ^6.1
- symfony/yaml: ^6.1
- twig/extra-bundle: ^3.4
- twig/twig: ^3.4
Requires (Dev)
- phpunit/phpunit: ^9.5
- symfony/browser-kit: ^6.1
- symfony/debug-bundle: ^6.1
- symfony/framework-bundle: ^6.1
- symfony/maker-bundle: ^1.45
- symfony/phpunit-bridge: ^6.1
README
一个 Symfony 前端角色权限包。此包允许网站管理员管理用户角色和权限。
内容
一些页面截图



安装
在安装此包之前,将此配置复制到您 symfony 项目中的 config/packages/symfrop.yaml 文件中
symfrop_bundle: resources_info: App/Controller: '%kernel.project_dir%/src/Controller' entities: entity: user_entity: 'Njeaner\Symfrop\Entity\User' role_entity: 'Njeaner\Symfrop\Entity\Role' action_entity: 'Njeaner\Symfrop\Entity\Action' form: role_form: 'Njeaner\Symfrop\Form\RoleType' action_form: 'Njeaner\Symfrop\Form\ActionType' user_role_form: 'Njeaner\Symfrop\Form\UserRoleType' app_roles: ROLE_USER: 'user' ROLE_ADMIN: 'admin' ROLE_SUPERADMIN: ['root', false]
当配置文件复制到 config/packages/symfrop.yaml 中时,然后使用以下命令安装包
composer require njeaner/symfrop
包安装后,将此代码复制到 config/routes/attributes.yaml
controllers: resource: '@SymfropBundle/Controller/' type: attribute
并使用此命令生成 Symfrop 用户、角色和动作实体
php bin\console symfrop:entities [entities-folder]
或此命令
symfony console symfrop:entities [entities-folder]
可选的 [entities-folder] 参数是包含您的认证实体的文件夹。如果此参数缺失,实体将生成在 src/Entity/ 目录中。例如,"php bin\console symfrop:entities Auth" 命令将在 src/Entity/Auth/ 目录中生成 symfrop 实体。
现在在您的 config/packages/symfrop.yaml 中,将以下行更改为此
user_entity: 'Njeaner\Symfrop\Entity\User' role_entity: 'Njeaner\Symfrop\Entity\Role' action_entity: 'Njeaner\Symfrop\Entity\Action'
通过此
user_entity: 'App\Entity[\entities-folder]\User' role_entity: 'App\Entity[\entities-folder]\Role' action_entity: 'App\Entity[\entities-folder]\Action'
示例
user_entity: 'App\Entity\Auth\User' role_entity: 'App\Entity\Auth\Role' action_entity: 'App\Entity\Auth\Action'
或如果实体直接生成在 src/Entity 目录中
user_entity: 'App\Entity\User' role_entity: 'App\Entity\Role' action_entity: 'App\Entity\Action'
注意:您不必使用 symfrop 命令生成实体,此命令是一种简单地生成所有所需实体的方法。symfrop 包使用三个核心实体
- 一个用户实体,表示应用程序用户,此实体必须实现 Njeaner\Symfrop\Entity\Contract\UserInterface,它扩展了 symfony 用户接口;
- 一个角色实体,定义在应用程序中使用的不同类型的角色,此实体必须实现 Njeaner\Symfrop\Entity\Contract\RoleInterface。默认角色有
- ROLE_USER(一个简单用户角色),
- ROLE_ADMIN(一个管理员角色),
- ROLE_SUPERADMIN(具有所有特权的根角色)。
- 一个动作实体,定义应用程序中所有用户操作,此实体必须实现 Njeaner\Symfrop\Entity\Contract\ActionInterface。每个 symfony 控制器操作都是一个 symfrop 操作,可以使用 symfrop 类和方法属性进行指定。
如何使用它?
定义 symfrop 用户操作
symfrop 包使用控制器类和方法属性来定义应用程序中的用户操作和权限。可以使用两个属性来定义控制器操作
- Njeaner\Symfrop\Core\Annotation\Route,它是 Symfony\Component\Routing\Annotation\Route 的扩展,为 symfrop 包添加了一些属性。当使用此属性时,不需要使用更多 symfony 路由属性,因为它接受所有 symfony 路由属性属性以及 symfrop 属性属性。
- Njeaner\Symfrop\Core\Annotation\RouteAction。此属性必须与 symfony 路由属性结合使用。因此,任何 symfony 控制器操作都必须包含两个方法属性实例:一个 Symfony\Component\Routing\Annotation\Route 用于定义 symfony 路由和一个 Njeaner\Symfrop\Core\Annotation\RouteAction 用于定义 symfrop 用户操作。
symfrop 属性有
- name(必需):用于定义操作名称
- title(可选):用于定义操作标题,如果值缺失,则使用名称值
- target(可选):字符串或数组值,用于定义与定义的操作关联的角色。
- isUpdatable(默认:true):定义是否允许动作更新。
- hasAuth(默认:true):定义控制器动作是否可以通过symfrop包进行身份验证。没有symfrop属性的动作不能通过此包进行身份验证。
- isIndex(默认:false):指定动作是否是索引动作。
- updatedRole(默认:false):当属性目标值更改时使用。允许更新数据库角色对应关系。
- isUpdated(默认:false):当(某)属性属性值更改时使用。允许更新数据库值。
- actionCondition(默认:null):在授权检查期间要检查的补充条件。
- conditionOption:与actionCondition属性一起使用,以指定actionCondition是否将覆盖授权检查,还是与它结合。Njeaner\Symfrop\Core\Annotation\RouteAction属性只接受这些属性。Njeaner\Symfrop\Core\Annotation\Route属性将这些属性与Symfony\Component\Routing\Annotation\Route属性属性结合使用,以在指定的时间定义symfony路由动作和symfrop用户动作。一个简单示例
namespace App\Controller\Auth; use App\Repository\Auth\UserRepository; use Njeaner\Symfrop\Core\Annotation\Route ; use Njeaner\Symfrop\Core\Service\CONSTANTS; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; #[Route('/auth/user/{_locale<fr|en|es|pt>?en}', requirements: ['_locale' => 'fr|en|es'])] class UserController extends AbstractController { // path, name, methods are for symfony routing. name, target, isIndex are for symfrop user action. #[Route(path: '', name: 'app_auth_user_index', methods: ['GET'], target: CONSTANTS::ROLE_ALL, isIndex: true)] public function index(UserRepository $userRepository): Response { return $this->render('auth/user/index.html.twig', [ 'users' => $userRepository->findAll(), ]); } }
检查 symfrop 用户操作
symfrop授权在kernel.request事件和控制器实例化之前进行检查。该包使用当前路由名称和当前安全用户来检查动作授权。
在控制器中检查
有时我们可能需要在控制器动作中检查某些路由是否受授权。
//... use Njeaner\Symfrop\Core\Manager\AnnotationManager; class UserController extends BaseAppController { // path, name, methods are for symfony routing. name, target, isIndex are for symfrop user action. #[Route(path: '', name: 'app_auth_user_index', methods: ['GET'], target: CONSTANTS::ROLE_ALL, isIndex: true)] public function index(UserRepository $userRepository, AnnotationManager $am): Response { if($am->isAuthorize('some-route-name')){ // return true or false // do some action; } return $this->render('auth/user/index.html.twig', [ 'users' => $userRepository->findAll(), ]); } }
在 twig 模板中检查
在twig模板中检查用户动作授权可以显示或隐藏链接、表单,这取决于用户动作权限。例如,仅对具有编辑用户信息权限的管理员显示编辑用户信息链接或表单。
Symfrop包提供三种在twig模板中检查用户动作授权的方法。
-
create_symfrop_link函数,允许创建链接。使用此twig函数,只有在当前用户有处理此链接的动作权限时才会生成链接。它接受2到4个参数。
- 必需的第一个参数(类型为字符串)是路由名称。
- 必需的第二个参数(类型为字符串或两个字符串的数组)是链接标签。如果是一个数组参数,第一个数组项将是链接标签,第二个数组项将是链接未生成时显示的文本。
- 可选的第三个参数是生成链接href的参数。
- 可选的最后参数是添加一些html标签属性到链接中,如class、id、title、style等。
示例
{{ create_symfrop_link( 'my_route_name', 'link_label', {# or ['link_label', 'default_label'] #} {'param': 'param_value'}, {'class': 'btn btn-primary', 'title': 'link_title'} ) }}
- symfrop标签,允许仅在用户获得动作权限时渲染块。这对于仅当用户有处理表单动作的权限时渲染表单很有用。例如,仅对有权限编辑用户信息的管理员显示编辑用户信息表单。symfrop标签有一个else标签,允许在用户没有权限处理指定动作时渲染其他内容。
示例
{% symfrop route_name %} {# show some block #} {% endsymfrop %} {# or #} {% symfrop route_name %} {# show some block #} {% else %} {# show other block #} {% endsymfrop %}
- is action autorized标签,允许检查用户是否获得动作路由权限。
示例
{% if route_name is authorized action %} {# show some block #} {% endsymfrop %} {# or #} {% symfrop route_name %} {# show some block #} {% else %} {# show other block #} {% endsymfrop %}
在 Symfrop 包中翻译
Symfrop包提供一些twig函数来处理翻译。
- __函数是symfrop基本区域翻译函数。
- __u或__U函数是ucfirst区域翻译函数。
- __t或__T是symfony title过滤器的衍生。
用法示例
__('name') {# will return: "name" if request locale is english(en), "nom" if french(fr) or "nombre" if request locale is spanish(es) #}
生成实体 CRUD
Symfrop包提供了一个symfony等效的make:crud命令,可以轻松创建一个crud,它使用Njeaner\Symfrop\Annotations\RouteAction方法属性、包含区域翻译的表单以及带有symfrop动作链接和表单权限检查的视图。
使用php命令生成symfrop crud
php bin/console symfrop:crud
覆盖默认 symfrop 控制器方法操作
Symfrop包默认使用七个(07)控制器方法来管理默认包动作。这些是
- njeaner_symfrop_role_index显示所有定义的角色;
- njeaner_symfrop_user_index显示应用程序中所有用户的角色;
- njeaner_symfrop_role_create用于角色创建;
- njeaner_symfrop_role_update 用于角色编辑;
- njeaner_symfrop_role_delete 用于删除角色;
- njeaner_symfrop_user_role_edit 用于编辑用户角色;
- njeaner_symfrop_action_edit 用于编辑用户行为。
要覆盖这些行为之一或全部,您只需创建一个具有相同 symfony 路由属性名和相同 symfrop 属性名的 symfony 控制器方法。
例如
use Njeaner\Symfrop\Core\Annotation\RouteAction; class MyCostumActionController{ /*This will override default njeaner_symfrop_role_index that list all role list*/ #[RouteAction(name: 'njeaner_symfrop_role_index')] public function roleIndex(){ return $this->getRoleRepostory()->findAll(); } }
注入顶部或/和底部导航栏、样式表标签和脚本标签
symfrop 包允许在包默认视图中注入顶部和底部导航栏、样式表和脚本标签。这允许在所有应用程序(包括 symfrop 视图)中具有相同的导航栏。这种注入必须在 config/packages/symfrop.yaml 中配置,在 templates 部分如下
templates: navbar_top: my_top_navbar_file.html navbar_bottom: my_bottom_navbar_file.html scripts: ['my_first_script.js', 'my_other_script.js'] stylesheets: ['my_first_style.css', 'my_other_style.css']
注意:每个部分都是可选的。您只需注入其中之一。
更改默认 symfrop 样式值
以下列出了所有 symfrop 自定义 CSS 类及其值。如果您想覆盖一些类的值,可以在自定义 CSS 样式文件中做到。通过使用您的浏览器检查 symfrop 视图页面,您可以确定要覆盖哪些类值。
.symfrop-container{ margin: 8px; padding: 8px; display: flex; justify-content: center; flex-direction: column; padding-top: 40px; padding-bottom:60px; } .symfrop-row{ display: flex; align-items: stretch; justify-content: space-between; flex-wrap: wrap; } .symfrop-col{ padding: 4px; margin: 4px; width: 100%; } .symfrop-col-4{ padding: 4px; margin: 4px; width: 25vw; } .symfrop-col-3{ padding: 4px; margin: 4px; width: 30.5vw; } .symfrop-width-3{ width: 30.5vw; } .symfrop-width-4{ width: 25vw; } .symfrop-width-2{ width: 50vw; } .symfrop-bg-dark{ background-color: rgb(26, 26, 32); } .symfrop-form{ width: 40vw; padding: 5px; padding: 10px; background-color: rgba(26, 100, 32, 0.4); } .symfrop-form-group{ margin: 10px; } .symfrop-form-group > ul { color: red; padding-top: 0; padding-bottom: 0; margin-top: 0; margin-bottom: 0; } .symfrop-card{ width: 100%; background-color: rgba(26, 100, 32, 0.4); min-height: 50px; border-radius: 5px; position: relative; } .symfrop-card-body{ padding: 2px; min-height: 40px; } .symfrop-card-title{ font-size: 1.2rem; padding: 8px; background-color: #50cece; border-radius: 5px 5px 0px 0px; } .symfrop-card-footer{ font-size: 1.2rem; padding: 4px; border-radius: 0px 0px 5px 5px; min-height: 30px; display: flex; justify-content: center; } .symfrop-card-footer a{ text-decoration: none; } .symfrop-display-block{ display:block; } a{ text-decoration: none; } .symfrop-input { width: 100%; height: 1.2rem; border-radius: 5px; } .symfrop-btn{ min-width: 80px; min-height: 20px; border-radius: 4px; padding: 5px; border: 1px solid grey; background-color: grey; } .symfrop-btn:hover, input:hover{ opacity: 0.7; } .symfrop-btn.symfrop-btn-primary{ background-color: rgb(0, 150, 200); color: white; } .symfrop-btn.symfrop-btn-success{ background-color: rgb(0, 150, 20); color: white; } .symfrop-btn.symfrop-btn-danger{ background-color: rgb(200, 50, 0); color: white; } .symfrop-text-white{ color: white; } .symfrop-text-center{ text-align: center; } .symfrop-text-left{ text-align: left; } .symfrop-text-right{ text-align: right; } th, td{ padding: 2px; } .symfrop-flex{ display: flex; } .symfrop-flex-center{ align-items: center; justify-content: center; } .symfrop-alert{ margin: 4px; padding: 8px; border-radius: 5px; background-color: #cacaca; color: white; text-align: center; } .symfrop-alert.error{ background-color: rgba(186, 86, 86, 0.7); } .symfrop-alert.symfrop-success{ background-color: rgba(86, 186, 86, 0.7); }