├── .gitattributes
├── .gitignore
├── README.md
├── composer.json
└── src
├── Commands
└── SimplePassportConfiguration.php
├── Core
├── Paginator.php
├── PartialList.php
├── UserProfiles.php
└── UserServices.php
├── Http
├── Controllers
│ ├── ProfileController.php
│ └── RoleController.php
└── Middleware
│ └── RoleMiddleware.php
├── Rules
├── ProfileExists.php
└── RoleExists.php
├── SecurityStarterServiceProvider.php
├── config
└── security-starter.php
├── database
└── migrations
│ ├── 2019_02_22_150438_create_profile_table.php
│ ├── 2019_02_22_150448_create_role_table.php
│ ├── 2019_02_22_150500_create_profile_role_table.php
│ └── 2019_02_22_150512_create_user_profiles_table.php
├── models
├── Profile.php
└── Role.php
└── routes
└── api.php
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto
2 | *.css linguist-vendored
3 | *.scss linguist-vendored
4 | *.js linguist-vendored
5 | CHANGELOG.md export-ignore
6 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /.idea
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
Due to a time constraint, unfortunately this repository is no longer maintained.
2 |
3 | Security-Starter is a ready to use package that provide to you a complete CRUD REST system for a User/Profile/Role architecture, and also provide a middleware to specify roles that the user must have to access your routes, and it's based on the **heloufir/simple-passport** package that offers to you a **forgot password** system, you can refer to this [link](https://github.com/heloufir/simple-passport) to know more about this package.
4 |
5 | 
6 |
7 | # A full implementation
8 |
9 | You can find a complete implementation of this repository in [Ngx Security Starter](https://github.com/heloufir/ngx-security-starter)
10 |
11 | # Installation
12 |
13 | composer require heloufir/security-starter
14 |
15 | # Configuration
16 |
17 | **Method 1.** You can configure this package automatically, by using the command `php artisan starter:config` (if you want to configure it manually, go to **Method 2**)
18 | When executing this command you will be asked to answer some questions, and at the very end you will need to complete 3 steps manually :
19 |
20 | - Add Laravel\Passport\HasApiTokens trait to the User model
21 |
22 | ```php
23 | \Heloufir\SecurityStarter\Http\Middleware\RoleMiddleware::class` to the $routeMiddleware in Kernel
56 |
57 | **File: app/Http/Kernel.php**
58 | ```php
59 | protected $routeMiddleware = [
60 | // ...
61 | 'roles' => \Heloufir\SecurityStarter\Http\Middleware\RoleMiddleware::class
62 | ];
63 | ```
64 |
65 | **Method 2.** (Manual configuration)
66 |
67 | First, you need to publish the **heloufir/simple-passport**:
68 |
69 | php artisan vendor:publish --provider=Heloufir\SimplePassport\SimplePassportServiceProvider
70 |
71 | After, you need to publish the **heloufir/security-starter**:
72 |
73 | php artisan vendor:publish --provider=Heloufir\SecurityStarter\SecurityStarterServiceProvider
74 |
75 | Then, if you want to customize the **profiles**, **roles**, **profile_roles** and **user_profiles** tables you need first to update the file **config/security-starter.php**, then go to next step.
76 |
77 | Launch migrations to add **laravel/passport** tables and **heloufir/security-starter** tables:
78 |
79 | php artisan migrate
80 |
81 | Then, install **laravel/passport** oauth clients, by executing:
82 |
83 | php artisan passport:install
84 |
85 | Add Laravel\Passport\HasApiTokens trait to the User model
86 |
87 | ```php
88 | \Heloufir\SecurityStarter\Http\Middleware\RoleMiddleware::class` to the $routeMiddleware in Kernel
121 |
122 | **File: app/Http/Kernel.php**
123 | ```php
124 | protected $routeMiddleware = [
125 | // ...
126 | 'roles' => \Heloufir\SecurityStarter\Http\Middleware\RoleMiddleware::class
127 | ];
128 | ```
129 |
130 | > Don't forget to update the guards in your **auth.php** configuration file for the `api` to **passport**
131 |
132 | ```php
133 | 'guards' => [
134 | 'web' => [
135 | 'driver' => 'session',
136 | 'provider' => 'users',
137 | ],
138 |
139 | 'api' => [
140 | 'driver' => 'passport', // <- Here
141 | 'provider' => 'users',
142 | ],
143 | ],
144 | ```
145 |
146 | That's all, the installation and configuration of **security-starter** is done.
147 |
148 | You can check the [wiki](https://github.com/heloufir/security-starter/wiki) for more information about this package.
149 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "heloufir/security-starter",
3 | "description": "Seucirty starter is a full implementation of laravel/passport and heloufir/simple-passport, containing all the implementations of the authentication and forgot password systems, which allows you to start your project from a good foundation, and only worry about the business logic of your application.",
4 | "type": "package",
5 | "require": {
6 | "heloufir/simple-passport": "^1.0"
7 | },
8 | "license": "MIT",
9 | "authors": [
10 | {
11 | "name": "EL OUFIR Hatim",
12 | "email": "eloufirhatim@gmail.com"
13 | }
14 | ],
15 | "extra": {
16 | "laravel": {
17 | "providers": [
18 | "Heloufir\\SecurityStarter\\SecurityStarterServiceProvider"
19 | ]
20 | }
21 | },
22 | "autoload": {
23 | "psr-4": {
24 | "Heloufir\\SecurityStarter\\": "src/"
25 | }
26 | },
27 | "minimum-stability": "dev",
28 | "prefer-stable" : true
29 | }
30 |
--------------------------------------------------------------------------------
/src/Commands/SimplePassportConfiguration.php:
--------------------------------------------------------------------------------
1 | option('trust')) {
40 | $this->step();
41 | } else {
42 | if ($this->confirm('You wan\'t to publish the SimplePassport provider?')) {
43 | $this->step(1);
44 | }
45 | if ($this->confirm('You wan\'t to publish the SecurityStarter provider?')) {
46 | $this->step(2);
47 | }
48 | if ($this->confirm('You wan\'t to customize SecurityStarter tables names?')) {
49 | $this->step(3);
50 | }
51 | if ($this->confirm('You wan\'t to migrate laravel/passport and heloufir/simple-passport migrations?')) {
52 | try {
53 | $this->step(4);
54 | } catch (\Exception $e) {
55 | $this->error($e->getMessage());
56 | $this->line('');
57 | $this->error('>>>>>> Please fix the above error, and execute the starter:config command again!');
58 | $this->line('');
59 | return false;
60 | }
61 | }
62 | if ($this->confirm('You wan\'t to install laravel/passport keys?')) {
63 | $this->step(5);
64 | }
65 | }
66 | $this->line('');
67 | $this->line('***************************************************************************************************************************');
68 | $this->line('Almost Done! You still need to do the following steps:');
69 | $this->line('');
70 | $this->line(' 1. Add Laravel\Passport\HasApiTokens trait to the User model');
71 | $this->line(' 2. Add Heloufir\SecurityStarter\Core\UserProfiles trait to the User model');
72 | $this->line(' 3. Add \'roles\' => \Heloufir\SecurityStarter\Http\Middleware\RoleMiddleware::class to the $routeMiddleware in Kernel');
73 | $this->line('***************************************************************************************************************************');
74 | $this->line('');
75 | return true;
76 | }
77 |
78 | /**
79 | * Configuration steps
80 | *
81 | * @param int $step
82 | * The configuration step to do
83 | * >> Default value is -1, in this case all steps are executed
84 | *
85 | * @author EL OUFIR Hatim
86 | */
87 | private function step(int $step = -1)
88 | {
89 | switch ($step) {
90 | case 1:
91 | $this->call('vendor:publish', [
92 | '--provider' => 'Heloufir\SimplePassport\SimplePassportServiceProvider'
93 | ]);
94 | $this->call('config:cache');
95 | break;
96 | case 2:
97 | $this->call('vendor:publish', [
98 | '--provider' => 'Heloufir\SecurityStarter\SecurityStarterServiceProvider'
99 | ]);
100 | $this->call('config:cache');
101 | break;
102 | case 3:
103 | $profiles = $this->ask('Name of the "profiles" table? (default: ' . config('security-starter.tables.profiles') . ')') ?? config('security-starter.tables.profiles');
104 | $roles = $this->ask('Name of the "roles" table? (default: ' . config('security-starter.tables.roles') . ')') ?? config('security-starter.tables.roles');
105 | $profileRole = $this->ask('Name of the "profile_roles" table? (default: ' . config('security-starter.tables.associations.profile_roles') . ')') ?? config('security-starter.tables.associations.profile_roles');
106 | $userProfiles = $this->ask('Name of the "user_profiles" table? (default: ' . config('security-starter.tables.associations.user_profiles') . ')') ?? config('security-starter.tables.associations.user_profiles');
107 | $this->updateConfigFile('security-starter.tables.profiles', $profiles);
108 | $this->updateConfigFile('security-starter.tables.roles', $roles);
109 | $this->updateConfigFile('security-starter.tables.associations.profile_roles', $profileRole);
110 | $this->updateConfigFile('security-starter.tables.associations.user_profiles', $userProfiles);
111 | $this->call('config:cache');
112 | break;
113 | case 4:
114 | $this->call('migrate');
115 | break;
116 | case 5:
117 | $this->call('passport:install');
118 | break;
119 | case -1:
120 | $this->step(1);
121 | $this->step(2);
122 | $this->step(4);
123 | $this->step(5);
124 | break;
125 | default:
126 | break;
127 | }
128 | }
129 |
130 | /**
131 | * Update configuration file
132 | *
133 | * @param string $old
134 | * The old value to update
135 | * @param string $new
136 | * The new value to set
137 | *
138 | * @author EL OUFIR Hatim
139 | */
140 | private function updateConfigFile(string $old, string $new)
141 | {
142 | $content = file_get_contents(config_path('security-starter.php'));
143 | $search = '/\=\>\s*\'' . config($old) . '\'\,/m';
144 | $replace = '=> \'' . $new . '\',';
145 | $content = preg_replace($search, $replace, $content);
146 | file_put_contents(config_path('security-starter.php'), $content);
147 | }
148 | }
149 |
--------------------------------------------------------------------------------
/src/Core/Paginator.php:
--------------------------------------------------------------------------------
1 |
22 | */
23 | public static function paginate(Builder $builder, Request $request = null): array
24 | {
25 | if ($request != null && $request->has('size')) {
26 | $count = $builder->count();
27 | $size = $request->size;
28 | $page = 1;
29 | if ($request->has('page')) {
30 | $page = $request->page;
31 | }
32 | $builder
33 | ->skip(($page - 1) * $size)
34 | ->take($size);
35 | $result = new PartialList($builder->get(), $count, $page, $size);
36 | } else {
37 | $result = new PartialList($builder->get(), $builder->count(), 1, $builder->count());
38 | }
39 | return $result->toArray();
40 | }
41 |
42 | }
--------------------------------------------------------------------------------
/src/Core/PartialList.php:
--------------------------------------------------------------------------------
1 |
51 | */
52 | public function __construct(Collection $data, int $count, int $page, int $size)
53 | {
54 | $this->data = $data;
55 | $this->count = $count;
56 | $this->page = $page;
57 | $this->size = $size;
58 | }
59 |
60 | /**
61 | * Return an array containing the partial list information
62 | *
63 | * @return array
64 | *
65 | * @author EL OUFIR Hatim
66 | */
67 | public function toArray(): array
68 | {
69 | return [
70 | 'data' => $this->data,
71 | 'count' => $this->count,
72 | 'page' => $this->page,
73 | 'size' => $this->size
74 | ];
75 | }
76 |
77 | }
--------------------------------------------------------------------------------
/src/Core/UserProfiles.php:
--------------------------------------------------------------------------------
1 |
15 | */
16 | public function profiles()
17 | {
18 | return $this->belongsToMany(Profile::class, config('security-starter.tables.associations.user_profiles'), 'refUser', 'refProfile');
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/src/Core/UserServices.php:
--------------------------------------------------------------------------------
1 |
20 | */
21 | public function attacheProfilesToUser(int $user, array $profiles)
22 | {
23 | DB::table(config('security-starter.tables.associations.user_profiles'))
24 | ->where('refUser', $user)
25 | ->delete();
26 | foreach ($profiles as $profile) {
27 | DB::table(config('security-starter.tables.associations.user_profiles'))
28 | ->insert([
29 | 'refUser' => $user,
30 | 'refProfile' => $profile
31 | ]);
32 | }
33 | }
34 |
35 | }
--------------------------------------------------------------------------------
/src/Http/Controllers/ProfileController.php:
--------------------------------------------------------------------------------
1 |
27 | */
28 | public function index(Request $request): JsonResponse
29 | {
30 | $query = Profile::query();
31 | $query->with(['roles']);
32 | return response()->json(self::paginate($query, $request), 200);
33 | }
34 |
35 | /**
36 | * Store a newly created resource in storage.
37 | *
38 | * @param Request $request
39 | * The request object
40 | *
41 | * @return JsonResponse
42 | *
43 | * @author EL OUFIR Hatim
44 | */
45 | public function store(Request $request): JsonResponse
46 | {
47 | $rules = [
48 | 'code' => [
49 | 'required',
50 | 'max:255',
51 | 'unique:' . config('security-starter.tables.profiles') . ',code'
52 | ],
53 | 'designation' => [
54 | 'required',
55 | 'max:255'
56 | ],
57 | 'roles' => [
58 | 'array'
59 | ]
60 | ];
61 | $validator = Validator::make($request->all(), $rules);
62 | if ($validator->fails()) {
63 | return response()->json(collect($validator->getMessageBag())->flatten()->toArray(), 403);
64 | }
65 | $profile = new Profile();
66 | $profile->code = $request->get('code');
67 | $profile->designation = $request->get('designation');
68 | $profile->save();
69 | if ($request->has('roles')) {
70 | foreach ($request->get('roles') as $role) {
71 | DB::table(config('security-starter.tables.associations.profile_roles'))
72 | ->insert([
73 | 'refProfile' => $profile->id,
74 | 'refRole' => $role
75 | ]);
76 | }
77 | }
78 | return response()->json(Profile::where('id', $profile->id)->with(['roles'])->first(), 200);
79 | }
80 |
81 | /**
82 | * Display the specified resource.
83 | *
84 | * @param int $id
85 | * The profile id
86 | *
87 | * @return JsonResponse
88 | *
89 | * @author EL OUFIR Hatim
90 | */
91 | public function show($id): JsonResponse
92 | {
93 | $query = Profile::query();
94 | $query->where('id', $id);
95 | $query->with(['roles']);
96 | return response()->json($query->first(), $query->count() == 0 ? 404 : 200);
97 | }
98 |
99 | /**
100 | * Update the specified resource in storage.
101 | *
102 | * @param Request $request
103 | * The request object
104 | * @param int $id
105 | * The profile id
106 | *
107 | * @return JsonResponse
108 | */
109 | public function update(Request $request, $id): JsonResponse
110 | {
111 | $rules = [
112 | 'code' => [
113 | 'required',
114 | 'max:255',
115 | new ProfileExists($id),
116 | 'unique:' . config('security-starter.tables.profiles') . ',code,' . $id
117 | ],
118 | 'designation' => [
119 | 'required',
120 | 'max:255'
121 | ],
122 | 'roles' => [
123 | 'array'
124 | ]
125 | ];
126 | $validator = Validator::make($request->all(), $rules);
127 | if ($validator->fails()) {
128 | return response()->json(collect($validator->getMessageBag())->flatten()->toArray(), 403);
129 | }
130 | $profile = Profile::where('id', $id)->first();
131 | $profile->code = $request->get('code');
132 | $profile->designation = $request->get('designation');
133 | $profile->save();
134 | DB::table(config('security-starter.tables.associations.profile_roles'))
135 | ->where('refProfile', $id)
136 | ->delete();
137 | if ($request->has('roles')) {
138 | foreach ($request->get('roles') as $role) {
139 | DB::table(config('security-starter.tables.associations.profile_roles'))
140 | ->insert([
141 | 'refProfile' => $profile->id,
142 | 'refRole' => $role
143 | ]);
144 | }
145 | }
146 | return response()->json(Profile::where('id', $profile->id)->with(['roles'])->first(), 200);
147 | }
148 |
149 | /**
150 | * Remove the specified resource from storage.
151 | *
152 | * @param Request $request
153 | * The request object
154 | * @param int $id
155 | * The profile id
156 | *
157 | * @return JsonResponse
158 | *
159 | * @author EL OUFIR Hatim
160 | */
161 | public function destroy(Request $request, int $id): JsonResponse
162 | {
163 | $rules = [
164 | 'id' => [
165 | new ProfileExists($id)
166 | ]
167 | ];
168 | $request->request->add(['id' => $id]);
169 | $validator = Validator::make($request->all(), $rules);
170 | if ($validator->fails()) {
171 | return response()->json(collect($validator->getMessageBag())->flatten()->toArray(), 403);
172 | }
173 | DB::table(config('security-starter.tables.associations.profile_roles'))
174 | ->where('refProfile', $id)
175 | ->delete();
176 | DB::table(config('security-starter.tables.associations.user_profiles'))
177 | ->where('refProfile', $id)
178 | ->delete();
179 | return response()->json(Profile::where('id', $id)->delete(), 200);
180 | }
181 | }
182 |
--------------------------------------------------------------------------------
/src/Http/Controllers/RoleController.php:
--------------------------------------------------------------------------------
1 |
27 | */
28 | public function index(Request $request): JsonResponse
29 | {
30 | $query = Role::query();
31 | return response()->json(self::paginate($query, $request), 200);
32 | }
33 |
34 | /**
35 | * Store a newly created resource in storage.
36 | *
37 | * @param Request $request
38 | * The request object
39 | *
40 | * @return JsonResponse
41 | *
42 | * @author EL OUFIR Hatim
43 | */
44 | public function store(Request $request): JsonResponse
45 | {
46 | $rules = [
47 | 'code' => [
48 | 'required',
49 | 'max:255',
50 | 'unique:' . config('security-starter.tables.roles') . ',code'
51 | ],
52 | 'designation' => [
53 | 'required',
54 | 'max:255'
55 | ]
56 | ];
57 | $validator = Validator::make($request->all(), $rules);
58 | if ($validator->fails()) {
59 | return response()->json(collect($validator->getMessageBag())->flatten()->toArray(), 403);
60 | }
61 | $role = new Role();
62 | $role->code = $request->get('code');
63 | $role->designation = $request->get('designation');
64 | $role->save();
65 | return response()->json(Role::where('id', $role->id)->first(), 200);
66 | }
67 |
68 | /**
69 | * Display the specified resource.
70 | *
71 | * @param int $id
72 | * The role id
73 | *
74 | * @return JsonResponse
75 | *
76 | * @author EL OUFIR Hatim
77 | */
78 | public function show($id): JsonResponse
79 | {
80 | $query = Role::query();
81 | $query->where('id', $id);
82 | return response()->json($query->first(), $query->count() == 0 ? 404 : 200);
83 | }
84 |
85 | /**
86 | * Update the specified resource in storage.
87 | *
88 | * @param Request $request
89 | * The request object
90 | * @param int $id
91 | * The role id
92 | *
93 | * @return JsonResponse
94 | */
95 | public function update(Request $request, $id): JsonResponse
96 | {
97 | $rules = [
98 | 'code' => [
99 | 'required',
100 | 'max:255',
101 | new RoleExists($id),
102 | 'unique:' . config('security-starter.tables.roles') . ',code,' . $id
103 | ],
104 | 'designation' => [
105 | 'required',
106 | 'max:255'
107 | ]
108 | ];
109 | $validator = Validator::make($request->all(), $rules);
110 | if ($validator->fails()) {
111 | return response()->json(collect($validator->getMessageBag())->flatten()->toArray(), 403);
112 | }
113 | $role = Role::where('id', $id)->first();
114 | $role->code = $request->get('code');
115 | $role->designation = $request->get('designation');
116 | $role->save();
117 | return response()->json(Role::where('id', $role->id)->first(), 200);
118 | }
119 |
120 | /**
121 | * Remove the specified resource from storage.
122 | *
123 | * @param Request $request
124 | * The request object
125 | * @param int $id
126 | * The role id
127 | *
128 | * @return JsonResponse
129 | *
130 | * @author EL OUFIR Hatim
131 | */
132 | public function destroy(Request $request, int $id): JsonResponse
133 | {
134 | $rules = [
135 | 'id' => [
136 | new RoleExists($id)
137 | ]
138 | ];
139 | $request->request->add(['id' => $id]);
140 | $validator = Validator::make($request->all(), $rules);
141 | if ($validator->fails()) {
142 | return response()->json(collect($validator->getMessageBag())->flatten()->toArray(), 403);
143 | }
144 | DB::table(config('security-starter.tables.associations.profile_roles'))
145 | ->where('refRole', $id)
146 | ->delete();
147 | return response()->json(Role::where('id', $id)->delete(), 200);
148 | }
149 | }
150 |
--------------------------------------------------------------------------------
/src/Http/Middleware/RoleMiddleware.php:
--------------------------------------------------------------------------------
1 | user() == null) {
22 | return response()->json(['error' => 'unauthorized', 'message' => 'The request does not contains token'], 401);
23 | }
24 | $this->hasRole($request->user(), $roles);
25 | return $next($request);
26 | }
27 |
28 | /**
29 | * Check if the user has a list of roles, based on a type (any or all)
30 | *
31 | * @param $user
32 | * The user object
33 | * @param array $roles
34 | * The roles array
35 | *
36 | * @return bool
37 | *
38 | * @author EL OUFIR Hatim
39 | */
40 | private function hasRole($user, array $roles): bool
41 | {
42 | $roles = collect($roles);
43 | switch ($roles->first()) {
44 | case 'any':
45 | $roles->forget(0);
46 | return $this->any($user, $roles);
47 | case 'all':
48 | $roles->forget(0);
49 | return $this->all($user, $roles);
50 | default:
51 | return $this->any($user, $roles);
52 | }
53 | }
54 |
55 | /**
56 | * Check if the user has any role of a collection of roles
57 | *
58 | * @param $user
59 | * The user object
60 | * @param Collection $roles
61 | * The roles collection
62 | *
63 | * @return bool
64 | *
65 | * @author EL OUFIR Hatim
66 | */
67 | private function any($user, Collection $roles): bool
68 | {
69 | $result = false;
70 | foreach ($user->profiles as $profile) {
71 | $result = $result || $profile->roles->pluck('code')->intersect($roles)->count() != 0;
72 | }
73 | return $result;
74 | }
75 |
76 | /**
77 | * Check if the user has all roles of a collection of roles
78 | *
79 | * @param $user
80 | * The user object
81 | * @param Collection $roles
82 | * The roles collection
83 | *
84 | * @return bool
85 | *
86 | * @author EL OUFIR Hatim
87 | */
88 | private function all($user, Collection $roles): bool
89 | {
90 | $results = collect();
91 | foreach ($user->profiles as $profile) {
92 | $intersection = $profile->roles->pluck('code')->intersect($roles);
93 | foreach ($intersection as $item) {
94 | if (!$results->contains($item)) {
95 | $results->push($item);
96 | }
97 | }
98 | }
99 | dd($results->count() == $roles->count());
100 | return $results->count() == $roles->count();
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/src/Rules/ProfileExists.php:
--------------------------------------------------------------------------------
1 | id = $id;
15 | }
16 |
17 | /**
18 | * Determine if the validation rule passes.
19 | *
20 | * @param string $attribute
21 | * @param mixed $value
22 | * @return bool
23 | */
24 | public function passes($attribute, $value)
25 | {
26 | return Profile::where('id', $this->id)->count() != 0;
27 | }
28 |
29 | /**
30 | * Get the validation error message.
31 | *
32 | * @return string
33 | */
34 | public function message()
35 | {
36 | return trans('validation.exists', ['attribute' => 'profile']);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/Rules/RoleExists.php:
--------------------------------------------------------------------------------
1 | id = $id;
15 | }
16 |
17 | /**
18 | * Determine if the validation rule passes.
19 | *
20 | * @param string $attribute
21 | * @param mixed $value
22 | * @return bool
23 | */
24 | public function passes($attribute, $value)
25 | {
26 | return Role::where('id', $this->id)->count() != 0;
27 | }
28 |
29 | /**
30 | * Get the validation error message.
31 | *
32 | * @return string
33 | */
34 | public function message()
35 | {
36 | return trans('validation.exists', ['attribute' => 'role']);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/SecurityStarterServiceProvider.php:
--------------------------------------------------------------------------------
1 | app->make(ProfileController::class);
22 |
23 | // Register RoleController
24 | $this->app->make(RoleController::class);
25 | }
26 |
27 | /**
28 | * Bootstrap services.
29 | *
30 | * @return void
31 | */
32 | public function boot()
33 | {
34 | // Register package commands
35 | $this->commands([
36 | SimplePassportConfiguration::class
37 | ]);
38 |
39 | // Register package routes
40 | $this->loadRoutesFrom(__DIR__ . '/routes/api.php');
41 |
42 | // Register package migrations
43 | $this->loadMigrationsFrom(__DIR__ . '/database/migrations');
44 |
45 | // Publish package sources
46 | $this->publishes([
47 | __DIR__ . '/config/security-starter.php' => config_path('security-starter.php')
48 | ]);
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/config/security-starter.php:
--------------------------------------------------------------------------------
1 | > You can change these values before starting the migration command.
14 | |
15 | */
16 | 'tables' => [
17 | 'profiles' => 'profiles',
18 | 'roles' => 'roles',
19 | 'associations' => [
20 | 'profile_roles' => 'profile_roles',
21 | 'user_profiles' => 'user_profiles'
22 | ]
23 | ],
24 |
25 | /*
26 | |--------------------------------------------------------------------------
27 | | Privileges
28 | |--------------------------------------------------------------------------
29 | |
30 | | This value represents the roles that the use must have to access
31 | | respectively the profiles and roles REST resources
32 | | >> Please refer to [https://github.com/heloufir/security-starter] to have
33 | | an idea on how to use this package
34 | |
35 | */
36 | 'privileges' => [
37 | 'profiles' => 'any,ROLE_PROFILES',
38 | 'roles' => 'any,ROLE_ROLES'
39 | ]
40 |
41 | ];
--------------------------------------------------------------------------------
/src/database/migrations/2019_02_22_150438_create_profile_table.php:
--------------------------------------------------------------------------------
1 | increments('id');
18 | $table->string('code', 255)->unique();
19 | $table->string('designation', 255);
20 | $table->timestamps();
21 | });
22 | }
23 |
24 | /**
25 | * Reverse the migrations.
26 | *
27 | * @return void
28 | */
29 | public function down()
30 | {
31 | Schema::dropIfExists(config('security-starter.tables.profiles'));
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/database/migrations/2019_02_22_150448_create_role_table.php:
--------------------------------------------------------------------------------
1 | increments('id');
18 | $table->string('code', 255)->unique();
19 | $table->string('designation', 255);
20 | $table->timestamps();
21 | });
22 | }
23 |
24 | /**
25 | * Reverse the migrations.
26 | *
27 | * @return void
28 | */
29 | public function down()
30 | {
31 | Schema::dropIfExists(config('security-starter.tables.roles'));
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/database/migrations/2019_02_22_150500_create_profile_role_table.php:
--------------------------------------------------------------------------------
1 | integer('refProfile')->unsigned();
18 | $table->foreign('refProfile')->references('id')->on(config('security-starter.tables.profiles'));
19 | $table->integer('refRole')->unsigned();
20 | $table->foreign('refRole')->references('id')->on(config('security-starter.tables.roles'));
21 | $table->primary(['refProfile', 'refRole']);
22 | });
23 | }
24 |
25 | /**
26 | * Reverse the migrations.
27 | *
28 | * @return void
29 | */
30 | public function down()
31 | {
32 | Schema::table(config('security-starter.tables.associations.profile_roles'), function (Blueprint $table) {
33 | $table->dropForeign(['refProfile']);
34 | $table->dropForeign(['refRole']);
35 | });
36 | Schema::dropIfExists(config('security-starter.tables.associations.profile_roles'));
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/database/migrations/2019_02_22_150512_create_user_profiles_table.php:
--------------------------------------------------------------------------------
1 | integer('refUser')->unsigned();
18 | $table->foreign('refUser')->references('id')->on(app(config('auth.providers.users.model'))->getTable() ?: 'users');
19 | $table->integer('refProfile')->unsigned();
20 | $table->foreign('refProfile')->references('id')->on(config('security-starter.tables.profiles'));
21 | $table->primary(['refProfile', 'refUser']);
22 | });
23 | }
24 |
25 | /**
26 | * Reverse the migrations.
27 | *
28 | * @return void
29 | */
30 | public function down()
31 | {
32 | Schema::table(config('security-starter.tables.associations.user_profiles'), function (Blueprint $table) {
33 | $table->dropForeign(['refUser']);
34 | $table->dropForeign(['refProfile']);
35 | });
36 | Schema::dropIfExists(config('security-starter.tables.associations.user_profiles'));
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/models/Profile.php:
--------------------------------------------------------------------------------
1 | table = config('security-starter.tables.profiles');
22 | }
23 |
24 | /**
25 | * Get roles related to this profile
26 | *
27 | * @return BelongsToMany
28 | *
29 | * @author EL OUFIR Hatim
30 | */
31 | public function roles(): BelongsToMany
32 | {
33 | return $this->belongsToMany(Role::class, config('security-starter.tables.associations.profile_roles'), 'refProfile', 'refRole');
34 | }
35 |
36 | /**
37 | * Get users related to this profile
38 | *
39 | * @return BelongsToMany
40 | *
41 | * @author EL OUFIR Hatim
42 | */
43 | public function users(): BelongsToMany
44 | {
45 | return $this->belongsToMany(config('auth.providers.users.model'), config('security-starter.tables.associations.user_profiles'), 'refProfile', 'refUser');
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/models/Role.php:
--------------------------------------------------------------------------------
1 | table = config('security-starter.tables.roles');
22 | }
23 |
24 | /**
25 | * Get profiles related to this role
26 | *
27 | * @return BelongsToMany
28 | *
29 | * @author EL OUFIR Hatim
30 | */
31 | public function profiles(): BelongsToMany
32 | {
33 | return $this->belongsToMany(Profile::class, config('security-starter.tables.associations.profile_roles'), 'refRole', 'refProfile');
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/routes/api.php:
--------------------------------------------------------------------------------
1 | 'api', 'middleware' => ['auth:api']], function () {
4 | Route::resource('profiles', 'Heloufir\SecurityStarter\Http\Controllers\ProfileController')
5 | ->except(['create', 'edit'])
6 | ->middleware(['roles:' . config('security-starter.privileges.profiles')]);
7 | Route::resource('roles', 'Heloufir\SecurityStarter\Http\Controllers\RoleController')
8 | ->except(['create', 'edit'])
9 | ->middleware(['roles:' . config('security-starter.privileges.roles')]);
10 | });
--------------------------------------------------------------------------------