Skip to content

Instantly share code, notes, and snippets.

@POMXARK
Created May 21, 2024 04:02
Show Gist options
  • Save POMXARK/9eec54decf089202cc114f3f1e8c986b to your computer and use it in GitHub Desktop.
Save POMXARK/9eec54decf089202cc114f3f1e8c986b to your computer and use it in GitHub Desktop.
sms authentication
NUTNET_SMS_PROVIDER=log
#NUTNET_SMS_PROVIDER=smsru
<?php
use App\Filament\Auth\AuthController;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
Route::get('/user', function (Request $request) {
return $request->user();
})->middleware('auth:sanctum');
Route::post('/tokens/create', [AuthController::class, 'token']);
Route::post('/register', [AuthController::class, 'authentication']);
Route::post('/verification', [AuthController::class, 'verification']);
<?php
namespace App\Filament\Auth;
use App\Models\User;
use Filament\Pages\Auth\Login as BaseAuth;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Nutnet\LaravelSms\SmsSender;
use RandomLib\Factory;
use Symfony\Component\HttpFoundation\Response;
class AuthController extends BaseAuth
{
/**
* @OA\Post(
* path="/tokens/create",
* summary="Аутентификация в системе",
* tags={"Пользователи"},
* @OA\RequestBody(
* required=true,
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(
* type="object",
* @OA\Property(
* property="email",
* description="Email",
* type="string",
* example="[email protected]",
* ),
* @OA\Property(
* property="password",
* description="Пароль",
* type="string",
* example="123456789",
* )
* )
* )
* ),
* @OA\Response(
* response=200,
* description="Успешная операция",
* @OA\JsonContent()
* )
* )
*/
public function token(Request $request): JsonResponse
{
$validator = Validator::make($request->all(), [
'email' => ['required', 'string', 'email', 'max:255'],
'password' => ['required', 'string', 'min:8'],
]);
if ($validator->fails()) {
return response()->json(['error' => $validator->errors()], 401);
}
/* @var User $user */
$user = User::query()->where('email', $request->email)->first();
if (!$user || !Hash::check($request->password, $user->password)) {
return response()->json(['error' => 'The provided credentials are incorrect.'], 401);
}
// TODO: заменить на passport этот хранит токен вечно, переделать авторизацию админа убрать пароль из бд,
// TODO: данные админа статичны в единственном экземпляре хранить в json model
return response()->json(['data' => ['token' => $user->createToken($user->email)->plainTextToken]]);
}
/**
* @OA\Post(
* path="/authentication",
* summary="Регистрация или аутентификация в системе",
* tags={"Пользователи"},
* @OA\RequestBody(
* required=true,
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(
* type="object",
* @OA\Property(
* property="phone",
* description="Телефон",
* type="string",
* example="77777777777",
* ),
* ),),),
* @OA\Response(
* response=200,
* description="Успешная операция",
* @OA\JsonContent()
* )
* )
*
*/
public function authentication(Request $request, SmsSender $smsSender): JsonResponse
{
$user = User::query()->select('id', 'phone', 'created_at', 'updated_at', 'deleted_at')
->where('phone', $request->phone)->first();
if (!$user) {
$validated = $request->validate([
'phone' => 'required|numeric|unique:users',
'deleted_at' => 'nullable|date',
]);
$user = User::query()->create($validated);
}
$seconds = 30;
Cache::remember($user->phone, $seconds, function () use ($smsSender, $user) {
$code = self::generateCode();
self::sendSms($user->phone, $code, $smsSender);
return $code;
});
return response()->json(['data' => ['user' => $user]]);
}
/**
* @OA\Post(
* path="/verification",
* summary="Проверка смс кода",
* tags={"Пользователи"},
* @OA\RequestBody(
* required=true,
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(
* type="object",
* @OA\Property(
* property="phone",
* description="Телефон",
* type="string",
* ),
* @OA\Property(
* property="code",
* description="Смс код подтвеждения",
* type="string",
* ),
* ),),),
* @OA\Response(
* response=200,
* description="Успешная операция",
* @OA\JsonContent()
* )
* )
*
*/
public function verification(Request $request): JsonResponse
{
$request->validate([
'phone' => 'required|numeric|exists:users',
'code' => 'required|numeric',
]);
$phone = $request->phone;
$user = User::query()->where('phone', $phone)->first();
$code = $request->code;
if (Cache::has($phone)) {
if (Cache::get($phone) === $code) {
Cache::forget($phone);
return response()->json(['data' => ['token' => $user->createToken($user->phone)->plainTextToken]]);
} else {
return response()->json(['data' => ['error' => 'Не верный код']], Response::HTTP_UNAUTHORIZED);
}
} else {
return response()->json(['data' => ['error' => 'Код не действителен или номер телефона не зарегистрирован']],
Response::HTTP_UNAUTHORIZED);
}
}
public function sendSms(string $phone, string $code, SmsSender $smsSender): void
{
if (config('nutnet-laravel-sms.provider') === 'log') {
// отправка сообщений с параметрами, для тестирования в logs
$smsSender->send($phone, $code, [
'test' => 1
]);
} else {
// отправка сообщения на 1 номер с оплатой
$smsSender->send($phone, $code);
}
}
public function generateCode(): string
{
$factory = new Factory();
$generator = $factory->getLowStrengthGenerator();
return $generator->generateString(4,'0123456789');
}
}
php artisan l5-swagger:generate
composer require rap2hpoutre/laravel-log-viewer
composer require paragonie/random-lib
composer require nutnet/laravel-sms
<?php
/**
* @author Maksim Khodyrev<[email protected]>
* 17.07.17
*/
return [
/**
* название класса-провайдера
* Доступные провайдеры:
* * \Nutnet\LaravelSms\Providers\Log (alias: log)
* * \Nutnet\LaravelSms\Providers\Smpp (alias: smpp)
* * \Nutnet\LaravelSms\Providers\SmscRu (alias: smscru)
* * \Nutnet\LaravelSms\Providers\SmsRu (alias: smsru)
* * \Nutnet\LaravelSms\Providers\IqSmsRu (alias: iqsms)
* @see Nutnet\LaravelSms\Providers
*/
'provider' => env('NUTNET_SMS_PROVIDER', 'log'),
/**
* настройки, специфичные для провайдера
*/
'providers' => [
'log' => [
/**
* каналы, в которые публикуются сообщения
* оставьте пустым, если хотите использовать общие настройки логирования
* @see https://laravel.com/docs/5.8/logging#building-log-stacks
*/
'channels' => [], // для версий Laravel >=5.6
],
'smpp' => [
// все настройки провадера находятся в конфиг. файле franzose/laravel-smpp
],
'smscru' => [
'login' => env('SMSCRU_LOGIN'),
'password' => env('SMSCRU_PASSWORD'),
'message_defaults' => [],
],
'smsru' => [
'auth_type' => 'standard',
'login' => env('SMSRU_LOGIN'),
'password' => env('SMSRU_PASSWORD'),
'partner_id' => null,
'message_defaults' => [],
],
'iqsms' => [
'login' => env('IQSMS_LOGIN'),
'password' => env('IQSMS_PASSWORD'),
'message_defaults' => [],
],
],
];
Route::get('logs', [\Rap2hpoutre\LaravelLogViewer\LogViewerController::class, 'index'])->middleware('auth:sanctum');
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment