This post is from the professional Laravel developer community, original link: learnku.com/laravel/t/2…
In this article, we’ll learn how to build restful apis in Laravel using JWT authentication. JWT stands for JSON Web Tokens. We will also use the API to create full-featured CRUD applications for user products.
Apis are a great choice when working with cross-platform applications. In addition to the website, your product may have Android and iOS apps. In this case, the API is just as good because you can write a different front end without changing any of the back end code. When using the API, simply click GET, POST, or some other type of request with a few parameters, and the server returns data in JSON(JavaScript Object Notation) format that is processed by the client application.
instructions
Let’s start by writing down our application details and functionality. We will use JWT authentication to build a list of basic user products using restful apis in Laravel.
A User will use the following functions
- Register and create a new account
- Log in to their account
- Unregister and discard tokens and leave the application
- Get the details of the logged-in user
- Retrieves the list of products available to the user
- Find a specific product by ID
- Add the new product to the user product list
- Edit existing product details
- Remove existing products from the user list
A User required
- name
- password
The Product will fill A
- name
- price
- quantity
Creating a new project
We can start and create a new Laravel project by running the following command.
composer create-project --prefer-dist laravel/laravel jwt
Copy the code
This creates a new Laravel project in a directory named JWT.
Configure the JWT extension pack
We will use the Tymondesigns/JWT-Auth extension pack to let us use JWT in Laravel.
Install the Tymon/JwT-Auth extension pack
Let’s install the extension pack in the Laravel application. If you are using Laravel 5.5 or above, run the following command to get the JWT package for dev-develop:
composer require tymon/jwt-auth:dev-develop --prefer-source
Copy the code
If you are using Laravel 5.4 or below, run the following command:
composer require tymon/jwt-auth
Copy the code
For Laravel versions lower than 5.5, you also set the service provider and alias in the config/app.php file.
'providers'=> [ .... Tymon\JWTAuth\Providers\JWTAuthServiceProvider::class, .... ] .'aliases'= > [...'JWTAuth' => Tymon\JWTAuth\Facades\JWTAuth::class,
'JWTFactory'= >'Tymon\JWTAuth\Facades\JWTFactory'. ] .Copy the code
If your Laravel version is 5.5 or above, Laravel does “automatic package discovery.”
Publishing configuration files
For Laravel 5.5 or above, use the following command to publish the configuration file:
php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"
Copy the code
For previous versions of Laravel, run the following command:
php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\JWTAuthServiceProvider"
Copy the code
The command above generates the config/jwt.php configuration file. Without the comments, the configuration file looks like this:
<? phpreturn [
'secret' => env('JWT_SECRET'),
'keys'= > ['public' => env('JWT_PUBLIC_KEY'),
'private' => env('JWT_PRIVATE_KEY'),
'passphrase' => env('JWT_PASSPHRASE')],'ttl' => env('JWT_TTL', 60).'refresh_ttl' => env('JWT_REFRESH_TTL', 20160),
'algo' => env('JWT_ALGO'.'HS256'),
'required_claims'= > ['iss'.'iat'.'exp'.'nbf'.'sub'.'jti',].'persistent_claims'= > [/ /'foo', / /'bar',].'lock_subject'= >true.'leeway' => env('JWT_LEEWAY', 0).'blacklist_enabled' => env('JWT_BLACKLIST_ENABLED'.true),
'blacklist_grace_period' => env('JWT_BLACKLIST_GRACE_PERIOD', 0).'decrypt_cookies'= >false.'providers'= > ['jwt' => Tymon\JWTAuth\Providers\JWT\Lcobucci::class,
'auth' => Tymon\JWTAuth\Providers\Auth\Illuminate::class,
'storage' => Tymon\JWTAuth\Providers\Storage\Illuminate::class,
],
];
Copy the code
Generate the JWT key
JWT tokens are issued using an encrypted key. For Laravel 5.5 or above, run the following command to generate the key for token issuance.
php artisan jwt:secret
Copy the code
Laravel versions lower than 5.5 run:
php artisan jwt:generate
Copy the code
This tutorial uses Laravel 5.6. The next steps in the tutorial have only been tested in 5.5 and 5.6. May not work with Laravel 5.4 or below. You can read the documentation for older versions of Laravel.
Registered middleware
The JWT Certification extension comes with middleware that allows us to use it. To register auth.jwt middleware in app/Http/ kernel. PHP:
protected $routeMiddleware= [...'auth.jwt' => \Tymon\JWTAuth\Http\Middleware\Authenticate::class,
];
Copy the code
The middleware verifies the user’s authentication by checking the token attached to the request. If the user authentication, not the middleware will throw UnauthorizedHttpException anomalies.
Set the routing
Before we begin, we will set up routes for all the points discussed in this tutorial. Open routes/api.php and copy the following routes into your file.
Route::post('login'.'ApiController@login');
Route::post('register'.'ApiController@register');
Route::group(['middleware'= >'auth.jwt'].function () {
Route::get('logout'.'ApiController@logout');
Route::get('user'.'ApiController@getAuthUser');
Route::get('products'.'ProductController@index');
Route::get('products/{id}'.'ProductController@show');
Route::post('products'.'ProductController@store');
Route::put('products/{id}'.'ProductController@update');
Route::delete('products/{id}'.'ProductController@destroy');
});
Copy the code
Updating the User model
JWT needs to implement the Tymon\JWTAuth\Contracts\JWTSubject interface in the User model. This interface needs to implement two methods, getJWTIdentifier and getJWTCustomClaims. Update app/ user.php with the following.
<? php namespace App; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; use Tymon\JWTAuth\Contracts\JWTSubject; class User extends Authenticatable implements JWTSubject { use Notifiable; /** * The attributes that are mass assignable. * * @var array */ protected$fillable = [
'name'.'email'.'password',]; /** * The attributes that should be hiddenfor arrays.
*
* @var array
*/
protected $hidden = [
'password'.'remember_token',]; /** * Get the identifier that will be storedin the subject claim of the JWT.
*
* @return mixed
*/
public function getJWTIdentifier()
{
return $this->getKey();
}
/**
* Return a key value array, containing any custom claims to be added to the JWT.
*
* @return array
*/
public function getJWTCustomClaims()
{
return[]; }}Copy the code
JWT authentication logic
Let’s write the Restful API logic in Laravel using JWT authentication.
Users need a name, email address and password to register. So, let’s create a form request to validate the data. Create a form request named RegisterAuthRequest by running the following command: RegisterAuthRequest
php artisan make:request RegisterAuthRequest
Copy the code
It will create the registerAuthRequest.php file in the app/Http/Requests directory. Paste the following code into the file.
<? php namespace App\Http\Requests; use Illuminate\Foundation\Http\FormRequest; Class RegisterAuthRequest extends FormRequest {/** * Determines whether the user is authorized to make this request ** @return bool
*/
public function authorize()
{
return true; } /** * gets the validation rule ** @ applied to the requestreturn array
*/
public function rules()
{
return [
'name'= >'required|string'.'email'= >'required|email|unique:users'.'password'= >'required|string|min:6|max:10']; }}Copy the code
Run the following command to create a new ApiController:
php artisan make:controller ApiController
Copy the code
This will create the apicontroller.php file in the app/Http/Controllers directory. Paste the following code into the file.
<? php namespace App\Http\Controllers; use App\Http\Requests\RegisterAuthRequest; use App\User; use Illuminate\Http\Request; use JWTAuth; use Tymon\JWTAuth\Exceptions\JWTException; class ApiController extends Controller { public$loginAfterSignUp = true;
public function register(RegisterAuthRequest $request)
{
$user = new User();
$user->name = $request->name;
$user->email = $request->email;
$user->password = bcrypt($request->password);
$user->save();
if ($this->loginAfterSignUp) {
return $this->login($request);
}
return response()->json([
'success'= >true.'data'= >$user
], 200);
}
public function login(Request $request)
{
$input = $request->only('email'.'password');
$jwt_token = null;
if (!$jwt_token = JWTAuth::attempt($input)) {
return response()->json([
'success'= >false.'message'= >'Invalid Email or Password',], 401); }return response()->json([
'success'= >true.'token'= >$jwt_token,]); } publicfunction logout(Request $request)
{
$this->validate($request['token'= >'required'
]);
try {
JWTAuth::invalidate($request->token);
return response()->json([
'success'= >true.'message'= >'User logged out successfully'
]);
} catch (JWTException $exception) {
return response()->json([
'success'= >false.'message'= >'Sorry, the user cannot be logged out'
], 500);
}
}
public function getAuthUser(Request $request)
{
$this->validate($request['token'= >'required'
]);
$user = JWTAuth::authenticate($request->token);
return response()->json(['user'= >$user]); }}Copy the code
Let me explain what happened to the code above.
In the Register method, we receive the RegisterAuthRequest. Create a user using the data in the request. If the loginAfterSignUp attribute is true, the user is logged in by calling the login method after registration. Otherwise, a successful response is returned with user data.
In the Login method, we get a subset of the request, which contains only the E-mail and password. JWTAuth:: Attempt () is called with the input value as an argument, and the response is stored in a variable. If false is returned from the Attempt method, a failed response is returned. Otherwise, a successful response is returned.
In the logout method, verify that the request contains token validation. Invalidate the token by calling the invalidate method and return a successful response. If a JWTException exception is caught, a failed response is returned.
In the getAuthUser method, verify that the request contains a token field. The Authenticate method is then called, which returns the authenticated user. Finally, the response is returned with the user.
The authentication section is now complete.
Building the product part
To create the Product section, we need the Product model, controller, and migration file. Run the following commands to create the Product model, controller, and migrate files.
php artisan make:model Product -mc
Copy the code
It creates a new database migration file create_products_table.php in the database/migrations directory, changing the up method.
public function up()
{
Schema::create('products'.function (Blueprint $table) {
$table->increments('id');
$table->integer('user_id');
$table->string('name');
$table->integer('price');
$table->integer('quantity');
$table->timestamps();
$table->foreign('user_id')
->references('id')
->on('users')
->onDelete('cascade');
});
}
Copy the code
Add the Fillable attribute to the Product model. Open the product.php file in the app directory and add attributes.
protected $fillable = [
'name'.'price'.'quantity'
];
Copy the code
Now set up the database credentials in the.env file and migrate the database by running the following command.
php artisan migrate
Copy the code
Now we must add a relationship to the User model to retrieve the related products. Add the following methods in app/ user.php.
public function products()
{
return $this->hasMany(Product::class);
}
Copy the code
Open the productController.php file in app/Http/Controllers. Overwrite the previous one by adding the use directive at the beginning of the file.
use App\Product;
use Illuminate\Http\Request;
use JWTAuth;
Copy the code
Now we will implement five methods.
- Index, to get a list of all products for authenticated users
- Show to get a specific product by ID
- Store to store new products in the product list
- Update, updates product details by ID
- Destroy, remove products from the list by ID
Add a constructor to get the authenticated user and store it in the User attribute.
protected $user;
public function __construct()
{
$this->user = JWTAuth::parseToken()->authenticate();
}
Copy the code
ParseToken parses the token from the request and authenticate the user with the token.
Let’s add the index method.
public function index()
{
return $this->user
->products()
->get(['name'.'price'.'quantity'])
->toArray();
}
Copy the code
The code above is very simple. We just grab all the products using our Eloquent method and assemble the results into an array. Finally, we return this array. Laravel will automatically convert this to JSON and create a 200 success response code.
Continue to implement the show method.
public function show($id)
{
$product = $this->user->products()->find($id);
if (!$product) {
return response()->json([
'success'= >false.'message'= >'Sorry, product with id ' . $id . ' cannot be found'
], 400);
}
return $product;
}
Copy the code
This is also very easy to understand. We just need to find the product by ID. If the product does not exist, a 400 fault response is returned. Otherwise, an array of products is returned.
Next up is the Store method
public function store(Request $request)
{
$this->validate($request['name'= >'required'.'price'= >'required|integer'.'quantity'= >'required|integer'
]);
$product = new Product();
$product->name = $request->name;
$product->price = $request->price;
$product->quantity = $request->quantity;
if ($this->user->products()->save($product))
return response()->json([
'success'= >true.'product'= >$product
]);
else
return response()->json([
'success'= >false.'message'= >'Sorry, product could not be added'
], 500);
}
Copy the code
In the Store method, verify that the request contains a name, price, and quantity. Then, use the data in the request to create a new product model. If the product successfully writes to the database, a success response is returned, otherwise a custom 500 failure response is returned.
Implementing the Update method
public function update(Request $request.$id)
{
$product = $this->user->products()->find($id);
if (!$product) {
return response()->json([
'success'= >false.'message'= >'Sorry, product with id ' . $id . ' cannot be found'
], 400);
}
$updated = $product->fill($request->all())
->save();
if ($updated) {
return response()->json([
'success'= >true
]);
} else {
return response()->json([
'success'= >false.'message'= >'Sorry, product could not be updated'], 500); }}Copy the code
In the update method, we get the product by ID. If the product does not exist, return a 400 response. We then populate the data from the request with the product details using the fill method. Update the product model and save it to the database, returning a 200 success response if the record is successfully updated, or 500 internal server error response to the client otherwise.
Now, let’s implement the destroy method.
public function destroy($id)
{
$product = $this->user->products()->find($id);
if (!$product) {
return response()->json([
'success'= >false.'message'= >'Sorry, product with id ' . $id . ' cannot be found'
], 400);
}
if ($product->delete()) {
return response()->json([
'success'= >true
]);
} else {
return response()->json([
'success'= >false.'message'= >'Product could not be deleted'], 500); }}Copy the code
In the destroy method, we get the product by ID and return a 400 response if it doesn’t exist. We then delete the product and return the appropriate response based on the successful status of the delete operation.
The controller code is now complete, the complete controller code is here.
test
Let’s start by testing authentication. We will use the serve command to start the Web service on the development machine, or you can use a virtual host instead. Run the following command to start the Web service.
php artisan serve
Copy the code
It will listen on localhost:8000
To test restful apis’, we use Postman. After filling in the request body, we request a register route.
Send the request and you will get the token.
Our users are now registered and authenticated. We can send another request to detect the LOGIN route, which returns 200 and the token.
Obtaining User Details
Test authentication is complete. Next, test the product section by first creating a product.
Now get the product by requesting the Index method.
Tutorial source code GitHub.