Skip to content

Commit

Permalink
Merge pull request #69 from laravelcm/setup-sanctum-api-login
Browse files Browse the repository at this point in the history
👽 Mis en place de l'api de connexion avec Sanctum
  • Loading branch information
mckenziearts authored Nov 2, 2022
2 parents 7bcf891 + 86c42a9 commit cfd7fd2
Show file tree
Hide file tree
Showing 10 changed files with 313 additions and 1 deletion.
59 changes: 59 additions & 0 deletions app/Http/Controllers/Api/Auth/LoginController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php

namespace App\Http\Controllers\Api\Auth;

use App\Http\Controllers\Controller;
use App\Http\Requests\Api\LoginRequest;
use App\Http\Resources\AuthenticateUserResource;
use App\Models\User;
use Carbon\Carbon;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Validation\ValidationException;

class LoginController extends Controller
{
public function login(LoginRequest $request): JsonResponse
{
$user = User::query()
->with(['roles', 'permissions'])
->where('email', strtolower($request->input('email')))
->first();

$sanitized = [
'email' => strtolower($request->input('email')),
'password' => $request->input('password'),
];

if (empty($user) || !Auth::attempt($sanitized)) {
throw ValidationException::withMessages([
'email' => 'Les informations d\'identification fournies sont incorrectes.',
]);
}

if (! empty($user->tokens())) {
$user->tokens()->delete();
}

$user->last_login_at = Carbon::now();
$user->last_login_ip = $request->ip();
$user->save();

return response()->json([
'user' => new AuthenticateUserResource($user),
'token' => $user->createToken($request->input('email'))->plainTextToken,
'roles' => $user->roles()->pluck('name'),
'permissions' => $user->permissions()->pluck('name'),
]);
}

public function logout(Request $request): JsonResponse
{
if ($request->user()->currentAccessToken()) {
$request->user()->currentAccessToken()->delete();
}

return response()->json(['message' => 'Déconnecté avec succès']);
}
}
1 change: 1 addition & 0 deletions app/Http/Kernel.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ class Kernel extends HttpKernel
],

'api' => [
\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
'throttle:api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
Expand Down
31 changes: 31 additions & 0 deletions app/Http/Requests/Api/LoginRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

namespace App\Http\Requests\Api;

use Illuminate\Foundation\Http\FormRequest;

class LoginRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize(): bool
{
return true;
}

/**
* Get the validation rules that apply to the request.
*
* @return array<string, mixed>
*/
public function rules(): array
{
return [
'email' => ['required', 'email', 'exists:users,email'],
'password' => ['required'],
];
}
}
39 changes: 39 additions & 0 deletions app/Http/Resources/AuthenticateUserResource.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

namespace App\Http\Resources;

use App\Models\IdeHelperUser;
use Illuminate\Http\Resources\Json\JsonResource;

/**
* @mixin IdeHelperUser
*/
class AuthenticateUserResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
*/
public function toArray($request): array
{
return [
'id' => $this->id,
'name' => $this->name,
'email' => $this->email,
'username' => $this->username,
'bio' => $this->bio,
'profilePhotoUrl' => $this->profile_photo_url,
'phoneNumber' => $this->phone_number,
'optIn' => $this->opt_in,
'settings' => $this->settings,
'reputation' => $this->reputation,

'lastLoginAt' => $this->last_login_at,
'emailVerifiedAt' => $this->email_verified_at,
'createdAt' => $this->created_at,
'updatedAt' => $this->updated_at,
];
}
}
2 changes: 2 additions & 0 deletions app/Models/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use Illuminate\Notifications\Notifiable;
use Illuminate\Notifications\Notification;
use Illuminate\Support\Facades\Auth;
use Laravel\Sanctum\HasApiTokens;
use QCod\Gamify\Gamify;
use Rinvex\Subscriptions\Traits\HasPlanSubscriptions;
use Spatie\MediaLibrary\HasMedia;
Expand All @@ -28,6 +29,7 @@ class User extends Authenticatable implements MustVerifyEmail, HasMedia
use HasFactory;
use HasPlanSubscriptions;
use HasProfilePhoto;
use HasApiTokens;
use HasRoles;
use InteractsWithMedia;
use Notifiable;
Expand Down
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"laravel-notification-channels/twitter": "^6.0",
"laravel/fortify": "^1.13",
"laravel/framework": "^9.24",
"laravel/sanctum": "^3.0",
"laravel/slack-notification-channel": "^2.4",
"laravel/socialite": "^5.2",
"laravel/tinker": "^2.5",
Expand Down
67 changes: 66 additions & 1 deletion composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

67 changes: 67 additions & 0 deletions config/sanctum.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?php

use Laravel\Sanctum\Sanctum;

return [

/*
|--------------------------------------------------------------------------
| Stateful Domains
|--------------------------------------------------------------------------
|
| Requests from the following domains / hosts will receive stateful API
| authentication cookies. Typically, these should include your local
| and production domains which access your API via a frontend SPA.
|
*/

'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
'%s%s',
'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1',
Sanctum::currentApplicationUrlWithPort()
))),

/*
|--------------------------------------------------------------------------
| Sanctum Guards
|--------------------------------------------------------------------------
|
| This array contains the authentication guards that will be checked when
| Sanctum is trying to authenticate a request. If none of these guards
| are able to authenticate the request, Sanctum will use the bearer
| token that's present on an incoming request for authentication.
|
*/

'guard' => ['web'],

/*
|--------------------------------------------------------------------------
| Expiration Minutes
|--------------------------------------------------------------------------
|
| This value controls the number of minutes until an issued token will be
| considered expired. If this value is null, personal access tokens do
| not expire. This won't tweak the lifetime of first-party sessions.
|
*/

'expiration' => null,

/*
|--------------------------------------------------------------------------
| Sanctum Middleware
|--------------------------------------------------------------------------
|
| When authenticating your first-party SPA with Sanctum you may need to
| customize some of the middleware Sanctum uses while processing the
| request. You may change the middleware listed below as required.
|
*/

'middleware' => [
'verify_csrf_token' => App\Http\Middleware\VerifyCsrfToken::class,
'encrypt_cookies' => App\Http\Middleware\EncryptCookies::class,
],

];
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('personal_access_tokens', function (Blueprint $table) {
$table->id();
$table->morphs('tokenable');
$table->string('name');
$table->string('token', 64)->unique();
$table->text('abilities')->nullable();
$table->timestamp('last_used_at')->nullable();
$table->timestamp('expires_at')->nullable();
$table->timestamps();
});
}

/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('personal_access_tokens');
}
};
10 changes: 10 additions & 0 deletions routes/api.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<?php

use App\Http\Controllers\Api\Auth\LoginController;
use App\Http\Controllers\Api\ReplyController;
use App\Http\Controllers\Api\PremiumController;
use Illuminate\Support\Facades\Route;
Expand All @@ -22,3 +23,12 @@
Route::delete('replies/{id}', [ReplyController::class, 'delete']);

Route::get('premium-users', [PremiumController::class, 'users']);


/** Authentication Routes */
Route::post('login', [LoginController::class, 'login']);

/* Authenticated Routes */
Route::middleware('auth:sanctum')->group(function () {
Route::post('logout', [LoginController::class, 'logout']);
});

0 comments on commit cfd7fd2

Please sign in to comment.