Users, their roles and permissions

 As I already said, the application recognizes 3 authenticated user types: normal, admin and super admin. Normal user is a type with the lowest authorization level and he can only view his own account information, chenge his own password, view posts and comment on them. In this post we will see how all user types dashboards work.

Normal User's "My Account" Dashboard

User "My Account" Dashboard Page  (all 3 user types can access this page):


My Account View:


 <img src="https://i.pravatar.cc/120?u={{ Auth::user()->id }}" alt="avatar"> shows a random avatar taken from https://pravatar.cc/ that is permamently assigned to user's id. This means that avatars won't repeat themselves as they become unique for each user.
{{Auth::user()->username}} shows user's username.
{{ session('error') }} if there is any problem with user's session, then an error will occur.
The view also consists of changing password form. User have to type in current password, new password and confirm new password. 

Controller for My Account User's Dashboard:



 return view('showuser', ['users' => $user]); is responsible for showing the view for current user.

if(!Hash::check($request->old_password, auth()->user()->password)){
            return back()->with("error", "Old Password Doesn't match!");
        }

code above is responsible for checking if the password submited by user in the old password's form field matches with the password stored in database for this user. If those two don't match then an error occurs.

User::whereId(auth()->user()->id)->update([
            'password' => Hash::make($request->new_password)
        ]);

If those two are matching, then the record of user whose id matches the current user's id (authentication process) is updated with new, hashed password.

Admin Dashboard

When the authentication system recognizes a user with an admin rank, then it shows them the Admin Dashboard option.
 

Every page's view consists of navigation menu has that option so it is always visible for an admin to click on. 


@can('admin') states that only a user that meets the conditions of being an admin can access Admin dashboard option.
@endcan ends the statement. Those conditions are stated in
App/Providers/AppServiceProvider.php


Just as a reminder, in users table in my database, I set the is_admin value to be an integer, which by defaul for a new user is set as 0:

$table->integer('is_admin')->default(0);

App Provider allowed me to define 'admin' as an user with is_admin equal or bigger than 1. I also defined a 'superadmin' (which I will talk about later in this post) as an user with is_admin integer set as number 2. Thanks to that, 'superadmin' can access the same things as just an  'admin' but 'admin' can't access functionalities that are specify as ones for rank "2" of is_admin field.
Gate::define();
provides a simple, Closure based approach to authorization. It defines conditions that have to be met in order to access something for that authorization "rank". 

View for admin's Users Management:


@foreach ($users as $user) shows all information specified below that statement for each recor in users table.
The view consists of simple table that shows a list of all users that have an account on BTT. The table shows each user's record in a row. The record includes given user's id, username, email and admin rank. 0 = user is just a normal, casual user
1 = this user is an admin

Controller for admin's Users Management:



 public function allusers() shows all user that are currently in users table in app's database.

 if (auth()->user()->is_admin >= 1){
        return view('admin.posts.allusers', [
            'users' => User::all()->where('is_admin', '<', 2)
        ]);}
        else{
            abort(403);
        }

Using the code above I secured the path for viewing all users so only a user with 'admin' rank or above (in this case with 'superadmin' rank as well) is authorized to access it. The authentication system checks if current user is an admin and if he isn't, then it shows a 403 error message. This is useful as if an unauthorized user tries to access that page via putting it's name manually, directly into URL, the system will stop him from doing so.



403 HTTP error means that the user is trying to reach an address or a website that is forbidden to access for him.
If the user happens to be an admin, then he is authorized to see a list of all the users with a is_admin value smaller than 2, which means he will see all users except the 'superadmin'. Other functions included in this controlled are reserved only for 'superadmin' so I will go through them soon

Page with list of users in Admin's Dashboard:



SuperAdmin type of User

There is only one superadmin of the application and I set his rank manually in database through phpMyAdmin. The user with 'superadmin' rank characterises with is_admin value equalling 2. Normal admin (is_admin = 1) can only access the list view of all users. The 'superadmin', however, is authorized to edit all users records and delete user's account permamently from app's database. The account of 'superadmin' can't be edited, deleted or even viewed on the website, even by the 'superadmin' himself for security purposes. This means that it makes 'superadmin' the only user type that can be managed only manually, directly thorugh database with phpMyAdmin.  

Page with list of users in Admin's Dashboard for superadmin:

In order for 'superadmin' to be able to edit and delete users, this part of code was added to the view which is responsible for displaying all users table on Admin's dashboard:


href="/admin/users/{{ $user->id }}/useredit" sets the "Edit" link's path for editing the user's record.
<form method="POST" action="/admin/users/{{ $user->id }}"> states that the form's action will refer to the user, which id is found after clicking the button. This will cause in affecting only the chosen user.
@csrf allows the form to use CSRF protection offered by the framework.
CSRF attack takes place when the attacker causes the victim user to carry out an action unintentionally. Depending on the nature of the action, the attacker might be able to gain full control over the user's account. If the compromised user has a privileged role within the application, then the attacker might be able to take full control of all the application's data and functionality. Session cookie won't protect the user as in the request their browser will automatically include their session cookie in it to be viewed by attacker. To prevent that @csrf generates a CSRF token within relevant requests and then validates it.
@method ('DELETE') connects the button action with delete() method in Controller by mentioning the destroy function in the route.
<button onclick="return confirm('Are you sure you want to delete {{ $user->username }} ?')" triggers JavaScript confirmation alert before completing user's request. The confirmation alert asks if the user is sure he wants to delete the user with given username.

Controller functions added for 'superadmin' features to work:

public function destroy(User $user){
        if (auth()->user()->is_admin === 2){
       
        $user->delete();
        return back()-> with('success', "User Deleted");}

        else{
            abort(403);
        }
    }

This function allows only an user with is_admin value equal to 2 to delete a user record. The deletion will only apply to the chosen user. Again, if the unauthorized user will try to that that, the 403 page will appear.

 public function useredit(User $user)
    {
        if (auth()->user()->is_admin === 2){
            if($user->username !== 'admin'){
        return view('admin.posts.edituser', [
            'user' => $user
        ]);}
        else{
            abort(403);
        }
    }}

 Again, only 'superadmin' can access the view for editing an user record. The editing will only apply to the chosen user.

public function update(User $user)
    {
        if (auth()->user()->is_admin === 2){
        $attributes = request()->validate([
            'is_admin' => 'required|integer',
            'username' => 'required'
            ]);
            $user->is_admin = (int)$attributes['is_admin'];
            $user->update($attributes);
            return back()-> with('success', "User's admin status updated");
    }
            else{
                abort(403);
            }
    }
}


update() function is triggered by user edit form submission and simply states what values have to be included and verified before completion of that action.

Appeared Problem and its solution:
I couldn't make the is_admin rank changing work. It wasn't accepting the input even though it was set as numeric one. Finally I found out that even though the is_admin field accepts only numbers it doesn't pass them as integers to the database. To do that I added this line of code:
 $user->is_admin = (int)$attributes['is_admin'];
Before completing the request and passing fresh data to the database, the is_admin value sent by user is first converted into an integer. In that way the number from user's input is read as an integer by the database which allows 'superadmin' to change the admin rank of all users.


User Edit view (accessable for 'superadmin' only):

This view includes a form that allows 'superadmin' to change chosen user's username and admin rank. He can upgrade user to be an admin (maximum number that can be insetrted is 1 so he can't create another superadmin like that) or downgrade an admin to normal user (minimum value is 0).

Edit User Page:

web.php with routes for all of the above functions and views:

 Admin's Dashboard also has an option for post management where all admins can also add, edit, view and delete posts. I will talk about posts and their comments in my next publication.


Komentarze