Blog

  • Creating and Consuming RESTful API in Laravel

    Nice Tutorial to get started with APIs in Laravel.

    Madhavendra DuttDec 1·6 min read

    RESTful API
    RESTful API

    What is API?

    An API — Application Programming Interface, is a computing interface that defines interactions between multiple software intermediaries. It is a way to programmatically interact with a separate software component or resource.

    What is REST?

    REST is an acronym for REpresentational State Transfer. This term was coined by Roy Fielding in 2000. It is an architecture style for designing loosely coupled applications over HTTP, that is often used in the development of web services.

    REST defines 6 architectural constraints that make any web service a true RESTful API.

    1. Client-server — By separating the user interface from the data storage, we improve the portability of the user interface across multiple platforms and improve scalability by simplifying the server components.
    2. Stateless — Each request from the client to the server must contain all of the information necessary to understand the request, and cannot take advantage of any stored context on the server. Session state is therefore kept entirely on the client.
    3. Cacheable — Cache constraints require that the data within a response to a request be implicitly or explicitly labeled as cacheable or non-cacheable. If a response is cacheable, then a client cache is given the right to reuse that response data for later, equivalent requests.
    4. Uniform interface — By applying the principle of generality to the component interface, the overall system architecture is simplified and the visibility of interactions is improved.
    5. Layered system — The layered system style allows an architecture to be composed of hierarchical layers by constraining component behavior such that each component cannot “see” beyond the immediate layer with which they are interacting.
    6. Code on demand (optional) — REST allows client functionality to be extended by downloading and executing code in the form of applets or scripts. This simplifies clients by reducing the number of features required to be pre-implemented.

    Now let’s jump into creating and consuming RESTful API in Laravel. I would recommend to read and implement Migration and data seeding & Creating Relationships before you dive into this tutorial.

    Consumers of our API will be able to perform a few limited tasks. There would be the following endpoints:

    API endpoints for the unauthenticated route

    Related to category:

    • Get all categories GET /categories
    • Get all posts of a category GET /categories/{id}/posts

    Related to the post:

    • Get all posts GET /posts
    • Get a post by ID GET /posts/{id}
    • Get all comments on a post GET /posts/{id}/comments

    Related to the author:

    • Get details of an author GET /authors/{id}
    • Get all posts by an author GET /authors/posts
    • Get all comments by an author GET /authors/{id}/comments

    Related to the tag:

    • Get all posts of a tag GET /tags/{id}/posts

    API endpoint for the authenticated route

    Related to comment:

    • Store user comment POST /comments/posts/{id}

    You have to create API ResourcesControllers, and API Routes for the above-mentioned API endpoints.

    Step 1: Let’s first create API Resources. To do so follow the below-mentioned steps (don’t forget to implement the Migration and Relationship part):

    When building an API, you may need a transformation layer that sits between your Eloquent models and the JSON responses that are actually returned to your application’s users. Laravel’s resource classes allow you to expressively and easily transform your models and model collections into JSON.

    Run the command php artisan make:resource CategoryResource. It will create CategoryResource in app\Http\Resources directory.

    Open this file and return the desired data, eg. category_id in place of id. You can do a lot more than just masking the field names or number of fields to be returned like- we can return additional information with API, etc.

    public function toArray($request)
    {
    return [
    'category_id' => $this->id,
    'category_title' => $this->title,
    'category_color' => $this->color,
    ];
    }// (Optional) Additional code is attached to the response
    public function with($request){
    return [
    'version' => "1.0.0",
    'author_url' => "https://mditech.net"
    ];
    }

    The same way you have to create other required resources — CommentResourcePostResourceTagResourceUserResourceImageResource, and VideoResource. Create these resources or check them out from the repository.

    Step 2: The next activity is to create the required controllers. To do so follow the below steps:

    Run the command php artisan make:controller Api\\CategoryApiController. It will create CategoryApiController in theapp\Http\Controllers\Api directory. Open that file and write the methods to perform actions.

    public function index()
    {
    $categories = Category::all();
    return CategoryResource::collection($categories);
    }public function posts($id)
    {
    $posts = Post::where('category_id', $id)->orderBy('id', 'desc')->paginate();
    return PostResource::collection($posts);
    }

    Here you created two methods index and posts inside CategoryApiController.

    The index method will return all the categories wrapped inside CategoryResource.

    The posts method will return all the posts belonging to a specific category wrapped inside PostResource.

    The same way create the desired methods in CommentApiControllerPostApiControllerTagApiController, and UserApiController or checkout repository.

    Step 3: The last step is to create routes for the API. Proceed to the routes directory and open the api.php file and create the API endpoints that will reference the methods created in CategoryApiControllerCommentApiControllerPostApiControllerTagApiController, and UserApiController.

    <?php
    use App\Http\Controllers\Api\CategoryApiController;
    use App\Http\Controllers\Api\CommentApiController;
    use App\Http\Controllers\Api\PostApiController;
    use App\Http\Controllers\Api\TagApiController;
    use App\Http\Controllers\Api\UserApiController;
    use Illuminate\Support\Facades\Route;Route::get('authors/{id}', [UserApiController::class, 'show']);
    Route::get('authors/{id}/posts', [UserApiController::class, 'posts']);
    Route::get('authors/{id}/comments', [UserApiController::class, 'comments']);
    Route::get('categories', [CategoryApiController::class, 'index']);
    Route::get('categories/{id}/posts', [CategoryApiController::class, 'posts']);
    Route::get('posts', [PostApiController::class, 'index']);
    Route::get('posts/{id}', [PostApiController::class, 'show']);
    Route::get('posts/{id}/comments', [PostApiController::class, 'comments']);
    Route::get('tags/{id}/posts', [TagApiController::class, 'posts']);
    Route::middleware('auth:sanctum')->group(function () {
    Route::post('comments/posts', [CommentApiController::class, 'store']);
    });

    Testing the API endpoints

    Start the database and run php artisan serve command. Laravel development server will start on http://127.0.0.1:8000

    Open Postman and test all routes defined in api.php, but make sure to append your route with /api/

    To get all categories you should send a GET request to http://127.0.0.1:8000/api/categories

    categories
    RESTful API Returning Response

    Now lets test authenticated route as well. There is only one authenticated route for storing comment of logged in user on a post.

    We are using Laravel Sanctum for authentication and authorization. We will issue an API token and use that in Postman to authenticate the request.

    Laravel Sanctum provides a featherweight authentication system for SPAs (single page applications), mobile applications, and simple, token based APIs. Sanctum allows each user of your application to generate multiple API tokens for their account. These tokens may be granted abilities / scopes which specify which actions the tokens are allowed to perform.

    To issuse an API token we will run tinker command

    php artisan tinker

    It will now allow us to interact with the Laravel application from the command line. Here you need to create an API token for a user using createToken() method.

    Copy plainTextToken, to be used in Postman.

    Now open Postman and do the following:

    • New POST request to http://127.0.0.1:8000/api/comments/posts
    • In Authorization tab select Type as Bearer Token and paste the plainTextToken in Token text box.
    • Then in Headers tab Key as Accept and Value as application/json.
    • Then in Body tab select form-data radio button and in KeyValue write id — 159comment — Testing some comment on post 159
    • Now hit the send button and you will get back the newly created comment.

    In this article, we have been able to build and consume (Consumer was Postman)RESTful API using Laravel. We covered the API Resource creation, API Controller creation, and tested Authenticated and Non-Authenticated API Routes.

    The source code is available at Github for you to refer to.

    Read the previous part, Creating Relationships of this tutorial.

    Read the next part, Creating the Front End for Admin user.

    Twitter: kotagin

    GitHub: mdutt247

    E-mail: m.dutt@mditech.net

    Madhavendra Dutt

    Facilitator | Freelancer | Software Develop

  • LARAVEL 8: HOW TO CREATE RESTful APIs WITH LUMEN 8

    Open in appSamson Omojola

    Image for post

    WHAT WE’LL BE BUILDING

    In this tutorial, you’ll learn how to use Laravel Lumen (version 8) to create REST APIs.

    We’ll be creating a Lumen microservice that implements all the types of HTTP requests. Our microservice will help us manage users. So, from any frontend application we connect to our microservice, we should be able to:

    – Create a new user (POST Request)

    – Edit the details of a user (PUT Request)

    – Request for the details of users (GET Request)

    – Delete a user (DELETE Request)

    Here’s a link to the GitHub repo of this project: Repo

    Tools Required:

    · You need to have PHP installed. The minimum PHP version that is compatible with Lumen 8 is PHP 7.3. If you have the latest XAMPP, WAMP, or LAMP installed, you should be good to go.

    · You also need to have Composer installed. If you don’t have it, click here to get it.

    Knowledge Required:

    • Basic knowledge of Laravel will help you follow along.

    Let’s Get Started!

    Install lumen on your system by running the command below via a CLI:

    composer global require “laravel/lumen-installer”

    Next, in your CLI, navigate to the directory that you want your project to be located in and create a lumen project using the command:

    composer create-project — prefer-dist laravel/lumen projectName

    NB: Replace “projectName” with whatever you want to name your project.

    Lumen comes with some boilerplate code; a simple template that we can build upon. If you want to take a quick look at it, run php -S localhost:8000 -t public via your CLI and run localhost:8000 in your browser. You should see something like this:

    Image for post

    Now, let’s continue with creating our microservice.

    The next thing we want to do is create a database for our microservice. This is where all the details of our users will be stored. There are a number of ways to do this. I’m going to stick with MySQL, and I’ll make use of PHPmyAdmin. Feel free to use whatever option you deem best.

    Make sure your server is running(XAMPP, WAMP, or LAMP). Go to your browser and enter localhost/phpmyadmin. Create a new database and take note of the name you used.

    Next, let’s add our database details to our lumen project, so as to connect both together.

    Open the newly created lumen project with any code editor of your choice, navigate to the .env file, and update the name of the database, the username, and the password.

    By default, the username should be “root” and there should be no password.

    Now that our database is set, we can start working on the actual project. In this project, we’ll be making use of Laravel’s Eloquent and Facades classes. In Lumen, these classes come disabled, so we have to enable them ourselves. To do this, navigate to boostrap/app.php and uncomment the lines below:

    //$app->withFacades();

    //$app->withEloquent();

    Now, your bootstrap/app.php file should look like this:https://omojolasamsonade.medium.com/media/68dd19d605319f97a4cb061e715cd5b4

    We’ll be making use of Eloquent and Facades in our routes and controller files.

    Now that we have that set up, let’s create our users table in the database we just created. Run the following command in your CLI:

    php artisan make:migration create_users_table

    Navigate to the migrations folder and open the newly created users migration file. This is where we decide what columns the users table should have.

    Each user should have a first name, a last name, and an email address. So let’s go ahead and create columns for them.

    $table->string(‘first_name’);

    $table->text(‘last_name’);

    $table->integer(‘email_address’);

    Now, your users migration file should look like this:https://omojolasamsonade.medium.com/media/0caf4f7320a9f21e3159fbc2f5741ebf

    To create the table, run the following command in your CLI:

    php artisan migrate

    Now that we’ve successfully created our users table, the next step is to create our User model. In Lumen, there’s no CLI command for creating models, so navigate to your app/Models folder, create a file and name it User.php. If you find a User.php file already created in that folder, just use that instead. Now, let’s map it to our database:

    protected $fillable =[‘first_name’, ‘last_name’, ‘email_address’,];

    It should look like this now:https://omojolasamsonade.medium.com/media/05657cd2cae8ab19b8e53a881583d282

    Now we need to create the appropriate routes for our microservice. The code that will process API calls will be in a controller file named UserController. UserController will contain different methods for handling all the different HTTP requests, and each method will need a route pointing to it. The routes will serve as triggers for these methods. Every time they are called, the methods will be executed. We’ll be giving all the routes a common prefix “api/v1” (think of it as them all belonging to the same family).

    Navigate to routes/web.php and add the needed routes:

    $router->group([‘prefix’ => ‘api/v1’], function () use ($router) {

    $router->post(‘users/add’, ‘UserController@createUser’);

    $router->get(‘users/view/{id}’, ‘UserController@viewUser’);

    $router->put(‘users/edit/{id}’, ‘UserController@updateUser’);

    $router->delete(‘users/delete/{id}’, ‘UserController@deleteUser’);

    $router->get(‘users/index’, ‘UserController@index’);

    });

    Your web.php should look like this:https://omojolasamsonade.medium.com/media/8ae6347853eb6a9604c797d0068e5403

    (The comment above each route explains what the route does).

    Now that our routes are set, we need to actually create that controller file with the methods we are referencing above. These methods will be in charge of handling our API calls and processing our requests.

    Go to app/Http/Controllers and create a file named UserController.php

    These are the methods we need:

    Create New User

    public function createUser(Request $request){

    $user = User::create($request->all());

    return response()->json($user);

    }

    update user details

    public function updateUser(Request $request, $id){

    $user = User::find($id);

    $user->first_name = $request->input(‘first_name’);

    $user->last_name = $request->input(‘last_name’);

    $user->email_address = $request->input(‘email_address’);

    $user->save();

    return response()->json($user);

    }

    view user

    public function viewUser($id){

    $user = User::find($id);

    return response()->json($user);

    }

    delete user

    public function deleteUser($id){

    $user = User::find($id);

    $user->delete();

    return response()->json(‘Removed successfully’);

    }

    list users

    public function index(){

    $user =User::all();

    return response()->json($user);

    }

    Your User Controller should look like this:https://omojolasamsonade.medium.com/media/2d970a97395fe287e49e3d980da9c2e3

    The first method createUser() allows you to create a new user.

    The second method updateUser() allows you to update the details of an already existing user.

    The third method viewUser() allows you to view the details of a user you created.

    The fourth method deleteUser() allows you to delete a user from your database.

    The fifth method index() allows you to list all the users you created.

    Now, if a call is made to any of the routes in web.php, the corresponding method in UserController is triggered.

    You can use Postman to make the http request. To do that, make sure your lumen server is running. Use this command to get it started: php -S localhost:8000 -t public

    Next, fire up postman.

    Let’s test createUser() first. Send this HTTP request via Postman: http://localhost:8000/api/v1/users/add

    Image for post

    Create the required fields and supply them with values.

    (Use the POST option)

    You should get the details of the user you just created as a JSON response.

    Next, let’s test updateUser(). We can edit the details of the user we just created. Send this HTTP request via Postman: http://localhost:8000/api/v1/users/edit/1

    Image for post

    Supply the previously created fields with new values.

    (Use the PUT option)

    You should get the details you just entered back as a JSON response.

    Next, let’s test viewUser(). We can view the details of the user we just created. Send this HTTP request via Postman: http://localhost:8000/api/v1/users/view/1

    Image for post

    (Use the GET option)

    You should get the details of the user you created back as a JSON response.

    Next, let’s test deleteUser(). We can delete the user we just created. Send this HTTP request via Postman: http://localhost:8000/api/v1/users/delete/1

    (Use the DELETE option)

    You should get a success message back.

    Lastly, let’s test index(). This will list out all the users we have in our database. Send this HTTP request via Postman: http://localhost:8000/api/v1/users/index

    (Use the GET option)

    BUILDING A CLIENT APPLICATION TO CONSUME THE API

    Let’s create a very simple frontend application to consume the API we just created. A simple PHP application will suffice. Navigate to xampp/htdocs and create a folder for your frontend app. I’ll name mine “userfrontend”. Next, create a file in the folder and name it “index.php”.

    Make sure your lumen microservice and your XAMPP are running.

    We can use php’s curl function to make the API request, like this:

    $url = ‘http://localhost:8000/api/v1/users/index’;

    curl_setopt($curl, CURLOPT_URL, $url);

    $data = curl_exec($curl);

    Next, you convert the data to JSON format:

    $decodeUsers = json_decode($data, true);

    And lastly, loop through the data with a foreach loop and display each user’s data.

    Now, if you go to your browser and run http://localhost/userfrontend, you should see the details of the users in your database.

    Here’s a link to the GitHub repo of this project: Repo

    More from Samson Omojola

  • 7 Free APIs That Nobody Is Talking About

    7 Free APIs That Nobody Is Talking About

    Ethan O’Sullivan2 months ago

    APIs are vital tools in the success of any app.

    I agree, I would run into issues trying to use an XML feed because of it's formatting. So I developed an API that converts XML to JSON, check it out:https://medium.com/p/b09734329bc9

    5

    Reply

    Bizzabe83Bizzabe832 months ago

    Many times we just want to focus on the frontend

    Good read

    10

    Reply

    Alex Mireles

    Alex Mireles2 months ago

    Isn't 90% of this list on every beginner API?

    1

    Reply

    Chris Hornberger

    Chris Hornberger2 months ago

    Also, your comment about “everyone using the same APIs...” being a bad thing is just silly. What that does is create uniformity and standards. Oy.

    Reply

    { rxluz }

    { rxluz }2 months ago

    Wow, that’s handy APIs! The glyph and recipe I’ll use in some future project for sure, one suggestion to add to your excellent list is Unplash, I use it before to allow users to search high-quality and free for use images, others to check the weather and result of matches are quite useful as well.

    Anurag KanoriaNov 23, 2020 · 6 min read

    Nothing excites me more than finding an out of the ordinary API.

    Many times we just want to focus on the frontend but also need interesting, dynamic data to display.

    This is where public APIs come into play. API is an acronym for Application Programming Interface.

    The core benefit of using it is that it allows one program to interact with other programs.

    Using public APIs allows you to focus on the frontend and things that matter without worrying so much about the database and the backend.

    Below are 7 less-talked about public and free APIs.

    1. Evil Insult Generator

    How many times have you tried to insult your best friend? Now you have got a helping hand!

    As the API name suggests, the goal is to offer some of the evilest insults.

    You can create an app centered around this API or combine this API with other excellent APIs provided below like implementing the generated insults in meme templates.

    The API is extremely simple to use. You just need to visit a URL and you get the desired JSON output without even signing up for a key.

    Sample output of the API is provided below:

    {
    "number":"117",
    "language":"en",
    "insult":"Some cause happiness wherever they go; others, whenever they go.",
    "created":"2020-11-22 23:00:15",
    "shown":"45712",
    "createdby":"",
    "active":"1",
    "comment":"http:\/\/www.mirror.co.uk\/news\/weird-news\/worlds-20-most-bizarre-insults-7171396"
    }

    You get the other properties as well such as the time it was created, the language, any comment as well as the views.

    2. Movies and TV API

    TMDb is a famous API, but do you know there are other API that provides insights from specific shows and movies?

    Below are some of the APIs you can use to develop apps featuring your favorite show:

    1. Breaking Bad API
    2. API of Ice And Fire
    3. Harry Potter API
    4. YouTube API (for embedding YouTube functionalities)
    5. The Lord of the Rings API

    Like the API above, you can get started with some of the APIs without even signing up for a key.

    Not only this, using non-copyright images, you can truly create a great fan app for your beloved shows.

    Below is a sample output from the Breaking Bad API which you can get here.

    It doesn’t require a key however has a rate limit of 10,000 requests per day.

    {
    [
    {
    "quote_id":1,
    "quote":"I am not in danger, Skyler. I am the danger!",
    "author":"Walter White",
    "series":"Breaking Bad"
    },
    {
    "quote_id":2,
    "quote":"Stay out of my territory.",
    "author":"Walter White",
    "series":"Breaking Bad"
    },
    {
    "quote_id":3,
    "quote":"IFT",
    "author":"Skyler White",
    "series":"Breaking Bad"
    }
    .....
    ]
    }

    It returns a JSON containing an array of objects with quotes, the author of the quotes, and an ID.

    You can mix these dedicated APIs with YouTube API to create an ultimate app for the fans of these shows.

    3. Mapbox

    Mapbox provides precise location information and fully-fledged tools to developers.

    You get instant access to dynamic, live-updating maps which you can even further customize!

    If you have a project geared towards location and maps, this is a must-know API.

    However, it is worth mentioning that you have to sign up for free to get a unique access token.

    Using this token you can use the amazing services offered by this API.

    Not only this, you can use Mapbox with libraries such as the Leaflet.js library and create beautiful, mobile-friendly maps.

    I have discussed this and much more in my recent article covering the basics of Mapbox and Leaflet.js.Add Interactive Maps to Your WebsiteWithout using Google Maps!medium.com

    4. NASA API

    NASA provides a fabulous updated database of space-related information.

    Using this API, one can create mesmerizing and educational apps and websites.

    You get access to various different kinds of data from the Astronomy Picture of the Day all the way to the pictures captured by the Mars Rover.

    You can browse the entire list here.

    You can also retrieve NASA’s patents, software, and technology spinoff descriptions which you can use to build a patent portfolio.

    This API is really diverse and offers a wide variety of data. You can even access the NASA Image and Video library using it.

    Below is a sample query of the pictures captured by Curiosity on Mars.

    {
    "photos":[
    {
    "id":102693,
    "sol":1000,
    "camera":{
    "id":20,
    "name":"FHAZ",
    "rover_id":5,
    "full_name":"Front Hazard Avoidance Camera"
    },
    "img_src":"http://mars.jpl.nasa.gov/msl-raw-images/proj/msl/redops/ods/surface/sol/01000/opgs/edr/fcam/FLB_486265257EDR_F0481570FHAZ00323M_.JPG",
    "earth_date":"2015-05-30",
    "rover":{
    "id":5,
    "name":"Curiosity",
    "landing_date":"2012-08-06",
    "launch_date":"2011-11-26",
    "status":"active"
    }
    },
    .....
    ]
    }

    5. GIF Search

    https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fgiphy.com%2Fembed%2F3o7TKr2xg9OWcU8DWo%2Ftwitter%2Fiframe&display_name=Giphy&url=https%3A%2F%2Fmedia.giphy.com%2Fmedia%2F3o7TKr2xg9OWcU8DWo%2Fgiphy.gif&image=https%3A%2F%2Fi.giphy.com%2Fmedia%2F3o7TKr2xg9OWcU8DWo%2Fgiphy.gif&key=a19fcc184b9711e1b4764040d3dc5c07&type=text%2Fhtml&schema=giphySource: GIPHY

    We all love using and creating GIFs but did you know you can incorporate the GIFs in your next app for free using GIPHY?

    GIPHY is the largest GIF and sticker library in the world right now and using their official API you can leverage the vast collection to produce unique apps for free.

    Using the search endpoints, users can get the most relevant GIFs based on their query.

    You also get access to analytics and other tools which will enable you to create a personalized user experience.

    The most used feature, however, for me was the translate endpoint which converts words and phrases to the perfect GIF or Sticker. You can specify the weirdness level on a scale of 0–10.

    Note that you have to provide proper attribution by displaying “Powered By GIPHY” wherever the API is utilized.

    Below is a sample output of this API:

    {data: GIF Object[]pagination: Pagination Objectmeta: Meta Object}

    6. Favourite Quotes API

    As the name suggests, this API provides you with a thoughtful quotes collection.

    You can use these quotes to show on the landing page of your website or on the splash screen of your app to produce a rich user experience.

    You also get the ability to create and manage users and sessions via this API. However, there exists a rate limit of 30 requests in a 20-second interval per session.

    This API also has endpoints to filter, vote, list, update, and delete quotes.

    Below is the output for the Quote of the Day endpoint.

    {
    "qotd_date":"2020-11-23T00:00:00.000+00:00",
    "quote":{
    "id":29463,
    "dialogue":false,
    "private":false,
    "tags":[
    "great"
    ],
    "url":"https://favqs.com/quotes/walt-whitman/29463-the-great-cit-",
    "favorites_count":1,
    "upvotes_count":2,
    "downvotes_count":0,
    "author":"Walt Whitman",
    "author_permalink":"walt-whitman",
    "body":"The great city is that which has the greatest man or woman: if it be a few ragged huts, it is still the greatest city in the whole world."
    }
    }

    7. Edamam Nutrition and Recipe Analysis API

    Edamam generously provides access to a database of over 700,000 food items and 1.7 million+ nutritionally analyzed recipes.

    This API is great if you want to showcase your frontend skills as you can add high-quality pictures of food alongside the recipe of that food provided by this API.

    The free plan can’t be used commercially however it provides a comprehensive set of features such as Natural Language Processing support and 200 recipes per month.

    You can find the full details regarding different plans offered here.

    The users can simply type the ingredients and get the nutritional analysis which can help them eat smarter and better.

    You can check this cool feature here in the demo of this API.

    They have other APIs as well which can be used in conjunction with the rest to create a one-stop food app.

    They have added a new diet filter specifically geared towards the ongoing pandemic which leverages scientific publications about nutrients and foods to enhance immunity.

    Final Thoughts

    APIs are vital tools in the success of any app.

    Using third-party, public API allows developers to focus on things that matter while conveniently adding robust functionality to their app through these APIs.

    However, using the same API as everybody else not only creates unnecessary competition but also doesn’t provide any real value.

    Leveraging unique and flexible APIs can lead to the creation of some incredibly beautiful projects that you can showcase in your professional portfolio.

  • How to implement Laravel’s Must Verify Email feature in the API registration

    Laravel provides us with an amazing feature called Must Verify Email which makes email verification a breeze by just writing 2–3 lines of code really. But unfortunately there is no provision for applying the same feature in API, especially if you are using same auth user table to register in API . This threw me off for a while and there wasn’t many resource online , when i finally got around it , turned out to be very simple. So here i am going to share with you how to apply the same feature in your API registration as one stop solution. We will basically recreate the must verify email feature for API. Follow along ….

    Let’s install a fresh installation of Laravel, in my case I named my project as “email”, runn the following command to install laravel

    composer create-project --prefer-dist laravel/laravel email

    Laravel comes ship with users table migration which looks like this

    class CreateUsersTable extends Migration
    {
       /**
        * Run the migrations.
        *
        * @return void
        */
        public function up()
        {
            Schema::create('users', function (Blueprint $table) {
                $table->increments('id');
                $table->string('name');
                $table->string('email')->unique();
                $table->timestamp('email_verified_at')->nullable();
                $table->string('password');
                $table->rememberToken();
                $table->timestamps();
            });
        }
    }
    

    As you can see that laravel includes ‘email_verified_at’ in it’s schema which when we use Must Verify Email changes from null to the current timestamp , you can check the docs for more info.

    Before we implement the email verification feature we need to run the artisan command to make the authorisation scaffoldings type in the following command to enable auth:

    php artisan make:auth
    

    Once the auth is generated you can simply include the following in your User Model as mentionad in the docs

    <?php
    
    namespace App;
    
    use Illuminate\Notifications\Notifiable;
    use Illuminate\Contracts\Auth\MustVerifyEmail;
    use Illuminate\Foundation\Auth\User as Authenticatable;
    
    class User extends Authenticatable implements MustVerifyEmail
    {
        use Notifiable;
        // ...
    }
    

    And you can simply include the following in your web route

    Auth::routes(['verify' => true]);

    Add the middleware in the route to protect it like so

    Route::get('profile', function () {
    // Only verified users may enter...
    })->middleware('verified');

    So far we have only talked about how we can implement the email verification in the web route now coming to the topic i will guide you how we can replicate the same for API

    Let’s start with recreating the VerificationController that you can find under app/http/controllers/auth/VerificationController only for an API let’s name it “VerificationApiController” run the following command to make the controller

    php artisan make:controller VerificationApiController

    And just add the follwoing code inside the controller

    <?php
    
    namespace App\Http\Controllers;
    
    use App\User;
    use Illuminate\Foundation\Auth\VerifiesEmails;
    use Illuminate\Http\Request;
    use Illuminate\Auth\Events\Verified;
    
    class VerificationApiController extends Controller
    {
        use VerifiesEmails;
    
        /**
        * Show the email verification notice.
        *
        */
        public function show()
        {
            //
        }
    
        /**
        * Mark the authenticated user’s email address as verified.
        *
        * @param \Illuminate\Http\Request $request
        * @return \Illuminate\Http\Response
        */
        public function verify(Request $request)
        {
            $userID = $request[‘id’];
            $user = User::findOrFail($userID);
            $date = date(“Y-m-d g:i:s”);
            $user->email_verified_at = $date; // to enable the “email_verified_at field of that user be a current time stamp by mimicing the must verify email feature
            $user->save();
            return response()->json(‘Email verified!’);
        }
    
        /**
        * Resend the email verification notification.
        *
        * @param \Illuminate\Http\Request $request
        * @return \Illuminate\Http\Response
        */
        public function resend(Request $request)
        {
            if ($request->user()->hasVerifiedEmail()) {
            return response()->json(‘User already have verified email!’, 422);
            // return redirect($this->redirectPath());
        }
    
        $request->user()->sendEmailVerificationNotification();
        return response()->json(‘The notification has been resubmitted’);
        // return back()->with(‘resent’, true);
        }
    }

    Now let’s create our own notification which will mimic the Must Verify Email notification , just create a folder under the app folder called “Notifications” and create a file named “VerifyApiEmail.php” and paste in the following code:

    <?php
    
    namespace App\Notifications;
    
    use Illuminate\Support\Carbon;
    use Illuminate\Support\Facades\URL;
    use Illuminate\Auth\Notifications\VerifyEmail as VerifyEmailBase;
    
    class VerifyApiEmail extends VerifyEmailBase
    {
        /**
        * Get the verification URL for the given notifiable.
        *
        * @param mixed $notifiable
        * @return string
        */
        protected function verificationUrl($notifiable)
        {
            return URL::temporarySignedRoute(
            ‘verificationapi.verify’, Carbon::now()->addMinutes(60), [‘id’ => $notifiable->getKey()]
            ); // this will basically mimic the email endpoint with get request
        }
    }

    Now all you have to do for it to work is bring in the notification that you created into your User Model like so use App\Notifications\VerifyApiEmail;
    and add the following method inside your user Model

    public function sendApiEmailVerificationNotification()
    {
        $this->notify(new VerifyApiEmail); // my notification
    }
    

    You are almost done now all you have to do is specify the route “‘verificationapi.verify” in your api route , it’s important to note that you need to add the following routes inside your api route for it to work

    Route::get(‘email/verify/{id}’, ‘VerificationApiController@verify’)->name(‘verificationapi.verify’);
    Route::get(‘email/resend’, ‘VerificationApiController@resend’)->name(‘verificationapi.resend’);

    The above code will take care of email verification and getting the proper response as “Email Verified”. But we still need to be able to send the email notification to the email of the user trying to register via api , for that let’s make a controller to handle the api registration request by the user. Let’s call it UsersApiController , run the following command to make the controller

    php artisan make:controller UsersApiController

    and paste in the following code in it

    <?php
    
    namespace App\Http\Controllers;
    
    use Illuminate\Http\Request;
    use App\User;
    use Illuminate\Support\Facades\Hash;
    use Auth;
    use Validator;
    use Illuminate\Foundation\Auth\VerifiesEmails;
    use Illuminate\Auth\Events\Verified;
    
    class UsersApiController extends Controller
    {
        use VerifiesEmails;
    
        public $successStatus = 200;
    
        /**
        * login api
        *
        * @return \Illuminate\Http\Response
        */
        public function login()
        {
            if (Auth::attempt([‘email’ => request(‘email’), ‘password’ => request(‘password’)])) {
                $user = Auth::user();
                    if ($user->email_verified_at !== NULL) {
                        $success[‘message’] = “Login successfull”;
                        return response()->json([‘success’ => $success], $this-> successStatus);
                    } else {
                        return response()->json([‘error’=>’Please Verify Email’], 401);
                    }
                } else {
                return response()->json([‘error’=>’Unauthorised’], 401);
            }
        }
    
        /**
        * Register api
        *
        * @return \Illuminate\Http\Response
        */
        public function register(Request $request)
        {
            $validator = Validator::make($request->all(), [
                ‘name’ => ‘required’,
                ‘email’ => ‘required|email’,
                ‘password’ => ‘required’,
                ‘c_password’ => ‘required|same:password’,
            ]);
    
            if ($validator->fails()) {
                return response()->json([‘error’=>$validator->errors()], 401);
            }
    
            $input = $request->all();
            $input[‘password’] = Hash::make($input[‘password’]);
            $user = User::create($input);
            $user->sendApiEmailVerificationNotification();
            $success[‘message’] = ‘Please confirm yourself by clicking on verify user button sent to you on your email’;
            return response()->json([‘success’=>$success], $this-> successStatus);
        }
    
        /**
        * details api
        *
        * @return \Illuminate\Http\Response
        */
        public function details()
        {
            $user = Auth::user();
            return response()->json([‘success’ => $user], $this-> successStatus);
        }
    }

    Now all we need to do is add the routes to tie up with the methods in our controller as following , again make sure to add this in your api routes

    Route::post(‘login’, ‘UsersApiController@login’);
    
    Route::post(‘register’, ‘UsersApiController@register’);
    
    Route::group([‘middleware’ => ‘auth:api’], function() {
        Route::post(‘details’, ‘UsersApiController@details’)->middleware(‘verified’);
    }); // will work only when user has verified the email

    Congratulations now you can recieve the email via Api registration , you can test the result in Postman by simply sending a POST Request to
    yourUrl/api/register — to register and you should get an email and you can simply click on the link at the email that you have recieved you will get a response as “Email verified” and user is now verified.

    Hope this article helps you in solving your API email verification in laravel . Please feel free to reach me out for any queries or doubt.

  • Laravel: Adding those missing helpers you always wanted

    One of the things I like from any PHP project is having global helpers. You know, those functions you can call anywhere and remove or save you many lines or verbosity into one, maybe two, while allocating in one place any logic.

    $expected = from($this)->do('foo');

    The problem with Laravel itself is that sometimes is not enough with the helpers it includes. The ones included are mostly quick access to Services (like cache()) or Factories (like response()), and some that help you having an expected result (like data_get).

    For example, let’s say we want a function be called multiple times but sleep between executions, like we would need to avoid rate limiting for an external API. Without a helper, we will have to resort to create a Class and put the logic inside a public static method, and hopefully remember where it is located.

    class Logics
    {
    public static function logic_sleep($times, $sleep, $callback)
    {
    // Run and sleep between calls.
    }
    }Logics::sleep(4, 10, function() {
    // ...
    });

    Using this technique makes your global not so globally. Since this is one of many thing I need in my projects, I decided to create a package with more global helpers:

    Larahelp

    Those helpers you always wanted

    The main idea of a global helper, at least to me, is to have a piece of code that offers simplicityreadability and flexibility. Think about them as small swiss knives that you may put in your pocket.

    For example, the above can become its own global function, and we can call it literally anywhere.

    public function handle()
    {
    logic_sleep(10, 5, function () {
    $this->uploadRecords();
    });
    }

    The helper is very simple to operate, but we won’t know what the hell it does behind the scenes unless we dig into the source code, which is fair. In any case, having a global function of one or two words makes the whole code more readable. And since it’s our own helper, we can call it anything we want.

    How to add your own helpers

    But that’s is only one of the many helpers I decided to create for things I use a lot.

    To add global helpers to your project, you can simply add a PHP file with the global functions you want anywhere in your project (preferably inside your PSR-4 root folder) and tell Composer to load it.

    You are free to add how many files you want. I decided to separate them into categories like I did for my package to avoid having a wall of text full of functions.

    "autoload": {
    "psr-4": {
    "App\\": "app"
    },
    "files": [
    "app/Helpers/datetime.php",
    "app/Helpers/filesystem.php",
    "app/Helpers/http.php",
    "app/Helpers/objects.php",
    "app/Helpers/services.php"
    ]
    },

    I’m opened to suggestions too, so give it a go if you think it may be useful for you:

    DarkGhostHunter/Larahelp

    Supercharge your Laravel projects with more than 35 useful global helpers.

    github.com

  • Laravel localization and multi-language functionality in web

    Laravel localization and multi-language functionality in web

    MAKE USE OF LARAVEL FEATURES AND BEST PACKAGES FOR LOCALIZATION

    Laravel localization and multi-language functionality in web

    A step by step guide to implement multi-language functionality in your web projects

    Laravel made it so easy to implement a multi-language website. You can implement it with Laravel localization and just some tricks. Also, there is plenty of Laravel translation packages which you can use in your project. In this post, I will explain how to implement multi-language functionality.

    Creating a multi-language website requires two steps. Firstly, you need to detect user local language setting and change it bu user choice. Secondly, you need to translate messages and strings into user local language, in which we use Laravel localization.

    DETECTING AND SETTING USER LOCALE

    In order to detect user language setting, we need to create a language middleware. this middleware checks for locale setting in the user session. If there was no locale setting, the middleware sets a default locale setting. Then, it sets system locale by the user session setting.

    if (is_null(session('locale'))) {
        session(['locale'=> "en"]);
    }
    app()->setLocale(session('locale'));

    Setting locale is enough for Laravel localization to work. After that, we need a simple function To change the system language. This function gets a locale string and sets the user locale session.

    public function change_lang($lang) {
        if (in_array($lang,['en','tr','fa'])) {
            session(['locale'=> $lang]);
        }
        return back();
    }

    In order to make sure the given string is a locale string, we check the language string against an array of locales.

    Any route to that function, like a drop down to select language will work perfectly and will show your website multi-language functionality for users. So they can easily choose their languages.

    Using Laravel localization to translate strings

    Every string that needed to be translated must be in Laravel lang directive or __ function. For example, you can manage all message strings with inside messages.

    @lang('messages.successful_login')

    In addition, you can find more useful information about localization like how to put variables inside translation strings in Laravel documentation.

    Laravel Langman package is one of the useful packages for translation. In order to translate strings, every time you updated views with new strings, you just need to run Langman sync command:
    php artisan langman:sync

    Laravel Langman has a lot more commands that would help you in your Laravel project localization. Reading through its documentation will add a lot.

    Although this method is easy and enough, I realized that for SEO purposes and to share localized links to your website, you better consider concatenating user locale in your projects routes. Then, you can check user locale from the query string and the rest is just as same as I explained in this post.

    Keep in touch and share your ideas about Laravel localization and how you implement multi-language functionality in your web projects. What other methods and Laravel packages do you use in your multi-language projects?

    Also, you can read my other post about Laravel authorization and user’s permission management in Laravel.

    If you find this multi-language functionality method useful in Laravel and you may want to implement this on your Laravel projects, share your ideas with me. Follow me on Twitter, Let’s connect on LinkedIn and give me a visit to amiryousefi.com

  • Laravel authorization and roles permission management

    EASY AND FLEXIBLE USERS PERMISSIONS MANAGEMENT

    Laravel authorization and roles permission management

    a simple guide for a flexible authentication and authorization

    Inmany web projects, we have different user roles interacting with the system. Each role has its own permission. Every feature of the system can be enabled or disabled for these roles. We can define users permissions in our codes and check if they are authorized to do the requested action or not. A better way, mostly in more flexible systems, is to create a role and authorization management system. I’ll explain how to implement a Laravel authorization system and define users permission based on their roles.

    In this post, firstly we manage users in groups we called roles. Every role has different permissions. In order to avoid permissions conflict, we assume each user has only one role. Secondly, Laravel authorization implemented by middleware. This middleware checks for the user’s role permission and authorizes user requests.

    CREATING ROLES AND PERMISSIONS

    In order to implement Laravel authorization, we will create roles and permissions table. To assign a role for users, we create a roles table. The migration for roles table is as simple as this:

    Schema::create(‘roles’, function (Blueprint $table) {
        $table->increments(‘id’);
        $table->string(‘name’);
        $table->string(‘description’)->nullable();
        $table->timestamps();
    });

    We have an ID and name for roles. All users will be managed in these roles. There is also a description field, because you may need a short note on roles to describe each role for yourself.

    After that, we add a foreign key, role_id, in the user table. Adding this field to the default user model helps us for Laravel authorization.

    $table->unsignedInteger(‘role_id’)->index();
    $table->foreign(‘role_id’)->references(‘id’)->on(‘roles’);

    Now let’s talk about the permissions table. Every request leads to a method of a controller. So we store a list of all methods and their controller’s name in the permissions table. Later, we explain how we gather this list and how we check users authorization in Laravel by this permissions table.

    Schema::create(‘permissions’, function (Blueprint $table) {
        $table->increments(‘id’);
        $table->string(‘name’)->nullable();
        $table->string(‘key’)->nullable();
        $table->string(‘controller’);
        $table->string(‘method’);
        $table->timestamps();
    });

    Finally, a relationship created between roles and permission.

    Schema::create(‘permission_role’, function (Blueprint $table) {
        $table->unsignedInteger(‘permission_id’);
        $table->unsignedInteger(‘role_id’);$table->foreign(‘permission_id’)
            ->references(‘id’)
            ->on(‘permissions’)
            ->onDelete(‘cascade’);$table->foreign(‘role_id’)
            ->references(‘id’)
            ->on(‘roles’)
            ->onDelete(‘cascade’);$table->primary([‘permission_id’, ‘role_id’]);
    });

    We created a complete users->roles->permissions architecture. After that, an access list will be stored in these tables. So, we can easily implement Laravel authorization by checking requests against this list.

    Read Laravel migration documentation for further information about creating tables.

    CREATING AN ACCESS LIST FOR USER PERMISSIONS

    The whole purpose of this post is about being dynamic. Especially, in systems with a different type of roles. We need to create a list of permissions in the system. Also, this list must be updated as the system developed. List of controllers and methods is a good representation of all permissions in the system. Every route is leading to a method of a controller. So, it’s a good idea to make a list of permissions using the routes list.

    In order to do that, I used a Laravel database seeder. Firstly, let’s write a role seeder. It creates basic roles we need and stores them in the roles table. Running this artisan command will create RolesSeeder for you:

    php artisan make:seeder RolesTableSeeder

    Inside this RolesTableSeeder, we create our basic roles:

    DB::table(‘roles’)->insert([
        [‘name’ => ‘admin’],
        [‘name’ => ‘operator’],
        [‘name’ => ‘customer’],
    ]);

    You can add as many roles as you need. Also, you can create new roles from your website whenever you need a new one.

    The second step is to create an authorization list for each role. we create another Laravel seeder in which populate permissions table:

    php artisan make:seeder PermissionTableSeeder

    Firstly, we get all routes list. Then, We check up with the database if the permission already stored. After that, if this permission is not in the table already, we insert new permissions in the permissions table. After all, we attach all permissions to the admin role.

    $permission_ids = []; // an empty array of stored permission IDs
    // iterate though all routes
    foreach (Route::getRoutes()->getRoutes() as $key => $route) {
        // get route action
        $action = $route->getActionname(); // separating controller and method
        $_action = explode(‘@’, $action);
    
        $controller = $_action[0];
        $method = end($_action);
    
        // check if this permission is already exists
        $permission_check = Permission::where(
            [‘controller’ => $controller, ’method’ => $method]
        )->first();
        if (!$permission_check) {
            $permission = new Permission;
            $permission->controller = $controller;
            $permission->method = $method;
            $permission->save();
    
            // add stored permission id in array
            $permission_ids[] = $permission->id;
        }
    } // find admin role.
    $admin_role = Role::where(‘name’, ’admin’)->first(); // atache all permissions to admin role
    $admin_role->permissions()->attach($permission_ids);

    LARAVEL AUTHORIZATION USING MIDDLEWARE

    Every request in Laravel goes through middleware. Knowing that creating RolesAuth middleware will do Laravel authorization. You can create the middleware manually or by an artisan command:

    php artisan make:middleware RolesAuth

    Inside this middleware, we get all permissions for logged in user. Then, we check if the requested action is in the permissions list. If requested action can’t be found in permissions list, a 403 error response returns.

    // get user role permissions
    $role = Role::findOrFail(auth()->user()->role_id);
    $permissions = $role->permissions; // get requested action
    $actionName = class_basename($request->route()->getActionname()); // check if requested action is in permissions list
    foreach ($permissions as $permission) {
        $_namespaces_chunks = explode(‘\’, $permission->controller);
        $controller = end($_namespaces_chunks);
        if ($actionName == $controller . ‘@’ . $permission->method) {
            // authorized request
            return $next($request);
        }
    } // none authorized request
    return response(‘Unauthorized Action’, 403);

    Finally, you can register this middleware in Laravel and use it according to your requirements.

    I started publishing my experience about Laravel development, here you can see my post about Laravel localization. Comment your questions about this post or any other Laravel development questions in this area.

    Update 2020:
    Now you can use my Laravel permission package build based this article. It just got better, cleaner, and easier to understand.
    https://github.com/amiryousefi/laravel-permission

  • Create an Admin middleware for Laravel with spatie/laravel-permission

    Although there are many articles about this topic, I decided to document this in a post for my future self and to share with all of you the approach I usually use to separate an application depending on specific roles.

    Middleware provide a convenient mechanism for filtering HTTP requests entering your application. For example, Laravel includes a middleware that verifies the user of your application is authenticated. If the user is not authenticated, the middleware will redirect the user to the login screen. However, if the user is authenticated, the middleware will allow the request to proceed further into the application.

    Additional middleware can be written to perform a variety of tasks besides authentication. A CORS middleware might be responsible for adding the proper headers to all responses leaving your application. A logging middleware might log all incoming requests to your application.

    There are several middleware included in the Laravel framework, including middleware for authentication and CSRF protection. All of these middleware are located in the app/Http/Middleware directory.


    Creating a custom Admin middleware in Laravel

    Spatie/laravel-permission is great package developed by Spatie team that allows you to manage user permissions and roles in a database.

    For this example we are going to install the package and create a custom middleware to group our administration routes into a new single route file under the same access control logic for all admin routes.

    I will simplify the example in this post to use only two roles: Admin and User (without assigning specific permissions).

    Setup of spatie/laravel-permission package

    First of all, you must fill your .env file with a new database configuration.

    This package can be used in Laravel 5.4 or higher. If you are using an older version of Laravel, take a look at the v1 branch of this package.

    You can install the package via composer:

    composer require spatie/laravel-permission

    The service provider will automatically get registered. Or you may manually add the service provider in your config/app.php file:

    'providers' => [
        // ...
        Spatie\Permission\PermissionServiceProvider::class,
    ];

    You can publish the migration with:

    php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider" --tag="migrations"

    After the migration has been published you can create the role- and permission-tables by running the migrations:

    php artisan migrate

    Optionally you can publish the config file with:

    php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider" --tag="config"

    add the Spatie\Permission\Traits\HasRoles trait to your User model(s):

    use Illuminate\Foundation\Auth\User as Authenticatable;
    use Spatie\Permission\Traits\HasRoles;

    Using Laravel Authentication system

    Make sure of the Laravel authentication feature is present, if not, you can setup this with the artisan command:

    php artisan make:auth

    Creating some Users

    Now add some users to your application, optionally you can use a Seeder to achieve this. For example, create a new RolesAndPermissionsSeeder by running:

    php artisan make:seeder RolesAndPermissionsSeeder

    Now paste the following code into the new seeder

    public function run()
    {
        // Reset cached roles and permissions
        app()['cache']->forget('spatie.permission.cache');
    
    
        Role::create(['name' => 'user']);

    Don’t forget to import the Role class with use Spatie\Permission\Models\Role. Now we have two different users with different roles.

    Note: How we have relied on the UserFactory class, the default password for both is password (in Laravel 5.8, for earlier versions the default password is secret)

    You can now seed your database with this command

    php artisan db:seed --class=RolesAndPermissionsSeeder

    Creating the new middleware with the custom route file

    We are ready to create a new middleware to separate admin routes of user routes. It should be noted that an administrator can access the routes of a normal user, but not in an inverse way.

    Step 0: Add a test

    To achieve this quickly, I will rely on the use of automated tests using the integrated phpunit on Laravel:

    php artisan make:test RolesAccessTest

    And add the following tests:

    <?php
    
    namespace Tests\Feature;
    
    use App\User;
    use Tests\TestCase;
    
    class RolesAccessTest extends TestCase
    {
        /** @test */
        public function user_must_login_to_access_to_admin_dashboard()
        {
            $this->get(route('admin.dashboard'))
                 ->assertRedirect('login');
        }
    
        /** @test */
        public function admin_can_access_to_admin_dashboard()
        {
            //Having
            $adminUser = factory(User::class)->create();
    
            $adminUser->assignRole('admin');
    
            $this->actingAs($adminUser);
    
            //When
            $response = $this->get(route('admin.dashboard'));
    
            //Then
            $response->assertOk();
        }
    
        /** @test */
        public function users_cannot_access_to_admin_dashboard()
        {
            //Having
            $user = factory(User::class)->create();
    
            $user->assignRole('user');
    
            $this->actingAs($user);
    
            //When
            $response = $this->get(route('admin.dashboard'));
    
            //Then
            $response->assertForbidden();
        }
    
        /** @test */
        public function user_can_access_to_home()
        {
            //Having
            $user = factory(User::class)->create();
    
            $user->assignRole('user');
    
            $this->actingAs($user);
    
            //When
            $response = $this->get(route('home'));
    
            //Then
            $response->assertOk();
        }
    
        /** @test */
        public function admin_can_access_to_home()
        {
            //Having
            $adminUser = factory(User::class)->create();
    
            $adminUser->assignRole('admin');
    
            $this->actingAs($adminUser);
    
            //When
            $response = $this->get(route('home'));
    
            //Then
            $response->assertOk();
        }
    }

    Obviously these assertions could be improved by adding others to check views and / or content that should be shown in those sections, but for the purposes of this post, these tests are sufficient.

    If you run this test now, you will get the following errors:

    ./vendor/bin/phpunit --filter RolesAccessTest
    PHPUnit 7.4.3 by Sebastian Bergmann and contributors.

    Let’s start writing the code so that this test passes:

    Create a new temporary route into the routes/web.php file, your file will look like this:

    Route::get('/', function () {
        return view('welcome');
    });
    
    Auth::routes();
    
    Route::get('/home', 'HomeController@index')->name('home');
    
    Route::get('/admin/dashboard', function(){
        return 'Wellcome Admin!';
    })->name('admin.dashboard');

    Now, re-run the test:

    ./vendor/bin/phpunit --filter RolesAccessTest
    PHPUnit 7.4.3 by Sebastian Bergmann and contributors.

    At this point, we have 2 failures only, the admin route is a public route and is not restricted to the Admin role only, let’s fix it in a few steps.

    Step 1: Create a map for the new Admin routes

    Go to the app\Providers\RouteServiceProvider. In the map method add a new function for map the Admin routes:

    public function map()
    {
        $this->mapApiRoutes();
    
        $this->mapWebRoutes();
    
        $this->mapAdminRoutes();
    
        //
    }

    and now implement the new mapAdminRoutes method inside the provider:

    protected function mapAdminRoutes()
    {
        Route::middleware('admin')
             ->namespace($this->namespace)
             ->group(base_path('routes/admin.php'));
    }

    Note: optionally, I recommend separating also the namespace of the controllers that will be used by the admin routesand that in addition the users must have the admin role

    ->namespace($this->namespace . '\\Admin')

    Step 2: Create new admin.php file into routes folder

    Add a new file into routes filder called admin.php and move the route for admins inside of this new file:

    <?php

    Step 3: Create the Admin middleware

    Open the app\Http\Kernel class and find the $routeMiddleware attribute and add two new middleware that belong to spatie/laravel-permission package :

    protected $routeMiddleware = [
        ...
        'role' => \Spatie\Permission\Middlewares\RoleMiddleware::class,
        'permission' => \Spatie\Permission\Middlewares\PermissionMiddleware::class,
    ];

    And in the $middlewareGroups attribute add this new admin middleware group:

    protected $middlewareGroups = [
        'web' => [
            ....
        ],
    
        'admin' => [
            'web',
            'auth',
            'role:admin'
        ],
    
        'api' => [
            ...
        ],
    ];

    This group specifies that the middleware will make use of the web and auth middlewares, and that in addition the users must have the admin role. This middleware group was indicated into mapAdminRoutesmethod into our RouteServiceProvider.

    Final Step:

    Now you can re-run the tests and check the results

    ./vendor/bin/phpunit — filter RolesAccessTest
    PHPUnit 7.4.3 by Sebastian Bergmann and contributors.

    Now we have the new middleware working correctly to restrict access to administration routes only to the corresponding users. You can also perform a manual check with the created users in the Seeder

    Admin user successfully logged in into the admin routes

    And if you try to enter in the admin routes with the normal user you will get an Forbidden response:

    Normal user cannot enter to admin routes

    In Closing

    With this approach you will get a clear separation for the Admin routes and the normal User routes. We only needed to:

    • Install and configure spatie/laravel-permission
    • Create and assign desired Roles to Users
    • Create a new admin middleware group in the app\Http\Kernel class
    • Create a new mapAdminRoutes into the RouteServiceProvider to map a new routes/admin.php file and assign it to the new admin middleware group

    And some advantages of this approach are the separations of concerns for different app components:

    • Separated routes files
    • Separated Controllers with a custom namespace

    And also you can use this approach to separate resources files as assets or layouts and view files.

    As we have guided our development by the use of automated tests (TDD), we have not needed to manually test with each user of our application during the development, which is also another great advantage.

    Informatics Engineer | Musician

  • The Difference Between Active Directory and LDAP

    The Difference Between Active Directory and LDAP

    Any hacker knows the keys to the network are in Active Directory (AD). Once a hacker has access to one of your user accounts, it’s a race against you and your data security protections to see if you can stop them before they can start a data breach.

    It’s important to know Active Directory backwards and forwards in order to protect your network from unauthorized access – and that includes understanding LDAP.

    What is LDAP?

    LDAP (Lightweight Directory Access Protocol) is an open and cross platform protocol used for directory services authentication.

    LDAP provides the communication language that applications use to communicate with other directory services servers. Directory services store the users, passwords, and computer accounts, and share that information with other entities on the network.

    What is Active Directory?

    Active Directory is a directory services implementation that provides all sorts of functionality like authentication, group and user management, policy administration and more.

    Active Directory (AD) supports both Kerberos and LDAP – Microsoft AD is by far the most common directory services system in use today. AD provides Single-SignOn (SSO) and works well in the office and over VPN. AD and Kerberos are not cross platform, which is one of the reasons companies are implementing access management software to manage logins from many different devices and platforms in a single place. AD does support LDAP, which means it can still be part of your overall access management scheme.

    Active Directory is just one example of a directory service that supports LDAP. There are other flavors, too: Red Hat Directory Service, OpenLDAP, Apache Directory Server, and more.

    LDAP vs. Active Directory

    LDAP is a way of speaking to Active Directory.

    LDAP is a protocol that many different directory services and access management solutions can understand.

    The relationship between AD and LDAP is much like the relationship between Apache and HTTP:

    • HTTP is a web protocol.
    • Apache is a web server that uses the HTTP protocol.
    • LDAP is a directory services protocol.
    • Active Directory is a directory server that uses the LDAP protocol.

    Occasionally you’ll hear someone say, “We don’t have Active Directory, but we have LDAP.” What they probably mean is that they have another product, such as OpenLDAP, which is an LDAP server.
    It’s kind of like someone saying “We have HTTP” when they really meant “We have an Apache web server.”

    What is LDAP Authentication?

    There are two options for LDAP authentication in LDAP v3 – simple and SASL (Simple Authentication and Security Layer).

    Simple authentication allows for three possible authentication mechanisms:

    • Anonymous authentication: Grants client anonymous status to LDAP.
    • Unauthenticated authentication: For logging purposes only, should not grant access to a client.
    • Name/Password authentication: Grants access to the server based on the credentials supplied – simple user/pass authentication is not secure and is not suitable for authentication without confidentiality protection.

    SASL authentication binds the LDAP server to another authentication mechanism, like Kerberos. The LDAP server uses the LDAP protocol to send an LDAP message to the other authorization service. That initiates a series of challenge response messages that result in either a successful authentication or a failure to authenticate.

    It’s important to note that LDAP passes all of those messages in clear text by default, so anyone with a network sniffer can read the packets. You need to add TLS encryption or similar to keep your usernames and passwords safe.

    What is an LDAP Query?

    An LDAP query is a command that asks a directory service for some information. For instance, if you’d like to see which groups a particular user is a part of, you’d submit a query that looks like this:

    (&(objectClass=user)(sAMAccountName=yourUserName)
    (memberof=CN=YourGroup,OU=Users,DC=YourDomain,DC=com))

    Beautiful syntax, huh? Not quite as simple as typing a web address into your browser. Feels like LISP.

    Luckily, in most cases, you won’t need to write LDAP queries. To maintain your sanity, you’ll perform all your directory services tasks through a point-and-click management interface like Varonis DatAdvantage or perhaps using a command line shell like PowerShell that abstracts away the details of the raw LDAP protocol.

    TL;DR: LDAP is a protocol, and Active Directory is a server. LDAP authenticates Active Directory – it’s a set of guidelines to send and receive information (like usernames and passwords) to Active Directory. Want to learn more? Get a 1:1 AD demo and learn how Varonis helps protect your Active Directory environment.

  • Setting up Google Directory Sync with OpenLDAP

    I’ll be adding updates to my new blog here: https://blog.salrashid.me/

    Introduction

    Tutorial on how to provision users and groups from a local LDAP server (OpenLDAP) into your G-suites domain. Any users and groups present in your local LDAP server will get created in G-suites. Once your users are present in your G-suites domain, you can authorize these users and groups access to Google Cloud Resources and other G-suites features.

    This article is simply a tutorial on the simplified steps you would take for your on-prem directory server (ActiveDirectory, OpenLDAP). The Directory Sync utility overwrites any existing G-suites users and groups in favor of your local LDAP. As this is just a tutorial, only execute the ‘dry-run/simulate’ capabilities unless you are absolutely sure. You will need Domain Admin user privileges to your G-suites domain.

    This sample will only sync the basic Users and Groups objects from your LDAP to G-suites.

    Some references on the Directory Sync tool:

    If you are a Google Cloud Platform user, consider migrating your organization after you have setup Directory Sync

    This article is a copy of my github page.

    OpenLDAP configuration

    This tutorial run a Docker container with a configurable OpenLDAP server that you can setup and load sample data reflecting your LDAP hierarchy. The the sample LDIF file is very basic and enables the domain dc=example, dc=com with users under ou=users and groups under ou=groups

    You can edit the slapd.conf file and import.ldif file to map to your users and directory structure. You will need to initialize and load the LDIF files once the container starts up as shown below

    ** NOTE: I’ve made some specific modifications to the objectclass mappings for a users groups display name for simplicity **

    Download the sample Dockerfile and LDAP configuration

    Start the LDAP server

    The first step is to setup the local LDAP server. You will need to clone the gitrepo to acquire the sample Dockerfile and ldap configurations.

    Build the container

    docker build -t myldap .

    Start the container

    docker run -p 1389:389 -p 1636:636 myldap slapd  -h "ldap://0.0.0.0:389  ldaps://0.0.0.0:636" -d 3 -f /ldap/slapd.conf

    Install LDAP utilities on the host

    Either: Install some LDAP utilities you will need on the docker host

    apt-get install ldap-utils

    Alternatively, you can install an LDAP UI like Apache Directory Studio.

    Initialize your LDAP server

    Load the sample data

    ldapadd -v -x -D "cn=admin,dc=example,dc=com" -w mypassword  -H ldap://localhost:1389 -f import.ldif

    If you used Apache Directory Studio, you can load and execute the .ldif file directly (“LDAP →New LDIF FIle”) after you establish a connection:

    Verify via query

    ldapsearch -v -x -D "cn=admin,dc=example,dc=com" -w mypassword -b "ou=people,dc=example,dc=com" -H ldap://localhost:1389

    If you use Directory Studio, you can browse the imported LDAP structure in the console directly.

    Setup dry-run Google Directory Sync

    Once the LDAP server is running, we need to run the Directory Sync utility.

    Again only run the Directory Sync in dry-run mode!!

    Download and Start the Directory Sync utility Download: https://support.google.com/a/answer/6120989 Launch:

    $ GoogleCloudDirSync/config-manager

    Setup the Google Domain Configuration

    You need to be domain super user to syn and run this utility:

    Connect to the LDAP server

    Connect as cn=admin,dc=example,dc=com. The default password is mypassword

    If you are using ldaps://, you need to add in the certificate chain first:

    cd GoogleCloudDirSync/jre
    $ keytool -keystore lib/security/cacerts -storepass changeit -import -file path_to_your/ldap_crt.pem -alias mydc
    $ keytool -keystore lib/security/cacerts -storepass changeit -import -file path_to_your/CA_crt.pem -alias myca

    Select Users and Groups to sync

    User Configuration

    I’ve made some specific maps for LDAP attributes to G-suites attributes:

    • cn -> Unique identifer attribute
    • mail -> email address to use
    • givenName -> Users Firstname
    • sn -> Users Lastname
    • userPassword -> SHA1 format for the users local LDAP password

    The users in LDAP are found under ou=People,dc=example,dc=com and the primary identifier is cn

    The SHA format for the password can be derived using sample utilities bundled with openldap:

    slappasswd -h  {SHA} -s mypassword
    {SHA}kd/Z3bQZiv/FwZTNjObTOP3kcOI=

    Groups Configuration

    I did not want to override the default openldap schema so I ended up using the description attribute of objectclass: groupofuniquenames as the attribute the utility will use to infer the Group Email Address:

    • Group Email Address Attribute: description

    Meaning the LDAP’s description field for a groupofuniquenames denotes the email address to provision in G-suites.

    You can search for the groups by looking in the subtree for:

    (&(objectClass=groupOfUniqueNames)(cn=*))

    For example:

    dn: cn=engineering, ou=groups, dc=example,dc=com
    cn: engineering
    objectclass: groupofuniquenames
    description: engineering@example.com
    uniqueMember: cn=user1,ou=people, dc=example,dc=com
    uniqueMember: cn=user2,ou=people, dc=example,dc=com

    To verify, select “Test Query” button:

    Execute Dry-Run Sync

    Now that you are all setup, click the ‘Simulate sync’ button to see what would happen.

    REMEMBER TO SELECT “SIMULATE SYNC”

    If had existing users already in my apps domain and I tried to import new ones, the reconciliation favored the local LDAP (meaning it would add local ldap and delete existing accounts~)

    Execute Sync

    Only execute a full sync if you are absolutely sure this is what you want to do!!

    If you are confident on the sync setup, you can initiate the full synchronization. Once the users and groups are committed, you can see them in the Google Apps domain console.

    Note, the setup does not sync or overwrite the domain admin users.

    You can also backup/export your existing users list first to a .csv file prior to running the full sync.

    The following changes were applied on the Google domain:-
    *****************************************************************************Change Status Report, Generated 10:09:17 AM Dec 28, 2016
    Successful user changes:
    Deleted: 0
    Modified: 0
    Created: 2Failures:
    Delete: 0
    Modify: 0
    Create: 0Created 2 new users
    User: "user1@example.com"
    Local key "dXNlcjE"
    Given name "user1"
    Family name "user1"
    Set SHA-1 password hashUser: "user2@example.com"
    Local key "dXNlcjI"
    Given name "user2"
    Family name "user2"
    Set SHA-1 password hash
    Successful group changes:
    Deleted: 0
    Modified: 2
    Created: 2Failures:
    Delete: 0
    Modify: 0
    Create: 0Successfully modified 2 groups
    Group: "finance@example.com"
    Added user user1@example.comGroup: "engineering@example.com"
    Added user user1@example.com
    Added user user2@example.com
    Created 2 new groups
    Group: "engineering@example.com"
    Group: "finance@example.com"The following changes were proposed:-
    *****************************************************************************Proposed Change Report, Generated 10:09:16 AM Dec 28, 2016Analyzed users:
    2 local
    1 remoteProposed changes:
    Delete: 0
    Modify: 0
    Create: 2Create - 2 total
    New user 1: "user1@example.com"
    Non-address primary key "dXNlcjE"
    Given name "user1"
    Family name "user1"
    SHA1 password
    0 aliasesNew user 2: "user2@example.com"
    Non-address primary key "dXNlcjI"
    Given name "user2"
    Family name "user2"
    SHA1 password
    0 aliasesAnalyzed groups:
    2 local
    0 remoteProposed changes:
    Delete: 0
    Modify: 2
    Create: 2
    Create Group(s) - 2 total
    "engineering@example.com"
    "finance@example.com"
    Modify (all proposed changes) - 2 total groups affected
    Modify group 1: "engineering@example.com"
    Add address "user1@example.com"
    Add address "user2@example.com"Modify group 2: "finance@example.com"
    Add address "user1@example.com"

    Directory Sync via Admin API

    You can also script the provisioning and management of users and groups via the G-suites APIs such as Directory API

    #!/usr/bin/pythonfrom apiclient.discovery import build
    import httplib2
    from oauth2client.service_account import ServiceAccountCredentials
    from oauth2client.client import GoogleCredentials
    import logging
    import json
    import sys
    from apiclient import discovery
    import oauth2client
    from oauth2client import client
    from oauth2client import toolsscope = 'https://www.googleapis.com/auth/admin.directory.user'
    credentials = ServiceAccountCredentials.from_p12_keyfile('adminapi@fabled-ray-104117.iam.gserviceaccount.com',
    'project1-5fc7d442817b.p12',
    scopes=scope)
    credentials = credentials.create_delegated('admin@example.com')
    http = httplib2.Http()
    http = credentials.authorize(http)
    service = discovery.build('admin', 'directory_v1', http=http)
    results = service.users().list(customer='C023zw2x7', domain='example.com').execute()
    users = results.get('users', [])
    print json.dumps(users, sort_keys=True, indent=4)
    for u in users:
    print json.dumps(u['primaryEmail'], sort_keys=True, indent=4)