├── .gitattributes
├── .gitignore
├── LICENSE
├── README.md
├── composer.json
├── config
└── mojito.php
├── database
└── migrations
│ ├── add_custom_field_permission_tables.php
│ ├── create_admin_table.php
│ ├── create_menu_table.php
│ └── create_permission_group_table.php
└── src
├── AdminUserFactory.php
├── Console
└── InstallCommand.php
├── Contacts
└── UserContact.php
├── Database
└── MojitoTableSeeder.php
├── Http
├── Controllers
│ ├── AdminUserController.php
│ ├── CaptchaController.php
│ ├── ChangePasswordController.php
│ ├── Controller.php
│ ├── LoginController.php
│ ├── MenuController.php
│ ├── PermissionController.php
│ ├── PermissionGroupController.php
│ └── RoleController.php
├── Middleware
│ └── Authenticate.php
├── MojitoResponse.php
└── Requests
│ ├── AdminUser
│ └── CreateOrUpdateRequest.php
│ ├── ChangePasswordRequest.php
│ ├── Menu
│ └── CreateOrUpdateRequest.php
│ ├── Permission
│ └── CreateOrUpdateRequest.php
│ ├── PermissionGroup
│ └── CreateOrUpdateRequest.php
│ └── Role
│ └── CreateOrUpdateRequest.php
├── Models
├── AdminUser.php
├── Menu.php
├── Permission.php
├── PermissionGroup.php
└── User.php
├── Providers
└── MojitoServiceProvider.php
├── Resources
├── AdminUser.php
├── AdminUserCollection.php
├── Menu.php
├── Permission.php
├── PermissionCollection.php
├── PermissionGroup.php
├── PermissionGroupCollection.php
├── Role.php
└── RoleCollection.php
├── helpers.php
└── routes.php
/.gitattributes:
--------------------------------------------------------------------------------
1 | /tests export-ignore
2 | phpunit.xml export-ignore
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /.idea
2 | /vendor
3 | composer.lock
4 | .phpunit.result.cache
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Mojito
2 |
3 | Mojito 是基于 Laravel 开发的 [Mojito Admin](https://github.com/moell-peng/mojito-admin) 的服务端。
4 |
5 | 3.0 版本开始, 已将原来的项目分离为两个代码库,分别为以Vue3、Element Plus、Vite 开发的前端模板 [mojito -admin](https://github.com/moell-peng/mojito-admin) 和服务端 [mojito](https://github.com/moell-peng/mojito) 。如果是需要使用 vue2 版本,请访问 [2.0](https://github.com/moell-peng/mojito/tree/2.0) 分支。
6 |
7 | ## Mojito Admin 截图
8 |
9 | 
10 |
11 | ## 特性
12 |
13 | * 前后端分离,提供 [Mojito Admin](https://github.com/moell-peng/mojito-admin) 前端模板
14 | * 基于 laravel-permission 权限管理
15 | * 基于 sanctum 鉴权
16 | * 提供角色,权限,用户,菜单管理等功能的API
17 | * 多个后台支持统一管理权限,菜单和角色
18 | * 完善的PHPUnit测试
19 |
20 | ## 要求
21 |
22 | - Laravel >= 7.0.0
23 | - PHP >= 7.2.0
24 |
25 | ## 安装
26 |
27 | 首先安装laravel,并且确保你配置了正确的数据库连接。
28 |
29 | ```
30 | composer require moell/mojito
31 | ```
32 |
33 | 然后运行下面的命令来发布资源:
34 |
35 | ```
36 | php artisan mojito:install
37 | ```
38 |
39 | 命令执行成功会生成配置文件,数据迁移和构建SPA的文件。
40 |
41 | 修改 `app/Http/Kernel.php` :
42 |
43 | ```
44 | class Kernel extends HttpKernel
45 | {
46 | protected $routeMiddleware = [
47 | ...
48 | 'mojito.permission' => \Moell\Mojito\Http\Middleware\Authenticate::class,
49 | ];
50 |
51 | protected $middlewareGroups = [
52 | ...
53 | 'api' => [
54 | ...
55 | \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
56 | ],
57 | ];
58 | }
59 | ```
60 |
61 | 执行数据迁移,数据填充
62 |
63 | ```
64 | php artisan migrate
65 |
66 | php artisan db:seed --class="Moell\Mojito\Database\MojitoTableSeeder"
67 | ```
68 |
69 | 后台登录的账号 `admin` , 密码 `secret`
70 |
71 | ## 路由中间件
72 |
73 | * auth:sanctum 用于鉴权
74 | * mojito.permission 权限验证
75 |
76 | ## mojito.php 可选配置
77 |
78 | ```php
79 | return [
80 | 'guards' => [
81 | // laravel-permission 相对应的 guard
82 | 'admin' => [
83 | 'model' => \Moell\Mojito\Models\AdminUser::class, //登录鉴权的模型
84 | 'login_fields' => [ // 登录验证的字段,支持多个
85 | 'username',
86 | ],
87 | 'conditions' => [ // 登录验证的额外条件
88 | ['status', '=', 1]
89 | ]
90 | ]
91 | ],
92 | 'route_prefix' => "api", //路由前缀
93 |
94 | 'middleware' => [
95 | 'basic' => 'api', //基础中间件
96 |
97 | 'auth' => ['auth:sanctum'], //鉴权中间件
98 |
99 | 'permission' => ['auth:sanctum', 'mojito.permission'] //包含权限检测的中间件
100 | ]
101 | ];
102 | ```
103 |
104 | ## 依赖扩展包
105 |
106 | * spatie/laravel-permission
107 | * laravel/sanctum
108 |
109 | ## 常见错误
110 |
111 | * csrf token missing or incorrect , 请修改 sanctum.php 中的 `stateful` , 如 vite 使用的 `localhost:3000 `去除即可。更多详细请访问`laravel/sanctum`文档。
112 |
113 |
114 | ## 打赏
115 |
116 |
117 |
118 |
119 |
120 |
121 | ## License
122 |
123 | Apache License Version 2.0 see http://www.apache.org/licenses/LICENSE-2.0.html
124 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "moell/mojito",
3 | "description": "Mojito admin is a component of laravel, vue, element build backend system.",
4 | "keywords": ["laravel", "admin", "vue", "element", "laravel admin", "vue admin", "element admin"],
5 | "type": "library",
6 | "license": "MIT",
7 | "authors": [
8 | {
9 | "name": "moell",
10 | "email": "moell91@foxmail.com"
11 | }
12 | ],
13 | "require": {
14 | "php": "^7.2|^8.0",
15 | "spatie/laravel-permission": "^5.3",
16 | "laravel/sanctum": "^2.4|^3.2",
17 | "gregwar/captcha": "^1.1"
18 | },
19 | "require-dev": {
20 | "mockery/mockery": "^1.0",
21 | "orchestra/testbench": "^5.0|^6.0|^7.0|^8.0",
22 | "dms/phpunit-arraysubset-asserts": "^0.4.0",
23 | "doctrine/dbal": "^2.8",
24 | "laravel/legacy-factories": "^1.0.4"
25 | },
26 | "autoload": {
27 | "psr-4": {
28 | "Moell\\Mojito\\": "src/"
29 | },
30 | "files": [
31 | "src/helpers.php"
32 | ]
33 | },
34 | "autoload-dev": {
35 | "psr-4": {
36 | "Moell\\Mojito\\Tests\\": "tests/"
37 | }
38 | },
39 | "extra": {
40 | "laravel": {
41 | "providers": [
42 | "Moell\\Mojito\\Providers\\MojitoServiceProvider"
43 | ]
44 | }
45 | },
46 | "minimum-stability":"dev",
47 | "prefer-stable": true
48 | }
49 |
--------------------------------------------------------------------------------
/config/mojito.php:
--------------------------------------------------------------------------------
1 | [
5 | 'admin' => [
6 | 'model' => \Moell\Mojito\Models\AdminUser::class,
7 | 'login_fields' => [
8 | 'username',
9 | ],
10 | 'conditions' => [
11 | ['status', '=', 1]
12 | ]
13 | ]
14 | ],
15 |
16 | 'route_prefix' => "api",
17 |
18 | 'middleware' => [
19 | 'basic' => 'api',
20 |
21 | 'auth' => ['auth:sanctum'],
22 |
23 | 'permission' => ['auth:sanctum', 'mojito.permission']
24 | ],
25 |
26 | 'captcha_cache_ttl' => 2,
27 | ];
--------------------------------------------------------------------------------
/database/migrations/add_custom_field_permission_tables.php:
--------------------------------------------------------------------------------
1 | integer('pg_id')->default(0);
20 | $table->string('display_name', 50)->nullable();
21 | $table->string('icon', 30)->nullable();
22 | $table->smallInteger('sequence')->nullable();
23 | $table->string('created_name', 50)->nullable();
24 | $table->string('updated_name', 50)->nullable();
25 | $table->string('description')->nullable();
26 | });
27 |
28 | Schema::table($tableNames['roles'], function (Blueprint $table) {
29 | $table->string('description')->nullable();
30 | });
31 | }
32 |
33 | /**
34 | * Reverse the migrations.
35 | *
36 | * @return void
37 | */
38 | public function down()
39 | {
40 | $tableNames = config('permission.table_names');
41 |
42 | Schema::table($tableNames['permissions'], function (Blueprint $table) {
43 | $table->dropColumn('display_name');
44 | $table->dropColumn('icon');
45 | $table->dropColumn('sequence');
46 | $table->dropColumn('created_name');
47 | $table->dropColumn('updated_name');
48 | $table->dropColumn('description');
49 | });
50 |
51 | Schema::table($tableNames['roles'], function (Blueprint $table) {
52 | $table->dropColumn('description');
53 | });
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/database/migrations/create_admin_table.php:
--------------------------------------------------------------------------------
1 | increments('id');
18 | $table->string('name');
19 | $table->string('username')->unique();
20 | $table->string('password');
21 | $table->boolean("status");
22 | $table->rememberToken();
23 | $table->timestamps();
24 | });
25 | }
26 |
27 | /**
28 | * Reverse the migrations.
29 | *
30 | * @return void
31 | */
32 | public function down()
33 | {
34 | Schema::dropIfExists('admin_users');
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/database/migrations/create_menu_table.php:
--------------------------------------------------------------------------------
1 | increments('id');
18 | $table->integer('parent_id')->default(0);
19 | $table->string('icon', 50)->nullable();
20 | $table->string('uri');
21 | $table->tinyInteger('is_link')->default(0)->comment('0-no;1-yes');
22 | $table->string('permission_name', 50)->nullable();
23 | $table->string('name');
24 | $table->string('guard_name', 30);
25 | $table->smallInteger('sequence')->default(0);
26 | $table->timestamps();
27 | });
28 | }
29 |
30 | /**
31 | * Reverse the migrations.
32 | *
33 | * @return void
34 | */
35 | public function down()
36 | {
37 | Schema::dropIfExists('menus');
38 | }
39 | }
--------------------------------------------------------------------------------
/database/migrations/create_permission_group_table.php:
--------------------------------------------------------------------------------
1 | increments('id');
18 | $table->string('name');
19 | $table->timestamps();
20 | });
21 | }
22 |
23 | /**
24 | * Reverse the migrations.
25 | *
26 | * @return void
27 | */
28 | public function down()
29 | {
30 | Schema::dropIfExists('permission_groups');
31 | }
32 | }
--------------------------------------------------------------------------------
/src/AdminUserFactory.php:
--------------------------------------------------------------------------------
1 |
27 | * @return mixed
28 | */
29 | public function handle()
30 | {
31 | $this->call('vendor:publish', ['--provider' => 'Spatie\Permission\PermissionServiceProvider']);
32 | $this->call('vendor:publish', ['--provider' => 'Moell\Mojito\Providers\MojitoServiceProvider']);
33 | $this->call('vendor:publish', ['--provider' => 'Laravel\Sanctum\SanctumServiceProvider']);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/Contacts/UserContact.php:
--------------------------------------------------------------------------------
1 | 'admin-user.index',
17 | 'display_name' => '列表',
18 | 'pg_id' => 1
19 | ],
20 | [
21 | 'name' => 'admin-user.show',
22 | 'display_name' => '详细',
23 | 'pg_id' => 1
24 | ],
25 | [
26 | 'name' => 'admin-user.store',
27 | 'display_name' => '添加',
28 | 'pg_id' => 1
29 | ],
30 | [
31 | 'name' => 'admin-user.update',
32 | 'display_name' => '修改',
33 | 'pg_id' => 1
34 | ],
35 | [
36 | 'name' => 'admin-user.destroy',
37 | 'display_name' => '删除',
38 | 'pg_id' => 1
39 | ],
40 | [
41 | 'name' => 'admin-user.roles',
42 | 'display_name' => '用户角色列表',
43 | 'pg_id' => 1
44 | ],
45 | [
46 | 'name' => 'admin-user.assign-roles',
47 | 'display_name' => '分配角色',
48 | 'pg_id' => 1
49 | ],
50 | [
51 | 'name' => 'role.index',
52 | 'display_name' => '列表',
53 | 'pg_id' => 2
54 | ],
55 | [
56 | 'name' => 'role.show',
57 | 'display_name' => '详细',
58 | 'pg_id' => 2
59 | ],
60 | [
61 | 'name' => 'role.store',
62 | 'display_name' => '添加',
63 | 'pg_id' => 2
64 | ],
65 | [
66 | 'name' => 'role.update',
67 | 'display_name' => '修改',
68 | 'pg_id' => 2
69 | ],
70 | [
71 | 'name' => 'role.destroy',
72 | 'display_name' => '删除',
73 | 'pg_id' => 2
74 | ],
75 | [
76 | 'name' => 'role.permissions',
77 | 'display_name' => '获取角色的权限',
78 | 'pg_id' => 2
79 | ],
80 | [
81 | 'name' => 'role.assign-permissions',
82 | 'display_name' => '角色分配权限',
83 | 'pg_id' => 2
84 | ],
85 | [
86 | 'name' => 'role.guard-name-roles',
87 | 'display_name' => '看守器对应的所有角色',
88 | 'pg_id' => 2
89 | ],
90 | [
91 | 'name' => 'permission.index',
92 | 'display_name' => '列表',
93 | 'pg_id' => 3
94 | ],
95 | [
96 | 'name' => 'permission.show',
97 | 'display_name' => '详细',
98 | 'pg_id' => 3
99 | ],
100 | [
101 | 'name' => 'permission.store',
102 | 'display_name' => '添加',
103 | 'pg_id' => 3
104 | ],
105 | [
106 | 'name' => 'permission.update',
107 | 'display_name' => '修改',
108 | 'pg_id' => 3
109 | ],
110 | [
111 | 'name' => 'permission.destroy',
112 | 'display_name' => '删除',
113 | 'pg_id' => 3
114 | ],
115 | [
116 | 'name' => 'menu.index',
117 | 'display_name' => '列表',
118 | 'pg_id' => 4
119 | ],
120 | [
121 | 'name' => 'menu.show',
122 | 'display_name' => '详细',
123 | 'pg_id' => 4
124 | ],
125 | [
126 | 'name' => 'menu.store',
127 | 'display_name' => '添加',
128 | 'pg_id' => 4
129 | ],
130 | [
131 | 'name' => 'menu.update',
132 | 'display_name' => '修改',
133 | 'pg_id' => 4
134 | ],
135 | [
136 | 'name' => 'menu.destroy',
137 | 'display_name' => '删除',
138 | 'pg_id' => 4
139 | ],
140 | [
141 | 'name' => 'permission-group.index',
142 | 'display_name' => '列表',
143 | 'pg_id' => 5
144 | ],
145 | [
146 | 'name' => 'permission-group.show',
147 | 'display_name' => '详细',
148 | 'pg_id' => 5
149 | ],
150 | [
151 | 'name' => 'permission-group.store',
152 | 'display_name' => '添加',
153 | 'pg_id' => 5
154 | ],
155 | [
156 | 'name' => 'permission-group.update',
157 | 'display_name' => '修改',
158 | 'pg_id' => 5
159 | ],
160 | [
161 | 'name' => 'permission-group.destroy',
162 | 'display_name' => '删除',
163 | 'pg_id' => 5
164 | ],
165 | [
166 | 'name' => 'permission-group.guard-name-for-permission',
167 | 'display_name' => '获取看守器权限',
168 | 'pg_id' => 5
169 | ],
170 | [
171 | 'name' => 'permission-group.all',
172 | 'display_name' => '所有权限组',
173 | 'pg_id' => 5
174 | ]
175 | ];
176 |
177 | /**
178 | * Run the database seeds.
179 | *
180 | * @author moell
181 | * @return void
182 | */
183 | public function run()
184 | {
185 | app()['cache']->forget('spatie.permission.cache');
186 |
187 | $this->createdAdminUser();
188 |
189 | $this->createPermissionGroup();
190 |
191 | $this->createRole();
192 |
193 | $this->createPermission();
194 |
195 | $this->createMenu();
196 |
197 | $this->associateRolePermissions();
198 | }
199 |
200 | /**
201 | * @author moell
202 | */
203 | private function createdAdminUser()
204 | {
205 | AdminUserFactory::adminUser()->truncate();
206 |
207 | AdminUserFactory::adminUser()->create([
208 | 'name' => 'admin',
209 | 'username' => 'admin',
210 | 'status' => 1,
211 | 'password' => '$2y$10$TKh8H1.PfQx37YgCzwiKb.KjNyWgaHb9cbcoQgdIVFlYg7B77UdFm', // secret
212 | ]);
213 | }
214 |
215 | /**
216 | * @author moell
217 | */
218 | private function createPermission()
219 | {
220 | Permission::query()->delete();
221 |
222 | foreach ($this->permissions as $permission) {
223 | $permission['guard_name'] = 'admin';
224 | Permission::create($permission);
225 | }
226 | }
227 |
228 | /**
229 | * @author moell
230 | */
231 | private function createPermissionGroup()
232 | {
233 | PermissionGroup::truncate();
234 | PermissionGroup::insert([
235 | [
236 | 'id' => 1,
237 | 'name' => '管理员',
238 | ], [
239 | 'id' => 2,
240 | 'name' => '角色'
241 | ], [
242 | 'id' => 3,
243 | 'name' => '权限'
244 | ], [
245 | 'id' => 4,
246 | 'name' => '菜单'
247 | ], [
248 | 'id' => 5,
249 | 'name' => '权限组'
250 | ]
251 | ]);
252 | }
253 |
254 | /**
255 | * @author moell
256 | */
257 | private function createRole()
258 | {
259 | Role::query()->delete();
260 | Role::create([
261 | 'name' => 'admin',
262 | 'guard_name' => 'admin'
263 | ]);
264 | }
265 |
266 | /**
267 | * @author moell
268 | */
269 | private function createMenu()
270 | {
271 | Menu::truncate();
272 | Menu::insert([
273 | [
274 | 'id' => 1,
275 | 'parent_id' => 0,
276 | 'uri' => '/dashboard',
277 | 'name' => 'Dashboard',
278 | 'icon' => 'Orange',
279 | 'guard_name'=> 'admin'
280 | ],
281 | [
282 | 'id' => 2,
283 | 'parent_id' => 0,
284 | 'uri' => '/admin',
285 | 'name' => '系统管理',
286 | 'icon' => 'Setting',
287 | 'guard_name'=> 'admin'
288 | ],
289 | [
290 | 'id' => 3,
291 | 'parent_id' => 2,
292 | 'uri' => '/admin-user',
293 | 'name' => '管理员',
294 | 'icon' => '',
295 | 'guard_name'=> 'admin'
296 | ],
297 | [
298 | 'id' => 4,
299 | 'parent_id' => 2,
300 | 'uri' => '/role',
301 | 'name' => '角色',
302 | 'icon' => '',
303 | 'guard_name'=> 'admin'
304 | ],
305 | [
306 | 'id' => 5,
307 | 'parent_id' => 2,
308 | 'uri' => '/permission',
309 | 'name' => '权限',
310 | 'icon' => '',
311 | 'guard_name'=> 'admin'
312 | ],
313 | [
314 | 'id' => 6,
315 | 'parent_id' => 2,
316 | 'uri' => '/menu',
317 | 'name' => '菜单',
318 | 'icon' => '',
319 | 'guard_name'=> 'admin'
320 | ],
321 |
322 | ]);
323 | }
324 |
325 | /**
326 | * @author moell
327 | */
328 | private function associateRolePermissions()
329 | {
330 | $role = Role::first();
331 |
332 | AdminUserFactory::adminUser()->first()->assignRole($role->name);
333 |
334 | foreach ($this->permissions as $permission) {
335 | $role->givePermissionTo($permission['name']);
336 | }
337 | }
338 | }
339 |
--------------------------------------------------------------------------------
/src/Http/Controllers/AdminUserController.php:
--------------------------------------------------------------------------------
1 | adminUserModel = AdminUserFactory::adminUser();
25 | }
26 |
27 | /**
28 | * @author moell
29 | * @param Request $request
30 | * @return AdminUserCollection
31 | */
32 | public function index(Request $request)
33 | {
34 | return new AdminUserCollection($this->adminUserModel->where(request_intersect(['name', 'username']))->paginate());
35 | }
36 |
37 | /**
38 | * @author moell
39 | * @param $id
40 | * @return AdminUserResource
41 | */
42 | public function show($id)
43 | {
44 | return new AdminUserResource($this->adminUserModel->findOrFail($id));
45 | }
46 |
47 | /**
48 | * @author moell
49 | * @param CreateOrUpdateRequest $request
50 | * @return Response
51 | */
52 | public function store(CreateOrUpdateRequest $request)
53 | {
54 | $data = request_intersect([
55 | 'name', 'username', 'password'
56 | ]);
57 | $data['status'] = $request->status ? true : false;
58 | $data['password'] = bcrypt($data['password']);
59 |
60 | $this->adminUserModel->create($data);
61 |
62 | return $this->created();
63 | }
64 |
65 | /**
66 | * @author moell
67 | * @param CreateOrUpdateRequest $request
68 | * @param $id
69 | * @return Response
70 | */
71 | public function update(CreateOrUpdateRequest $request, $id)
72 | {
73 | $adminUser = $this->adminUserModel->findOrFail($id);
74 |
75 | $data = $request->only([
76 | 'name', 'status'
77 | ]);
78 |
79 | if ($request->filled('password')) {
80 | $data['password'] = bcrypt($request->password);
81 | }
82 |
83 | $adminUser->fill($data);
84 | $adminUser->save();
85 |
86 | return $this->noContent();
87 | }
88 |
89 | /**
90 | * @author moell
91 | * @param $id
92 | * @return Response
93 | */
94 | public function destroy($id)
95 | {
96 | $adminUser = $this->adminUserModel->findOrFail($id);
97 |
98 | $adminUser->delete();
99 |
100 | return $this->noContent();
101 | }
102 |
103 | /**
104 | * @author moell
105 | * @param $id
106 | * @param $provider
107 | * @return RoleCollection
108 | */
109 | public function roles($id, $provider)
110 | {
111 | $user = $this->getGuardModel($provider)->findOrFail($id);
112 |
113 | return new RoleCollection($user->roles);
114 | }
115 |
116 | /**
117 | * @param $id
118 | * @param $guard
119 | * @param Request $request
120 | * @return Response
121 | *@author moell
122 | */
123 | public function assignRoles($id, $guard, Request $request)
124 | {
125 | $user = $this->getGuardModel($guard)->findOrFail($id);
126 |
127 | $user->syncRoles($request->input('roles', []));
128 |
129 | return $this->noContent();
130 | }
131 |
132 | /**
133 | * @param $guard
134 | * @return Illuminate\Foundation\Auth\User
135 | */
136 | private function getGuardModel($guard)
137 | {
138 | return app(config('mojito.guards.' . $guard . '.model'));
139 | }
140 | }
141 |
--------------------------------------------------------------------------------
/src/Http/Controllers/CaptchaController.php:
--------------------------------------------------------------------------------
1 |
16 | * @param CaptchaBuilder $captchaBuilder
17 | * @return \Illuminate\Http\JsonResponse
18 | */
19 | public function generate(CaptchaBuilder $captchaBuilder)
20 | {
21 | $key = Str::uuid()->toString();
22 |
23 | $captcha = $captchaBuilder->build();
24 | $expiredAt = Carbon::now()->addMinutes(config("mojito.captcha_cache_ttl", 2));
25 |
26 | Cache::put($key, ['code' => $captcha->getPhrase()], $expiredAt);
27 |
28 | return $this->success([
29 | 'data' => [
30 | 'key' => $key,
31 | 'expired_at' => $expiredAt->toDateTimeString(),
32 | 'image_content' => $captcha->inline()
33 | ]
34 | ]);
35 | }
36 | }
--------------------------------------------------------------------------------
/src/Http/Controllers/ChangePasswordController.php:
--------------------------------------------------------------------------------
1 | old_password, $user->password)) {
22 | return $this->unprocesableEtity([
23 | 'password' => 'Incorrect password'
24 | ]);
25 | }
26 |
27 | $user->password = bcrypt($request->password);
28 | $user->save();
29 |
30 | return $this->noContent();
31 | }
32 | }
--------------------------------------------------------------------------------
/src/Http/Controllers/Controller.php:
--------------------------------------------------------------------------------
1 | guard);
21 |
22 | if (! $config) {
23 | return $this->forbidden("Undefined guard");
24 | }
25 |
26 | $cacheCaptcha = Cache::get($request->captcha_key);
27 | if (! $cacheCaptcha) {
28 | return $this->forbidden('Verification code has expired');
29 | }
30 |
31 | if (strtolower($cacheCaptcha['code']) != strtolower($request->captcha)) {
32 | return $this->forbidden('Please enter correct verify code');
33 | }
34 |
35 | Cache::forget($request->captcha_key);
36 |
37 | $conditions = data_get($config, 'conditions', []);
38 |
39 | $user = app($config['model'])->where(function ($query) use ($config) {
40 | foreach ($config['login_fields'] as $field) {
41 | $query->orWhere($field, request()->get('username'));
42 | }
43 | return $query;
44 | })->when($conditions, function ($query) use ($conditions) {
45 | return $query->where($conditions);
46 | })->first();
47 |
48 | if (! $user || ! Hash::check($request->password, $user->password)) {
49 | throw ValidationException::withMessages([
50 | 'username' => ['The provided credentials are incorrect.'],
51 | ]);
52 | }
53 |
54 | PersonalAccessToken::query()->where("tokenable_type", $config['model'])
55 | ->where("name", $request->guard)
56 | ->where("tokenable_id", $user->id)
57 | ->delete();
58 |
59 | return response()->json([
60 | 'data' => [
61 | 'token' => $user->createToken($request->guard)->plainTextToken,
62 | ]
63 | ]);
64 | }
65 |
66 | /**
67 | * logout
68 | * @return \Illuminate\Http\Response
69 | */
70 | public function logout()
71 | {
72 | Auth::user()->currentAccessToken()->delete();
73 |
74 | return $this->noContent();
75 | }
76 | }
--------------------------------------------------------------------------------
/src/Http/Controllers/MenuController.php:
--------------------------------------------------------------------------------
1 |
16 | * @param Request $request
17 | * @return \Illuminate\Http\JsonResponse
18 | */
19 | public function index(Request $request)
20 | {
21 | $menus = Menu::query()
22 | ->where('guard_name', $request->input('guard_name', 'admin'))
23 | ->orderBy('sequence', 'desc')
24 | ->get();
25 |
26 | return response()->json(['data' => make_tree($menus->toArray())]);
27 | }
28 | /**
29 | * @author moell
30 | * @param CreateOrUpdateRequest $request
31 | * @return \Illuminate\Http\Response
32 | */
33 | public function store(CreateOrUpdateRequest $request)
34 | {
35 | Menu::create($request->all());
36 |
37 | return $this->created();
38 | }
39 |
40 | /**
41 | * @author moell
42 | * @return \Illuminate\Http\JsonResponse
43 | */
44 | public function my(Request $request)
45 | {
46 | $guardName = data_get(Auth::user()->currentAccessToken(), "name", "admin");
47 |
48 | $userPermissions = Auth::user()->getAllPermissions()->pluck('name');
49 | $menus = Menu::query()
50 | ->where('guard_name', $guardName)
51 | ->orderBy('sequence', 'desc')
52 | ->get()
53 | ->filter(function ($item) use ($userPermissions) {
54 | return !$item->permission_name || $userPermissions->contains($item->permission_name);
55 | });
56 |
57 | return response()->json(['data' => make_tree($menus->toArray())]);
58 | }
59 |
60 | /**
61 | * @author moell
62 | * @param CreateOrUpdateRequest $request
63 | * @param $id
64 | * @return \Illuminate\Http\Response
65 | */
66 | public function update(CreateOrUpdateRequest $request, $id)
67 | {
68 | $menu = Menu::query()->findOrFail($id);
69 |
70 | $menu->update($request->toArray());
71 |
72 | return $this->noContent();
73 | }
74 |
75 | /**
76 | * @author moell
77 | * @param $id
78 | * @return MenuResource
79 | */
80 | public function show($id)
81 | {
82 | return new MenuResource(Menu::query()->findOrFail($id));
83 | }
84 |
85 | /**
86 | * @author moell
87 | * @param $id
88 | * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\Response
89 | */
90 | public function destroy($id)
91 | {
92 | $menu = Menu::query()->findOrFail($id);
93 |
94 | if (Menu::query()->where('parent_id', $menu->id)->count()) {
95 | return $this->unprocesableEtity([
96 | 'parent_id' => 'Please delete the submenu first.'
97 | ]);
98 | }
99 |
100 | $menu->delete();
101 |
102 | return $this->noContent();
103 | }
104 | }
--------------------------------------------------------------------------------
/src/Http/Controllers/PermissionController.php:
--------------------------------------------------------------------------------
1 |
18 | * @param Request $request
19 | * @return PermissionCollection
20 | */
21 | public function index(Request $request)
22 | {
23 | $permissions =tap(Permission::latest(), function ($query) {
24 | $query->where(request_intersect([
25 | 'name', 'guard_name', 'pg_id'
26 | ]));
27 | })->with('group')->paginate();
28 |
29 | return new PermissionCollection($permissions);
30 | }
31 |
32 | /**
33 | * @author moell
34 | * @param $id
35 | * @return PermissionResource
36 | */
37 | public function show($id)
38 | {
39 | return new PermissionResource(Permission::query()->findOrFail($id));
40 | }
41 |
42 | /**
43 | * @author moell
44 | * @param CreateOrUpdateRequest $request
45 | * @return \Illuminate\Http\Response
46 | */
47 | public function store(CreateOrUpdateRequest $request)
48 | {
49 | $attributes = $request->only([
50 | 'pg_id', 'name', 'guard_name', 'display_name', 'icon', 'sequence', 'description'
51 | ]);
52 | $attributes['created_name'] = Auth::user()->name;
53 |
54 | Permission::create($attributes);
55 |
56 | return $this->created();
57 | }
58 |
59 | /**
60 | * @author moell
61 | * @param CreateOrUpdateRequest $request
62 | * @param $id
63 | * @return \Illuminate\Http\Response
64 | */
65 | public function update(CreateOrUpdateRequest $request, $id)
66 | {
67 | $permission = Permission::query()->findOrFail($id);
68 |
69 | $attributes = $request->only([
70 | 'pg_id', 'name', 'guard_name', 'display_name', 'icon', 'sequence', 'description'
71 | ]);
72 |
73 | $attributes['updated_name'] = Auth::user()->name;
74 |
75 | $isset = Permission::query()
76 | ->where(['name' => $attributes['name'], 'guard_name' => $attributes['guard_name']])
77 | ->where('id', '!=', $id)
78 | ->count();
79 |
80 | if ($isset) {
81 | throw PermissionAlreadyExists::create($attributes['name'], $attributes['guard_name']);
82 | }
83 |
84 | $permission->update($attributes);
85 |
86 | return $this->noContent();
87 | }
88 |
89 | /**
90 | * @author moell
91 | * @param $id
92 | * @return \Illuminate\Http\Response
93 | */
94 | public function destroy($id)
95 | {
96 | permission::query()->findOrFail($id)->delete();
97 |
98 | return $this->noContent();
99 | }
100 |
101 | /**
102 | * @author moell
103 | * @return \Illuminate\Http\JsonResponse
104 | */
105 | public function allUserPermission()
106 | {
107 | return response()->json(['data' => Auth::user()->getAllPermissions()->pluck('name')]);
108 | }
109 | }
--------------------------------------------------------------------------------
/src/Http/Controllers/PermissionGroupController.php:
--------------------------------------------------------------------------------
1 |
17 | * @param Request $request
18 | * @return PermissionGroupCollection
19 | */
20 | public function index(Request $request)
21 | {
22 | $permissionGroups = tap(PermissionGroup::latest(), function ($query) {
23 | $query->where(request_intersect(['name']));
24 | })->paginate();
25 |
26 | return new PermissionGroupCollection($permissionGroups);
27 | }
28 |
29 | /**
30 | * @author moell
31 | * @param Request $request
32 | * @return PermissionGroupCollection
33 | */
34 | public function all(Request $request)
35 | {
36 | $permissionGroups = PermissionGroup::latest()->get();
37 |
38 | return new PermissionGroupCollection($permissionGroups);
39 | }
40 |
41 | /**
42 | * @param $guardName
43 | * @return \Illuminate\Http\JsonResponse
44 | */
45 | public function guardNameForPermissions($guardName)
46 | {
47 | $permissionGroups = PermissionGroup::query()
48 | ->with(['permission' => function ($query) use ($guardName) {
49 | $query->where('guard_name', $guardName);
50 | }])
51 | ->get()->filter(function($item) {
52 | return count($item->permission) > 0;
53 | });
54 |
55 | return response()->json([
56 | 'data' => array_values($permissionGroups->toArray())
57 | ]);
58 | }
59 |
60 | /**
61 | * @author moell
62 | * @param CreateOrUpdateRequest $request
63 | * @return \Illuminate\Http\Response
64 | */
65 | public function store(CreateOrUpdateRequest $request)
66 | {
67 | PermissionGroup::create(request_intersect(['name']));
68 |
69 | return $this->created();
70 | }
71 |
72 | /**
73 | * @author moell
74 | * @param $id
75 | * @return PermissionGroupResource
76 | */
77 | public function show($id)
78 | {
79 | return new PermissionGroupResource(PermissionGroup::findOrFail($id));
80 | }
81 |
82 | /**
83 | * @author moell
84 | * @param CreateOrUpdateRequest $request
85 | * @param $id
86 | * @return \Illuminate\Http\Response
87 | */
88 | public function update(CreateOrUpdateRequest $request, $id)
89 | {
90 | PermissionGroup::findOrFail($id)->update(request_intersect([
91 | 'name'
92 | ]));
93 |
94 | return $this->noContent();
95 | }
96 |
97 | /**
98 | * @param $id
99 | * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\Response
100 | */
101 | public function destroy($id)
102 | {
103 | $permissionGroup = PermissionGroup::findOrFail($id);
104 |
105 | if (Permission::query()->where('pg_id', $permissionGroup->id)->count()) {
106 | return $this->unprocesableEtity([
107 | 'pg_id' => 'Please move or delete the vesting permission.'
108 | ]);
109 | }
110 |
111 | $permissionGroup->delete();
112 |
113 | return $this->noContent();
114 | }
115 | }
--------------------------------------------------------------------------------
/src/Http/Controllers/RoleController.php:
--------------------------------------------------------------------------------
1 |
18 | * @param Request $request
19 | * @return RoleCollection
20 | */
21 | public function index(Request $request)
22 | {
23 | return new RoleCollection(Role::query()->where(request_intersect(['name']))->paginate());
24 | }
25 |
26 | /**
27 | * @author moell
28 | * @param $guardName
29 | * @return RoleCollection
30 | */
31 | public function guardNameRoles($guardName)
32 | {
33 | return new RoleCollection(Role::query()->where('guard_name', $guardName)->get());
34 | }
35 |
36 | public function show($id)
37 | {
38 | return new RoleResource(Role::query()->findOrFail($id));
39 | }
40 |
41 | /**
42 | * @author moell
43 | * @param CreateOrUpdateRequest $request
44 | * @return \Illuminate\Http\Response
45 | */
46 | public function store(CreateOrUpdateRequest $request)
47 | {
48 | Role::create(request_intersect([
49 | 'name', 'guard_name', 'description'
50 | ]));
51 |
52 | return $this->created();
53 | }
54 |
55 | /**
56 | * @author moell
57 | * @param CreateOrUpdateRequest $request
58 | * @param $id
59 | * @return \Illuminate\Http\Response
60 | */
61 | public function update(CreateOrUpdateRequest $request, $id)
62 | {
63 | if (Role::where(request_intersect(['name', 'guard_name']))->where('id', '!=', $id)->count()) {
64 | throw RoleAlreadyExists::create($request->name, $request->guard_name);
65 | }
66 |
67 | $role = Role::query()->findOrFail($id);
68 |
69 | $role->update(request_intersect([
70 | 'name', 'guard_name', 'description'
71 | ]));
72 |
73 | return $this->noContent();
74 | }
75 |
76 | /**
77 | * @author moell
78 | * @param $id
79 | * @return \Illuminate\Http\Response
80 | */
81 | public function destroy($id)
82 | {
83 | Role::destroy($id);
84 |
85 | return $this->noContent();
86 | }
87 |
88 | /**
89 | * @author moell
90 | * @param $id
91 | * @return PermissionCollection
92 | */
93 | public function permissions($id)
94 | {
95 | $role = Role::query()->findOrFail($id);
96 |
97 | return new PermissionCollection($role->permissions);
98 | }
99 |
100 | /**
101 | * Assign permission
102 | *
103 | * @author moell
104 | * @param $id
105 | * @param Request $request
106 | * @return \Illuminate\Http\Response
107 | */
108 | public function assignPermissions($id, Request $request)
109 | {
110 | $role = Role::query()->findOrFail($id);
111 |
112 | $role->syncPermissions($request->input('permissions', []));
113 |
114 | return $this->noContent();
115 | }
116 | }
--------------------------------------------------------------------------------
/src/Http/Middleware/Authenticate.php:
--------------------------------------------------------------------------------
1 |
13 | * @param $request
14 | * @param \Closure $next
15 | * @return mixed
16 | */
17 | public function handle($request, \Closure $next)
18 | {
19 | $permission = Route::currentRouteName();
20 |
21 | if (Auth::user()->hasPermissionTo($permission)) {
22 | return $next($request);
23 | }
24 |
25 | throw UnauthorizedException::forPermissions([$permission]);
26 | }
27 | }
--------------------------------------------------------------------------------
/src/Http/MojitoResponse.php:
--------------------------------------------------------------------------------
1 |
13 | * @param string $content
14 | * @return Response
15 | */
16 | protected function created($content = '')
17 | {
18 | return new Response($content, Response::HTTP_CREATED);
19 | }
20 |
21 | /**
22 | * 202
23 | *
24 | * @author moell
25 | * @return Response
26 | */
27 | protected function accepted()
28 | {
29 | return new Response('', Response::HTTP_ACCEPTED);
30 | }
31 |
32 | /**
33 | * 204
34 | *
35 | * @author moell
36 | * @return Response
37 | */
38 | protected function noContent()
39 | {
40 | return new Response('', Response::HTTP_NO_CONTENT);
41 | }
42 |
43 | /**
44 | * 400
45 | *
46 | * @author moell
47 | * @param $message
48 | * @param array $headers
49 | * @param int $options
50 | * @return \Illuminate\Http\JsonResponse
51 | */
52 | protected function badRequest($message, array $headers = [], $options = 0)
53 | {
54 | return response()->json([
55 | 'message' => $message
56 | ], Response::HTTP_BAD_REQUEST, $headers, $options);
57 | }
58 |
59 | /**
60 | * 401
61 | *
62 | * @author moell
63 | * @param string $message
64 | * @param array $headers
65 | * @param int $options
66 | * @return \Illuminate\Http\JsonResponse
67 | */
68 | protected function unauthorized($message = '', array $headers = [], $options = 0)
69 | {
70 | return response()->json([
71 | 'message' => $message ? $message : 'Token Signature could not be verified.'
72 | ], Response::HTTP_UNAUTHORIZED, $headers, $options);
73 | }
74 |
75 | /**
76 | * 403
77 | *
78 | * @author moell
79 | * @param string $message
80 | * @param array $headers
81 | * @param int $options
82 | * @return \Illuminate\Http\JsonResponse
83 | */
84 | protected function forbidden($message = '', array $headers = [], $options = 0)
85 | {
86 | return response()->json([
87 | 'message' => $message ? $message : 'Insufficient permissions.'
88 | ], Response::HTTP_FORBIDDEN, $headers, $options);
89 | }
90 |
91 | /**
92 | * 422
93 | *
94 | * @author moell
95 | * @param array $errors
96 | * @param array $headers
97 | * @param string $message
98 | * @param int $options
99 | * @return \Illuminate\Http\JsonResponse
100 | */
101 | protected function unprocesableEtity(array $errors = [], array $headers = [], $message = '', $options = 0)
102 | {
103 | return response()->json([
104 | 'message' => $message ? $message : '422 Unprocessable Entity',
105 | 'errors' => $errors
106 | ], Response::HTTP_UNPROCESSABLE_ENTITY, $headers, $options);
107 | }
108 |
109 | /**
110 | * 200
111 | *
112 | * @author moell
113 | * @param array $data
114 | * @param array $headers
115 | * @param int $options
116 | * @return \Illuminate\Http\JsonResponse
117 | */
118 | protected function success(array $data, array $headers = [], $options = 0)
119 | {
120 | return response()->json($data, Response::HTTP_OK, $headers, $options);
121 | }
122 | }
--------------------------------------------------------------------------------
/src/Http/Requests/AdminUser/CreateOrUpdateRequest.php:
--------------------------------------------------------------------------------
1 |
25 | * @return array
26 | */
27 | public function rules()
28 | {
29 | $rules = [
30 | 'name' => 'required|max:255'
31 | ];
32 |
33 | switch ($this->method()) {
34 | case 'POST':
35 | $rules['password'] = 'required|min:6|max:32';
36 | $rules['username'] = 'required|unique:' . AdminUserFactory::adminUser()->getTable();
37 | break;
38 | case 'PATCH':
39 | $rules['password'] = 'nullable|min:8|max:32';
40 | break;
41 | }
42 |
43 | return $rules;
44 | }
45 | }
--------------------------------------------------------------------------------
/src/Http/Requests/ChangePasswordRequest.php:
--------------------------------------------------------------------------------
1 |
24 | * @return array
25 | */
26 | public function rules()
27 | {
28 | return [
29 | 'old_password' => 'required|min:6|max:32',
30 | 'password' => 'required|min:8|max:32|confirmed',
31 | 'password_confirmation' => 'required|min:8|max:32'
32 | ];
33 | }
34 | }
--------------------------------------------------------------------------------
/src/Http/Requests/Menu/CreateOrUpdateRequest.php:
--------------------------------------------------------------------------------
1 |
24 | * @return array
25 | */
26 | public function rules()
27 | {
28 | return [
29 | 'parent_id' => 'required|numeric',
30 | 'name' => 'required',
31 | 'guard_name' => 'required',
32 | 'is_link' => 'in:0,1',
33 | 'uri' => 'required'
34 | ];
35 | }
36 | }
--------------------------------------------------------------------------------
/src/Http/Requests/Permission/CreateOrUpdateRequest.php:
--------------------------------------------------------------------------------
1 |
25 | * @return array
26 | */
27 | public function rules()
28 | {
29 | $rules = [
30 | 'name' => 'required|max:255',
31 | 'guard_name' => 'required|max:255',
32 | 'display_name' => 'required:max:50',
33 | 'pg_id' => 'required|numeric',
34 | 'sequence' => 'numeric'
35 | ];
36 |
37 | return $rules;
38 | }
39 | }
--------------------------------------------------------------------------------
/src/Http/Requests/PermissionGroup/CreateOrUpdateRequest.php:
--------------------------------------------------------------------------------
1 |
24 | * @return array
25 | */
26 | public function rules()
27 | {
28 | $rules = [
29 | 'name' => 'required|max:255'
30 | ];
31 |
32 | return $rules;
33 | }
34 | }
--------------------------------------------------------------------------------
/src/Http/Requests/Role/CreateOrUpdateRequest.php:
--------------------------------------------------------------------------------
1 |
24 | * @return array
25 | */
26 | public function rules()
27 | {
28 | $rules = [
29 | 'name' => 'required|max:255',
30 | 'guard_name' => 'required|max:255'
31 | ];
32 |
33 | return $rules;
34 | }
35 | }
--------------------------------------------------------------------------------
/src/Models/AdminUser.php:
--------------------------------------------------------------------------------
1 | belongsTo(PermissionGroup::class, 'pg_id');
11 | }
12 | }
--------------------------------------------------------------------------------
/src/Models/PermissionGroup.php:
--------------------------------------------------------------------------------
1 | hasMany('Moell\Mojito\Models\Permission', 'pg_id');
15 | }
16 | }
--------------------------------------------------------------------------------
/src/Models/User.php:
--------------------------------------------------------------------------------
1 | guard_name;
21 | }
22 |
23 | }
--------------------------------------------------------------------------------
/src/Providers/MojitoServiceProvider.php:
--------------------------------------------------------------------------------
1 | app->runningInConsole()) {
20 | $this->registerMigrations();
21 |
22 | $this->commands([
23 | InstallCommand::class,
24 | ]);
25 |
26 | $this->publishes([
27 | __DIR__.'/../../config/mojito.php' => config_path('mojito.php'),
28 | ], 'config');
29 | }
30 |
31 | $this->registerRouter();
32 | }
33 |
34 | /**
35 | * Register any application services.
36 | *
37 | * @return void
38 | */
39 | public function register()
40 | {
41 | //
42 | }
43 |
44 | private function registerMigrations()
45 | {
46 | $migrationsPath = __DIR__ . '/../../database/migrations/';
47 |
48 | $items = [
49 | 'create_admin_table.php',
50 | 'add_custom_field_permission_tables.php',
51 | 'create_menu_table.php',
52 | 'create_permission_group_table.php'
53 | ];
54 |
55 | $paths = [];
56 | foreach ($items as $key => $name) {
57 | $paths[$migrationsPath . $name] = database_path('migrations') . "/". $this->formatTimestamp($key+1) . '_' . $name;
58 | }
59 |
60 | $this->publishes($paths, 'migrations');
61 | }
62 |
63 | /**
64 | * @param $addition
65 | * @return false|string
66 | */
67 | private function formatTimestamp($addition)
68 | {
69 | return date('Y_m_d_His', time() + $addition);
70 | }
71 |
72 | /**
73 | * 注册路由
74 | *
75 | * @author moell
76 | */
77 | private function registerRouter()
78 | {
79 | if (strpos($this->app->version(), 'Lumen') === false && !$this->app->routesAreCached()) {
80 | app('router')->middleware('api')->group(__DIR__.'/../routes.php');
81 | } else {
82 | require __DIR__.'/../routes.php';
83 | }
84 | }
85 | }
--------------------------------------------------------------------------------
/src/Resources/AdminUser.php:
--------------------------------------------------------------------------------
1 | $this->id,
14 | 'name' => $this->name,
15 | 'username' => $this->username,
16 | 'status' => $this->status ? true : false,
17 | 'created_at' => (string)$this->created_at,
18 | 'updated_at' => (string)$this->updated_at
19 | ];
20 | }
21 | }
--------------------------------------------------------------------------------
/src/Resources/AdminUserCollection.php:
--------------------------------------------------------------------------------
1 | $this->collection
14 | ];
15 | }
16 | }
--------------------------------------------------------------------------------
/src/Resources/Menu.php:
--------------------------------------------------------------------------------
1 | $this->id,
14 | 'name' => $this->name,
15 | 'guard_name' => $this->guard_name,
16 | 'icon' => $this->icon,
17 | 'uri' => $this->uri,
18 | 'is_link' => $this->is_link,
19 | 'created_at' => (string)$this->created_at,
20 | 'updated_at' => (string)$this->updated_at
21 | ];
22 | }
23 | }
--------------------------------------------------------------------------------
/src/Resources/Permission.php:
--------------------------------------------------------------------------------
1 | $this->id,
14 | 'pg_id' => $this->pg_id,
15 | 'name' => $this->name,
16 | 'guard_name' => $this->guard_name,
17 | 'display_name' => $this->display_name,
18 | 'group' => new PermissionGroup($this->group),
19 | 'icon' => $this->icon,
20 | 'sequence' => $this->sequence,
21 | 'description' => $this->description,
22 | 'created_name' => $this->created_name,
23 | 'updated_name' => $this->updated_name,
24 | 'created_at' => (string)$this->created_at,
25 | 'updated_at' => (string)$this->created_at
26 | ];
27 | }
28 | }
--------------------------------------------------------------------------------
/src/Resources/PermissionCollection.php:
--------------------------------------------------------------------------------
1 | $this->collection
14 | ];
15 | }
16 | }
--------------------------------------------------------------------------------
/src/Resources/PermissionGroup.php:
--------------------------------------------------------------------------------
1 | $this->id,
14 | 'name' => $this->name,
15 | 'created_at' => (string)$this->created_at,
16 | 'updated_at' => (string)$this->updated_at
17 | ];
18 | }
19 | }
--------------------------------------------------------------------------------
/src/Resources/PermissionGroupCollection.php:
--------------------------------------------------------------------------------
1 | $this->collection
14 | ];
15 | }
16 | }
--------------------------------------------------------------------------------
/src/Resources/Role.php:
--------------------------------------------------------------------------------
1 | $this->id,
14 | 'name' => $this->name,
15 | 'guard_name' => $this->guard_name,
16 | 'description' => $this->description,
17 | 'created_at' => (string)$this->created_at,
18 | 'updated_at' => (string)$this->updated_at
19 | ];
20 | }
21 | }
--------------------------------------------------------------------------------
/src/Resources/RoleCollection.php:
--------------------------------------------------------------------------------
1 | $this->collection
14 | ];
15 | }
16 | }
--------------------------------------------------------------------------------
/src/helpers.php:
--------------------------------------------------------------------------------
1 | only(is_array($keys) ? $keys : func_get_args()));
12 | }
13 | }
14 |
15 | if (!function_exists('make_tree')) {
16 | /**
17 | * @param array $list
18 | * @param int $parentId
19 | * @return array
20 | */
21 | function make_tree(array $list, $parentId = 0) {
22 | $tree = [];
23 | if (empty($list)) {
24 | return $tree;
25 | }
26 |
27 | $newList = [];
28 | foreach ($list as $k => $v) {
29 | $newList[$v['id']] = $v;
30 | }
31 |
32 | foreach ($newList as $value) {
33 | if ($parentId == $value['parent_id']) {
34 | $tree[] = &$newList[$value['id']];
35 | } elseif (isset($newList[$value['parent_id']])) {
36 | $newList[$value['parent_id']]['children'][] = &$newList[$value['id']];
37 | }
38 | }
39 |
40 | return $tree;
41 | }
42 | }
--------------------------------------------------------------------------------
/src/routes.php:
--------------------------------------------------------------------------------
1 | namespace('\Moell\Mojito\Http\Controllers')
6 | ->prefix(config("mojito.route_prefix", "api"))
7 | ->middleware(config("mojito.middleware.basic", "api"))
8 | ->group(function ($router) {
9 | $router->post("auth/login", "LoginController@authenticate");
10 |
11 | $router->get("/captcha", "CaptchaController@generate");
12 |
13 | $router->middleware(config("mojito.middleware.auth", ['auth:sanctum']))->group(function ($router) {
14 | $router->post("auth/logout", "LoginController@logout")->name("auth.logout");
15 | $router->get('permission-user-all', 'PermissionController@allUserPermission')->name("permission.all-user-permission");
16 | $router->get('my-menu', 'MenuController@my')->name("menu.my");
17 | $router->patch('user-change-password', 'ChangePasswordController@changePassword')->name("user.change-password");
18 | });
19 |
20 |
21 | $router->middleware(config("mojito.middleware.permission", ['auth:sanctum', 'mojito.permission']))
22 | ->group(function ($router) {
23 | $router->apiResources([
24 | 'role' => 'RoleController',
25 | 'permission' => 'PermissionController',
26 | 'admin-user' => 'AdminUserController',
27 | 'permission-group' => 'PermissionGroupController',
28 | 'menu' => 'MenuController',
29 | ]);
30 |
31 | $router->get('role/{id}/permissions', 'RoleController@permissions')->name('role.permissions');
32 | $router->put('role/{id}/permissions', 'RoleController@assignPermissions')->name('role.assign-permissions');
33 | $router->get('guard-name-roles/{guardName}', 'RoleController@guardNameRoles')->name('role.guard-name-roles');
34 | $router->get('admin-user/{id}/roles/{guard}', 'AdminUserController@roles')->name('admin-user.roles');
35 | $router->put('admin-user/{id}/roles/{guard}', 'AdminUserController@assignRoles')->name('admin-user.assign-roles');
36 | $router->get('guard-name-for-permissions/{guardName}', 'PermissionGroupController@guardNameForPermissions')
37 | ->name('permission-group.guard-name-for-permission');
38 | $router->get("permission-group-all", "PermissionGroupController@all")->name("permission-group.all");
39 | });
40 | });
41 |
--------------------------------------------------------------------------------