Commit 13d116a8 authored by UtopiaXC's avatar UtopiaXC

🚆 重写迁移脚本,重构错误代码结构,完成登录

parent f0185086
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
...@@ -6,8 +6,14 @@ use App\Http\Utils\R; ...@@ -6,8 +6,14 @@ use App\Http\Utils\R;
use App\Models\Users\User; use App\Models\Users\User;
use App\Models\Users\UserProfile; use App\Models\Users\UserProfile;
use Exception; use Exception;
use HTTP_CODE;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Cookie;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Redis;
use Predis\Connection\ConnectionException;
use RedisCacheKey;
use Webpatser\Uuid\Uuid; use Webpatser\Uuid\Uuid;
class UserController extends Controller class UserController extends Controller
...@@ -15,38 +21,73 @@ class UserController extends Controller ...@@ -15,38 +21,73 @@ class UserController extends Controller
function register(Request $request) function register(Request $request)
{ {
if (!CaptchaController::check_captcha($request->get("captcha"), $request->cookie(app()->getNamespace() . "session"))) { if (!CaptchaController::check_captcha($request->get("captcha"), $request->cookie(app()->getNamespace() . "session"))) {
return R::error("403001","验证码错误"); return R::error(HTTP_CODE::UNAUTHORIZED_CAPTCHA);
} }
try { try {
if (!$request->get("email") || !$request->get("user_name") || !$request->get("password")) {
return R::error(HTTP_CODE::NOT_ACCEPT_PARAMS_CONTENT_WRONG);
}
$email = $request->get("email"); $email = $request->get("email");
$user_name=$request->get("user_name"); $user_name = $request->get("user_name");
$password=password_hash($request->get("password"),PASSWORD_DEFAULT); $password = password_hash($request->get("password"), PASSWORD_DEFAULT);
$user=User::query() $user = User::query()
->where("user_name",$user_name) ->where("user_name", $user_name)
->orWhere("user_name",$email) ->orWhere("user_name", $email)
->get(); ->get();
if (sizeof($user)!=0){ if (sizeof($user) != 0) {
return R::error("403002","该邮箱或用户名已被注册"); return R::error(HTTP_CODE::REFUSED_REGISTER_EXISTS);
} }
$user=new User(); $user = new User();
$user->id=Uuid::generate(); $user->id = Uuid::generate();
$user->user_name=$user_name; $user->user_name = $user_name;
$user->user_email=$email; $user->user_email = $email;
$user->user_password=$password; $user->user_password = $password;
$user->user_type=\UserTypeEnum::NORMAL; $user->user_type = \UserTypeEnum::NORMAL;
$user->user_status=\UserStatusEnum::NOT_VERITY; $user->user_status = \UserStatusEnum::NOT_VERITY;
$user_profile=new UserProfile(); $user_profile = new UserProfile();
$user_profile->id=Uuid::generate(); $user_profile->id = Uuid::generate();
$user_profile->user_id=$user->id; $user_profile->user_id = $user->id;
DB::beginTransaction(); DB::beginTransaction();
$user->save(); $user->save();
$user_profile->save(); $user_profile->save();
DB::commit(); DB::commit();
}catch (Exception $e){ } catch (Exception $e) {
DB::rollBack(); DB::rollBack();
return R::error("500001","用户数据保存错误"); return R::error(HTTP_CODE::INTERNAL_SERVER_ERROR);
} }
return R::ok(); return R::ok();
} }
function login(Request $request)
{
if (!CaptchaController::check_captcha($request->get("captcha"), $request->cookie(app()->getNamespace() . "session"))) {
return R::error(HTTP_CODE::UNAUTHORIZED_CAPTCHA);
}
$username = $request->get("user");
$password = $request->get("password");
if (!$username || !$password) {
return R::error(HTTP_CODE::NOT_ACCEPT_PARAMS_CONTENT_WRONG);
}
$user = User::query()
->where("user_name", $username)
->orWhere("user_email", $username)
->get();
if (sizeof($user) == 0) {
return R::error(HTTP_CODE::REFUSED_LOGIN_NO_REGISTER);
}
if (!password_verify($password, $user[0]->user_password)) {
return R::error(HTTP_CODE::REFUSED_LOGIN_WRONG, $user[0]->user_password);
}
$token = md5($user[0]->id . md5(microtime(true)));
$cookie = Cookie::make(\CookieKey::USER_TOKEN, $token, 60 * 24 * 30);
$expiredMinutes = 60 * 24 * 30;
$expiredAt = now()->addMinute($expiredMinutes);
try {
Redis::setex(RedisCacheKey::USER_TOKEN . $token, $expiredMinutes * 60, $user[0]);
} catch (ConnectionException $e) {
Cache::put(RedisCacheKey::USER_TOKEN . $token, $user[0], $expiredAt);
return R::ok()->withCookie($cookie);
}
return R::ok()->withCookie($cookie);
}
} }
...@@ -39,12 +39,14 @@ class Kernel extends HttpKernel ...@@ -39,12 +39,14 @@ class Kernel extends HttpKernel
\Illuminate\View\Middleware\ShareErrorsFromSession::class, \Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class, \App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class, \Illuminate\Routing\Middleware\SubstituteBindings::class,
\App\Http\Middleware\EncryptCookies::class
], ],
'api' => [ 'api' => [
// \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class, // \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
'throttle:api', 'throttle:api',
\Illuminate\Routing\Middleware\SubstituteBindings::class, \Illuminate\Routing\Middleware\SubstituteBindings::class,
\App\Http\Middleware\EncryptCookies::class
], ],
]; ];
...@@ -56,7 +58,6 @@ class Kernel extends HttpKernel ...@@ -56,7 +58,6 @@ class Kernel extends HttpKernel
* @var array * @var array
*/ */
protected $routeMiddleware = [ protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class, 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class, 'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class, 'can' => \Illuminate\Auth\Middleware\Authorize::class,
......
<?php
namespace App\Http\Middleware\View;
use Closure;
use Illuminate\Http\Request;
class SiteProfileMiddleware
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle(Request $request, Closure $next)
{
return $next($request);
}
}
...@@ -4,6 +4,8 @@ namespace App\Http\Middleware\View; ...@@ -4,6 +4,8 @@ namespace App\Http\Middleware\View;
use Closure; use Closure;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\Redis;
use Predis\Connection\ConnectionException;
class UserAuthMiddleware class UserAuthMiddleware
{ {
...@@ -16,6 +18,19 @@ class UserAuthMiddleware ...@@ -16,6 +18,19 @@ class UserAuthMiddleware
*/ */
public function handle(Request $request, Closure $next) public function handle(Request $request, Closure $next)
{ {
$token = $request->cookie(\CookieKey::USER_TOKEN);
if (!$token) {
$request->attributes->add([\HeaderKey::LOGIN_STATUS => false]);
}
try {
$user = json_decode(Redis::get(\RedisCacheKey::USER_TOKEN . $token), true);
} catch (ConnectionException $e) {
$user = json_decode(\Cache::get(\RedisCacheKey::USER_TOKEN . $token), true);
}
if (!$user)
$request->attributes->add([\HeaderKey::LOGIN_STATUS => false]);
else
$request->attributes->add([\HeaderKey::LOGIN_STATUS => true,\HeaderKey::USER_INFO=>$user]);
return $next($request); return $next($request);
} }
} }
...@@ -15,17 +15,17 @@ class R extends BaseController ...@@ -15,17 +15,17 @@ class R extends BaseController
static public function ok($data = []) static public function ok($data = [])
{ {
return response()->json([ return response()->json([
'code' => 200, 'code' => HTTP_CODE::SUCCESS,
'message' => "success", 'message' => trans('http_code.code')[HTTP_CODE::SUCCESS],
'data' => $data, 'data' => $data,
]); ]);
} }
static public function error($code,$message, $data = []) static public function error($code, $data = [])
{ {
return response()->json([ return response()->json([
'code' => $code, 'code' => $code,
'message' => $message, 'message' => trans('http_code.code')[(int)$code],
'data' => $data, 'data' => $data,
]); ]);
} }
......
...@@ -6,7 +6,24 @@ use Illuminate\Database\Eloquent\Factories\HasFactory; ...@@ -6,7 +6,24 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
/** /**
* App\Models\System\SiteProfile
* *
* @property string $id
* @property string $profile_type
* @property string $profile_description
* @property string $profile_content
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @method static \Illuminate\Database\Eloquent\Builder|SiteProfile newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|SiteProfile newQuery()
* @method static \Illuminate\Database\Eloquent\Builder|SiteProfile query()
* @method static \Illuminate\Database\Eloquent\Builder|SiteProfile whereCreatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|SiteProfile whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder|SiteProfile whereProfileContent($value)
* @method static \Illuminate\Database\Eloquent\Builder|SiteProfile whereProfileDescription($value)
* @method static \Illuminate\Database\Eloquent\Builder|SiteProfile whereProfileType($value)
* @method static \Illuminate\Database\Eloquent\Builder|SiteProfile whereUpdatedAt($value)
* @mixin \Eloquent
*/ */
class SiteProfile extends Model class SiteProfile extends Model
{ {
......
...@@ -5,6 +5,30 @@ namespace App\Models\Users; ...@@ -5,6 +5,30 @@ namespace App\Models\Users;
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
/**
* App\Models\Users\User
*
* @property string $id
* @property string $user_name
* @property string $user_email
* @property string $user_password
* @property string $user_type
* @property string $user_status
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @method static \Illuminate\Database\Eloquent\Builder|User newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|User newQuery()
* @method static \Illuminate\Database\Eloquent\Builder|User query()
* @method static \Illuminate\Database\Eloquent\Builder|User whereCreatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|User whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder|User whereUpdatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|User whereUserEmail($value)
* @method static \Illuminate\Database\Eloquent\Builder|User whereUserName($value)
* @method static \Illuminate\Database\Eloquent\Builder|User whereUserPassword($value)
* @method static \Illuminate\Database\Eloquent\Builder|User whereUserStatus($value)
* @method static \Illuminate\Database\Eloquent\Builder|User whereUserType($value)
* @mixin \Eloquent
*/
class User extends Model class User extends Model
{ {
use HasFactory; use HasFactory;
......
...@@ -5,6 +5,38 @@ namespace App\Models\Users; ...@@ -5,6 +5,38 @@ namespace App\Models\Users;
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
/**
* App\Models\Users\UserProfile
*
* @property string $id
* @property string $user_id
* @property string|null $user_nickname
* @property string|null $user_avatar
* @property string|null $user_sex
* @property string|null $user_birthday
* @property string|null $user_job
* @property string|null $user_city
* @property string|null $user_main_page
* @property string|null $user_github
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @method static \Illuminate\Database\Eloquent\Builder|UserProfile newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|UserProfile newQuery()
* @method static \Illuminate\Database\Eloquent\Builder|UserProfile query()
* @method static \Illuminate\Database\Eloquent\Builder|UserProfile whereCreatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|UserProfile whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder|UserProfile whereUpdatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|UserProfile whereUserAvatar($value)
* @method static \Illuminate\Database\Eloquent\Builder|UserProfile whereUserBirthday($value)
* @method static \Illuminate\Database\Eloquent\Builder|UserProfile whereUserCity($value)
* @method static \Illuminate\Database\Eloquent\Builder|UserProfile whereUserGithub($value)
* @method static \Illuminate\Database\Eloquent\Builder|UserProfile whereUserId($value)
* @method static \Illuminate\Database\Eloquent\Builder|UserProfile whereUserJob($value)
* @method static \Illuminate\Database\Eloquent\Builder|UserProfile whereUserMainPage($value)
* @method static \Illuminate\Database\Eloquent\Builder|UserProfile whereUserNickname($value)
* @method static \Illuminate\Database\Eloquent\Builder|UserProfile whereUserSex($value)
* @mixin \Eloquent
*/
class UserProfile extends Model class UserProfile extends Model
{ {
use HasFactory; use HasFactory;
......
...@@ -10,16 +10,17 @@ ...@@ -10,16 +10,17 @@
"require": { "require": {
"php": "^7.3|^8.0", "php": "^7.3|^8.0",
"ext-json": "*", "ext-json": "*",
"doctrine/dbal": "^3.1",
"fruitcake/laravel-cors": "^2.0", "fruitcake/laravel-cors": "^2.0",
"guzzlehttp/guzzle": "^7.0.1", "guzzlehttp/guzzle": "^7.0.1",
"laravel/framework": "^8.54", "laravel/framework": "^8.54",
"laravel/sanctum": "^2.11",
"laravel/tinker": "^2.5", "laravel/tinker": "^2.5",
"mews/captcha": "^3.2", "mews/captcha": "^3.2",
"predis/predis": "^1.1", "predis/predis": "^1.1",
"webpatser/laravel-uuid": "^4.0" "webpatser/laravel-uuid": "^4.0"
}, },
"require-dev": { "require-dev": {
"barryvdh/laravel-ide-helper": "^2.10",
"facade/ignition": "^2.5", "facade/ignition": "^2.5",
"fakerphp/faker": "^1.9.1", "fakerphp/faker": "^1.9.1",
"laravel/sail": "^1.0.1", "laravel/sail": "^1.0.1",
......
This diff is collapsed.
...@@ -14,9 +14,9 @@ class ApiUrl ...@@ -14,9 +14,9 @@ class ApiUrl
{ {
const API = '/api'; const API = '/api';
const USER = '/user'; const USER = '/user';
const CAPTCHA='/captcha'; const CAPTCHA = '/captcha';
const REGISTER = "/register"; const REGISTER = "/register";
const LOGIN = '/login';
} }
class Middleware class Middleware
...@@ -24,15 +24,48 @@ class Middleware ...@@ -24,15 +24,48 @@ class Middleware
const AUTH_MIDDLEWARE = 'AuthMiddleWare'; const AUTH_MIDDLEWARE = 'AuthMiddleWare';
} }
class UserTypeEnum{ class UserTypeEnum
const ADMIN="01"; {
const NORMAL="02"; const ADMIN = "01";
const VIP="03"; const NORMAL = "02";
const VIP = "03";
}
class UserStatusEnum
{
const NOT_VERITY = "01";
const NORMAL = "02";
const BANNED = "03";
const BANNED_FOREVER = "04";
} }
class UserStatusEnum{ class RedisCacheKey
const NOT_VERITY="01"; {
const NORMAL="02"; const SITE_PROFILE = "site_profile:";
const BANNED="03"; const USER_TOKEN = "user_token:";
const BANNED_FOREVER="04"; }
class CookieKey
{
const USER_TOKEN = "user_token";
}
class HeaderKey
{
const LOGIN_STATUS = "login_status";
const USER_INFO="user_info";
}
class SiteProfileTypeEnum
{
const WEB_TITLE = "01";
const SITE_URL = "02";
const WEB_FOOTER = "03";
}
class DefaultSiteProfile
{
const WEB_TITLE = 'Utopia 开放平台';
const SITE_URL = 'http://localhost';
const WEB_FOOTER='Copyright ©2021 <a href="https://www.utopiaxc.cn/">UtopiaXC</a> All Rights Reserved. | Powered By <a href="https://github.com/UtopiaXC/Utopia-Open-Platform" target="_blank">Utopia Open Platform</a>';
} }
<?php
class HTTP_CODE {
//成功请求 2xx
/**
* @var int 服务器成功响应
*/
const SUCCESS = 200;
//重定向 3xx
//客户端错误 4xx
/**
* @var int 错误的请求
*/
const BAD_REQUEST = 400;
/**
* @var int 请求由于SQL注入被拒绝
*/
const NOT_ACCEPT_SQL = 400001;
/**
* @var int 请求由于参数过长被拒绝
*/
const NOT_ACCEPT_PARAMS_TOO_LONG = 400002;
/**
* @var int 请求由于参数类型错误被拒绝
*/
const NOT_ACCEPT_PARAMS_TYPE_WRONG = 400003;
/**
* @var int 请求由于参数内容错误被拒绝
*/
const NOT_ACCEPT_PARAMS_CONTENT_WRONG = 400004;
/**
* @var int 请求由于请求语法错误被拒绝
*/
const NOT_ACCEPT_SYNTAX_WRONG = 400005;
/**
* @var int 请求参数存在不能为空的值
*/
const NOT_ACCEPT_NOT_BLANK = 400006;
/**
* @var int 验证失败
*/
const UNAUTHORIZED = 401;
/**
* @var int 验证码验证失败
*/
const UNAUTHORIZED_CAPTCHA = 401001;
/**
* @var int 请求被拒绝
*/
const REFUSED = 403;
/**
* @var int 注册信息不被服务器所接受
*/
const REFUSED_REGISTER_NOT_ACCEPT = 403001;
/**
* @var int 用户名或邮箱已存在
*/
const REFUSED_REGISTER_EXISTS = 403002;
/**
* @var int 用户不存在
*/
const REFUSED_LOGIN_NO_REGISTER=403003;
/**
* @var int 用户名或密码错误
*/
const REFUSED_LOGIN_WRONG=403004;
/**
* @var int 登录请求被拒绝,您的账号可能被封禁或停用
*/
const REFUSED_LOGIN_REFUSED=403005;
//服务器错误 5xx
/**
* @var int 服务器内部错误
*/
const INTERNAL_SERVER_ERROR = 500;
/**
* @var int 错误的网关
*/
const BAD_GATEWAY = 502;
}
...@@ -69,7 +69,7 @@ return [ ...@@ -69,7 +69,7 @@ return [
| |
*/ */
'timezone' => 'UTC', 'timezone' => 'PRC',
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
...@@ -82,7 +82,7 @@ return [ ...@@ -82,7 +82,7 @@ return [
| |
*/ */
'locale' => 'cn', 'locale' => 'zh_CN',
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
...@@ -95,7 +95,7 @@ return [ ...@@ -95,7 +95,7 @@ return [
| |
*/ */
'fallback_locale' => 'cn', 'fallback_locale' => 'en',
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
...@@ -141,7 +141,6 @@ return [ ...@@ -141,7 +141,6 @@ return [
/* /*
* Laravel Framework Service Providers... * Laravel Framework Service Providers...
*/ */
Illuminate\Auth\AuthServiceProvider::class,
Illuminate\Broadcasting\BroadcastServiceProvider::class, Illuminate\Broadcasting\BroadcastServiceProvider::class,
Illuminate\Bus\BusServiceProvider::class, Illuminate\Bus\BusServiceProvider::class,
Illuminate\Cache\CacheServiceProvider::class, Illuminate\Cache\CacheServiceProvider::class,
...@@ -158,7 +157,6 @@ return [ ...@@ -158,7 +157,6 @@ return [
Illuminate\Pipeline\PipelineServiceProvider::class, Illuminate\Pipeline\PipelineServiceProvider::class,
Illuminate\Queue\QueueServiceProvider::class, Illuminate\Queue\QueueServiceProvider::class,
Illuminate\Redis\RedisServiceProvider::class, Illuminate\Redis\RedisServiceProvider::class,
Illuminate\Auth\Passwords\PasswordResetServiceProvider::class,
Illuminate\Session\SessionServiceProvider::class, Illuminate\Session\SessionServiceProvider::class,
Illuminate\Translation\TranslationServiceProvider::class, Illuminate\Translation\TranslationServiceProvider::class,
Illuminate\Validation\ValidationServiceProvider::class, Illuminate\Validation\ValidationServiceProvider::class,
...@@ -172,7 +170,6 @@ return [ ...@@ -172,7 +170,6 @@ return [
* Application Service Providers... * Application Service Providers...
*/ */
App\Providers\AppServiceProvider::class, App\Providers\AppServiceProvider::class,
App\Providers\AuthServiceProvider::class,
// App\Providers\BroadcastServiceProvider::class, // App\Providers\BroadcastServiceProvider::class,
App\Providers\EventServiceProvider::class, App\Providers\EventServiceProvider::class,
App\Providers\RouteServiceProvider::class, App\Providers\RouteServiceProvider::class,
...@@ -195,7 +192,6 @@ return [ ...@@ -195,7 +192,6 @@ return [
'App' => Illuminate\Support\Facades\App::class, 'App' => Illuminate\Support\Facades\App::class,
'Arr' => Illuminate\Support\Arr::class, 'Arr' => Illuminate\Support\Arr::class,
'Artisan' => Illuminate\Support\Facades\Artisan::class, 'Artisan' => Illuminate\Support\Facades\Artisan::class,
'Auth' => Illuminate\Support\Facades\Auth::class,
'Blade' => Illuminate\Support\Facades\Blade::class, 'Blade' => Illuminate\Support\Facades\Blade::class,
'Broadcast' => Illuminate\Support\Facades\Broadcast::class, 'Broadcast' => Illuminate\Support\Facades\Broadcast::class,
'Bus' => Illuminate\Support\Facades\Bus::class, 'Bus' => Illuminate\Support\Facades\Bus::class,
......
<?php
return [
/*
|--------------------------------------------------------------------------
| Authentication Defaults
|--------------------------------------------------------------------------
|
| This option controls the default authentication "guard" and password
| reset options for your application. You may change these defaults
| as required, but they're a perfect start for most applications.
|
*/
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
/*
|--------------------------------------------------------------------------
| Authentication Guards
|--------------------------------------------------------------------------
|
| Next, you may define every authentication guard for your application.
| Of course, a great default configuration has been defined for you
| here which uses session storage and the Eloquent user provider.
|
| All authentication drivers have a user provider. This defines how the
| users are actually retrieved out of your database or other storage
| mechanisms used by this application to persist your user's data.
|
| Supported: "session"
|
*/
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
],
/*
|--------------------------------------------------------------------------
| User Providers
|--------------------------------------------------------------------------
|
| All authentication drivers have a user provider. This defines how the
| users are actually retrieved out of your database or other storage
| mechanisms used by this application to persist your user's data.
|
| If you have multiple user tables or models you may configure multiple
| sources which represent each model / table. These sources may then
| be assigned to any extra authentication guards you have defined.
|
| Supported: "database", "eloquent"
|
*/
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\User::class,
],
// 'users' => [
// 'driver' => 'database',
// 'table' => 'users',
// ],
],
/*
|--------------------------------------------------------------------------
| Resetting Passwords
|--------------------------------------------------------------------------
|
| You may specify multiple password reset configurations if you have more
| than one user table or model in the application and you want to have
| separate password reset settings based on the specific user types.
|
| The expire time is the number of minutes that the reset token should be
| considered valid. This security feature keeps tokens short-lived so
| they have less time to be guessed. You may change this as needed.
|
*/
'passwords' => [
'users' => [
'provider' => 'users',
'table' => 'password_resets',
'expire' => 60,
'throttle' => 60,
],
],
/*
|--------------------------------------------------------------------------
| Password Confirmation Timeout
|--------------------------------------------------------------------------
|
| Here you may define the amount of seconds before a password confirmation
| times out and the user is prompted to re-enter their password via the
| confirmation screen. By default, the timeout lasts for three hours.
|
*/
'password_timeout' => 10800,
];
...@@ -54,7 +54,7 @@ return [ ...@@ -54,7 +54,7 @@ return [
'unix_socket' => env('DB_SOCKET', ''), 'unix_socket' => env('DB_SOCKET', ''),
'charset' => 'utf8mb4', 'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci', 'collation' => 'utf8mb4_unicode_ci',
'prefix' => '', 'prefix' => env("APP_NAME") . "_",
'prefix_indexes' => true, 'prefix_indexes' => true,
'strict' => true, 'strict' => true,
'engine' => null, 'engine' => null,
...@@ -123,7 +123,7 @@ return [ ...@@ -123,7 +123,7 @@ return [
'options' => [ 'options' => [
'cluster' => env('REDIS_CLUSTER', 'redis'), 'cluster' => env('REDIS_CLUSTER', 'redis'),
'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'), 'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_') . '_database_'),
], ],
'default' => [ 'default' => [
......
This diff is collapsed.
...@@ -26,6 +26,7 @@ class CreateUsersProfile extends Migration ...@@ -26,6 +26,7 @@ class CreateUsersProfile extends Migration
$table->string('user_github')->nullable();; $table->string('user_github')->nullable();;
$table->timestamps(); $table->timestamps();
}); });
} }
/** /**
......
...@@ -14,14 +14,16 @@ class CreateUsersTable extends Migration ...@@ -14,14 +14,16 @@ class CreateUsersTable extends Migration
public function up() public function up()
{ {
Schema::create('users', function (Blueprint $table) { Schema::create('users', function (Blueprint $table) {
$table->uuid('id'); $table->uuid('id')->unique();
$table->string('user_name'); $table->string('user_name')->unique();
$table->string('user_email'); $table->string('user_email')->unique();
$table->string('user_password'); $table->string('user_password');
$table->string('user_type'); $table->string('user_type');
$table->string('user_status'); $table->string('user_status');
$table->timestamps(); $table->timestamps();
}); });
} }
/** /**
......
...@@ -15,7 +15,7 @@ class CreateSiteProfile extends Migration ...@@ -15,7 +15,7 @@ class CreateSiteProfile extends Migration
{ {
Schema::create('site_profile', function (Blueprint $table) { Schema::create('site_profile', function (Blueprint $table) {
$table->uuid('id'); $table->uuid('id');
$table->string('profile_type'); $table->string('profile_type')->unique();
$table->string('profile_description'); $table->string('profile_description');
$table->string('profile_content'); $table->string('profile_content');
$table->timestamps(); $table->timestamps();
......
<?php
namespace Database\Seeders;
use App\Models\Users\User;
use App\Models\Users\UserProfile;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
use UserStatusEnum;
use UserTypeEnum;
use Webpatser\Uuid\Uuid;
class AddAdminUserSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
* @throws \Throwable
*/
public function run()
{
DB::beginTransaction();
try {
//以下添加默认管理员账户
$user = new User();
$user->id = Uuid::generate();
$user->user_name = "admin";
$user->user_email = "admin@admin.com";
//默认密码Admin12345678
$user->user_password = '$2y$10$lb4WYqFMVtR7vlZMnTi7jO0ROBXzkSRGDK0vrnk965RfQAIsgSpO.';
$user->user_type = UserTypeEnum::ADMIN;
$user->user_status = UserStatusEnum::NORMAL;
$user->save();
$user_profile = new UserProfile();
$user_profile->id = Uuid::generate();
$user_profile->user_id = $user->id;
$user_profile->save();
}catch (\Exception $e){
DB::rollBack();
}
DB::commit();
}
}
...@@ -13,6 +13,9 @@ class DatabaseSeeder extends Seeder ...@@ -13,6 +13,9 @@ class DatabaseSeeder extends Seeder
*/ */
public function run() public function run()
{ {
// \App\Models\User::factory(10)->create(); $this->call([
AddAdminUserSeeder::class,
SiteProfileSeeder::class,
]);
} }
} }
<?php
namespace Database\Seeders;
use App\Models\System\SiteProfile;
use DB;
use Illuminate\Database\Seeder;
class SiteProfileSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
* @throws \Throwable
*/
public function run()
{
DB:: beginTransaction();
try {
//网站标题
$site_profile=new SiteProfile();
$site_profile->id=\Uuid::generate();
$site_profile->profile_type=\SiteProfileTypeEnum::WEB_TITLE;
$site_profile->profile_description=trans('site_profile_description.'.\SiteProfileTypeEnum::WEB_TITLE);
$site_profile->profile_content=\DefaultSiteProfile::WEB_TITLE;
$site_profile->save();
//网站地址
$site_profile=new SiteProfile();
$site_profile->id=\Uuid::generate();
$site_profile->profile_type=\SiteProfileTypeEnum::SITE_URL;
$site_profile->profile_description=trans('site_profile_description.'.\SiteProfileTypeEnum::SITE_URL);
$site_profile->profile_content=\DefaultSiteProfile::SITE_URL;
$site_profile->save();
//网站注脚
$site_profile=new SiteProfile();
$site_profile->id=\Uuid::generate();
$site_profile->profile_type=\SiteProfileTypeEnum::WEB_FOOTER;
$site_profile->profile_description=trans('site_profile_description.'.\SiteProfileTypeEnum::WEB_FOOTER);
$site_profile->profile_content=\DefaultSiteProfile::WEB_FOOTER;
$site_profile->save();
}catch (\Exception $e){
DB::rollBack();
}
DB::commit();
}
}
This diff is collapsed.
<?php
return [
/*
|--------------------------------------------------------------------------
| Authentication Language Lines
|--------------------------------------------------------------------------
|
| The following language lines are used during authentication for various
| messages that we need to display to the user. You are free to modify
| these language lines according to your application's requirements.
|
*/
'failed' => 'These credentials do not match our records.',
'password' => 'The provided password is incorrect.',
'throttle' => 'Too many login attempts. Please try again in :seconds seconds.',
];
<?php
return [
/*
|--------------------------------------------------------------------------
| Pagination Language Lines
|--------------------------------------------------------------------------
|
| The following language lines are used by the paginator library to build
| the simple pagination links. You are free to change them to anything
| you want to customize your views to better match your application.
|
*/
'previous' => '&laquo; Previous',
'next' => 'Next &raquo;',
];
<?php
return [
/*
|--------------------------------------------------------------------------
| Password Reset Language Lines
|--------------------------------------------------------------------------
|
| The following language lines are the default lines which match reasons
| that are given by the password broker for a password update attempt
| has failed, such as for an invalid token or invalid new password.
|
*/
'reset' => 'Your password has been reset!',
'sent' => 'We have emailed your password reset link!',
'throttled' => 'Please wait before retrying.',
'token' => 'This password reset token is invalid.',
'user' => "We can't find a user with that email address.",
];
<?php
return [
/*
|--------------------------------------------------------------------------
| Validation Language Lines
|--------------------------------------------------------------------------
|
| The following language lines contain the default error messages used by
| the validator class. Some of these rules have multiple versions such
| as the size rules. Feel free to tweak each of these messages here.
|
*/
'accepted' => 'The :attribute must be accepted.',
'accepted_if' => 'The :attribute must be accepted when :other is :value.',
'active_url' => 'The :attribute is not a valid URL.',
'after' => 'The :attribute must be a date after :date.',
'after_or_equal' => 'The :attribute must be a date after or equal to :date.',
'alpha' => 'The :attribute must only contain letters.',
'alpha_dash' => 'The :attribute must only contain letters, numbers, dashes and underscores.',
'alpha_num' => 'The :attribute must only contain letters and numbers.',
'array' => 'The :attribute must be an array.',
'before' => 'The :attribute must be a date before :date.',
'before_or_equal' => 'The :attribute must be a date before or equal to :date.',
'between' => [
'numeric' => 'The :attribute must be between :min and :max.',
'file' => 'The :attribute must be between :min and :max kilobytes.',
'string' => 'The :attribute must be between :min and :max characters.',
'array' => 'The :attribute must have between :min and :max items.',
],
'boolean' => 'The :attribute field must be true or false.',
'confirmed' => 'The :attribute confirmation does not match.',
'current_password' => 'The password is incorrect.',
'date' => 'The :attribute is not a valid date.',
'date_equals' => 'The :attribute must be a date equal to :date.',
'date_format' => 'The :attribute does not match the format :format.',
'different' => 'The :attribute and :other must be different.',
'digits' => 'The :attribute must be :digits digits.',
'digits_between' => 'The :attribute must be between :min and :max digits.',
'dimensions' => 'The :attribute has invalid image dimensions.',
'distinct' => 'The :attribute field has a duplicate value.',
'email' => 'The :attribute must be a valid email address.',
'ends_with' => 'The :attribute must end with one of the following: :values.',
'exists' => 'The selected :attribute is invalid.',
'file' => 'The :attribute must be a file.',
'filled' => 'The :attribute field must have a value.',
'gt' => [
'numeric' => 'The :attribute must be greater than :value.',
'file' => 'The :attribute must be greater than :value kilobytes.',
'string' => 'The :attribute must be greater than :value characters.',
'array' => 'The :attribute must have more than :value items.',
],
'gte' => [
'numeric' => 'The :attribute must be greater than or equal :value.',
'file' => 'The :attribute must be greater than or equal :value kilobytes.',
'string' => 'The :attribute must be greater than or equal :value characters.',
'array' => 'The :attribute must have :value items or more.',
],
'image' => 'The :attribute must be an image.',
'in' => 'The selected :attribute is invalid.',
'in_array' => 'The :attribute field does not exist in :other.',
'integer' => 'The :attribute must be an integer.',
'ip' => 'The :attribute must be a valid IP address.',
'ipv4' => 'The :attribute must be a valid IPv4 address.',
'ipv6' => 'The :attribute must be a valid IPv6 address.',
'json' => 'The :attribute must be a valid JSON string.',
'lt' => [
'numeric' => 'The :attribute must be less than :value.',
'file' => 'The :attribute must be less than :value kilobytes.',
'string' => 'The :attribute must be less than :value characters.',
'array' => 'The :attribute must have less than :value items.',
],
'lte' => [
'numeric' => 'The :attribute must be less than or equal :value.',
'file' => 'The :attribute must be less than or equal :value kilobytes.',
'string' => 'The :attribute must be less than or equal :value characters.',
'array' => 'The :attribute must not have more than :value items.',
],
'max' => [
'numeric' => 'The :attribute must not be greater than :max.',
'file' => 'The :attribute must not be greater than :max kilobytes.',
'string' => 'The :attribute must not be greater than :max characters.',
'array' => 'The :attribute must not have more than :max items.',
],
'mimes' => 'The :attribute must be a file of type: :values.',
'mimetypes' => 'The :attribute must be a file of type: :values.',
'min' => [
'numeric' => 'The :attribute must be at least :min.',
'file' => 'The :attribute must be at least :min kilobytes.',
'string' => 'The :attribute must be at least :min characters.',
'array' => 'The :attribute must have at least :min items.',
],
'multiple_of' => 'The :attribute must be a multiple of :value.',
'not_in' => 'The selected :attribute is invalid.',
'not_regex' => 'The :attribute format is invalid.',
'numeric' => 'The :attribute must be a number.',
'password' => 'The password is incorrect.',
'present' => 'The :attribute field must be present.',
'regex' => 'The :attribute format is invalid.',
'required' => 'The :attribute field is required.',
'required_if' => 'The :attribute field is required when :other is :value.',
'required_unless' => 'The :attribute field is required unless :other is in :values.',
'required_with' => 'The :attribute field is required when :values is present.',
'required_with_all' => 'The :attribute field is required when :values are present.',
'required_without' => 'The :attribute field is required when :values is not present.',
'required_without_all' => 'The :attribute field is required when none of :values are present.',
'prohibited' => 'The :attribute field is prohibited.',
'prohibited_if' => 'The :attribute field is prohibited when :other is :value.',
'prohibited_unless' => 'The :attribute field is prohibited unless :other is in :values.',
'same' => 'The :attribute and :other must match.',
'size' => [
'numeric' => 'The :attribute must be :size.',
'file' => 'The :attribute must be :size kilobytes.',
'string' => 'The :attribute must be :size characters.',
'array' => 'The :attribute must contain :size items.',
],
'starts_with' => 'The :attribute must start with one of the following: :values.',
'string' => 'The :attribute must be a string.',
'timezone' => 'The :attribute must be a valid timezone.',
'unique' => 'The :attribute has already been taken.',
'uploaded' => 'The :attribute failed to upload.',
'url' => 'The :attribute must be a valid URL.',
'uuid' => 'The :attribute must be a valid UUID.',
/*
|--------------------------------------------------------------------------
| Custom Validation Language Lines
|--------------------------------------------------------------------------
|
| Here you may specify custom validation messages for attributes using the
| convention "attribute.rule" to name the lines. This makes it quick to
| specify a specific custom language line for a given attribute rule.
|
*/
'custom' => [
'attribute-name' => [
'rule-name' => 'custom-message',
],
],
/*
|--------------------------------------------------------------------------
| Custom Validation Attributes
|--------------------------------------------------------------------------
|
| The following language lines are used to swap our attribute placeholder
| with something more reader friendly such as "E-Mail Address" instead
| of "email". This simply helps us make our message more expressive.
|
*/
'attributes' => [],
];
<?php
return ["code" => [
//2xx
HTTP_CODE::SUCCESS => "成功",
//3xx
//4xx
//400xxx
HTTP_CODE::BAD_REQUEST => "错误的请求",
HTTP_CODE::NOT_ACCEPT_SQL => '请求由于SQL注入被拒绝',
HTTP_CODE::NOT_ACCEPT_PARAMS_TOO_LONG => '请求由于参数过长被拒绝',
HTTP_CODE::NOT_ACCEPT_PARAMS_TYPE_WRONG => '请求由于参数类型错误被拒绝',
HTTP_CODE::NOT_ACCEPT_PARAMS_CONTENT_WRONG => '请求由于参数内容错误被拒绝',
HTTP_CODE::NOT_ACCEPT_SYNTAX_WRONG => '请求由于请求语法错误被拒绝',
HTTP_CODE::NOT_ACCEPT_NOT_BLANK=>'参数不能存在空值',
//401xxx
HTTP_CODE::UNAUTHORIZED => "未认证",
HTTP_CODE::UNAUTHORIZED_CAPTCHA => "验证码错误或超时",
//403xxx
HTTP_CODE::REFUSED => '请求被拒绝',
HTTP_CODE::REFUSED_REGISTER_NOT_ACCEPT => '注册信息不被服务器所接受',
HTTP_CODE::REFUSED_REGISTER_EXISTS => '用户名或邮箱已存在',
HTTP_CODE::REFUSED_LOGIN_NO_REGISTER => '用户不存在',
HTTP_CODE::REFUSED_LOGIN_WRONG => '用户名或密码错误',
HTTP_CODE::REFUSED_LOGIN_REFUSED => '登录请求被拒绝,您的账号可能被封禁或停用',
//5xx
HTTP_CODE::INTERNAL_SERVER_ERROR => '服务器内部错误',
HTTP_CODE::BAD_GATEWAY => '错误的网关',
]
];
<?php
return [
SiteProfileTypeEnum::WEB_TITLE => '网站标题',
SiteProfileTypeEnum::SITE_URL => '网站URL',
SiteProfileTypeEnum::WEB_FOOTER=>'网站版权注脚信息',
];
...@@ -3,11 +3,11 @@ ...@@ -3,11 +3,11 @@
@section('title') - 登录 @endsection @section('title') - 登录 @endsection
@section('body') @section('body')
<body class="login-page"> <body class="login-page">
<div class='loader'> <div class='loader'>
<div class='spinner-grow text-primary' role='status'><span class='sr-only'>Loading...</span></div> <div class='spinner-grow text-primary' role='status'><span class='sr-only'>Loading...</span></div>
</div> </div>
<div class="container"> <div class="container">
<div class="row justify-content-md-center"> <div class="row justify-content-md-center">
<div class="col-md-12 col-lg-4"> <div class="col-md-12 col-lg-4">
<div class="card login-box-container"> <div class="card login-box-container">
...@@ -18,9 +18,9 @@ ...@@ -18,9 +18,9 @@
<form> <form>
<div class="mb-3"> <div class="mb-3">
<div class="form-floating"> <div class="form-floating">
<input type="text" class="form-control" id="email" <input type="text" class="form-control" id="user"
placeholder="邮箱或用户名"> placeholder="邮箱或用户名">
<label for="email">邮箱或用户名</label> <label for="user">邮箱或用户名</label>
</div> </div>
</div> </div>
<div class="mb-3"> <div class="mb-3">
...@@ -30,9 +30,15 @@ ...@@ -30,9 +30,15 @@
<label for="password">密码</label> <label for="password">密码</label>
</div> </div>
</div> </div>
<div class="d-grid"> <div class="d-grid">
<button type="button" onclick="doLogin()" class="btn btn-info m-b-xs">登录</button> <div id="login_process" style="display: none;" class="progress m-b-xs">
<button type="button" class="btn btn-primary" onclick="window.location.href='{{WebUrl::FIND_PASSWORD}}'"> <div class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar"
aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" style="width: 100%"></div>
</div>
<button id="login_button" type="button" onclick="doLogin()" class="btn btn-info m-b-xs">登录</button>
<button type="button" class="btn btn-primary"
onclick="window.location.href='{{WebUrl::FIND_PASSWORD}}'">
找回密码 找回密码
</button> </button>
</div> </div>
...@@ -44,8 +50,8 @@ ...@@ -44,8 +50,8 @@
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="modal fade" id="alert" tabindex="-1" aria-labelledby="alert" aria-hidden="true"> <div class="modal fade" id="alert" tabindex="-1" aria-labelledby="alert" aria-hidden="true">
<div class="modal-dialog"> <div class="modal-dialog">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
...@@ -58,29 +64,116 @@ ...@@ -58,29 +64,116 @@
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</body> <div class="modal fade" id="captcha_dialog" tabindex="-1" data-bs-backdrop="static" data-bs-keyboard="false"
aria-labelledby="captcha" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="captcha_title">CAPTCHA 验证码</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body" id="captcha_content">
<div id="captcha_process" class="progress">
<div class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar"
aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" style="width: 100%"></div>
</div>
<div class="input-group mb-3" id="captcha_div" style="display: none">
<span class="input-group-text"><img id="captcha_img" style="display: none;" src=""
alt="captcha"></span>
<label for="captcha"></label>
<input type="text" class="form-control" id="captcha" aria-describedby="basic-addon3"
placeholder="验证码">
</div>
<div class="modal-footer" style="display: flex;justify-content: flex-end">
<button type="button" onclick="$('#login_process').hide();$('#login_button').show()" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
<button type="button" onclick="doCaptcha();" class="btn btn-primary">验证</button>
</div>
</div>
</div>
</div>
</div>
</body>
@endsection @endsection
@section('script') @section('script')
<script> <script src="https://cdn.bootcdn.net/ajax/libs/blueimp-md5/2.18.0/js/md5.js"></script>
function doLogin(){ <script>
let email=$("#email").val() function doLogin() {
let password=$("#password").val() let user = $("#user").val()
if (email===""||password===""){ let password = $("#password").val()
showAlert("警告","您有未输入的部分") if (user === "" || password === "") {
return showAlert("警告", "您有未输入的部分")
}
let pattern = /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/
if (!pattern.test(email)) {
showAlert("警告", "邮箱格式错误")
return return
} }
$.ajax({
$("#captcha_dialog").modal('show')
$("#login_process").show()
$("#login_button").hide()
$.ajax({
url: '{{ApiUrl::API.ApiUrl::CAPTCHA}}',
method: "get",
dataType: "json",
success: function (result) {
if (result.code === 200) {
$("#captcha_process").hide()
let captcha_img = $("#captcha_img")
captcha_img.attr("src", result.data.captcha_img)
captcha_img.show()
$("#captcha_div").show()
} else {
$("#login_process").hide()
$("#login_button").show()
showAlert("抱歉", "服务器错误,未获取到验证码")
}
},
error: function () {
$("#login_process").hide()
$("#login_button").show()
showAlert("抱歉", "服务器错误,未获取到验证码")
}
}) })
}
function doCaptcha(){
let process = $("#captcha_process")
process.show()
$("#captcha_div").hide()
let user = $("#user").val()
let password = $("#password").val()
let captcha = $("#captcha").val()
$.ajax({
url: '{{ApiUrl::API.ApiUrl::USER.ApiUrl::LOGIN}}',
dataType: "json",
type:'post',
data: {
"user": user,
"password": md5(password),
"captcha":captcha
},
success: function (result) {
$("#captcha_dialog").modal('hide')
$("#login_process").hide()
$("#login_button").show()
if(result.code===200){
window.location.href="/";
}else{
showAlert("抱歉",result.message)
} }
},
error: function () {
$("#login_process").hide()
$("#login_button").show()
$("#captcha_dialog").modal('hide')
showAlert("抱歉","服务器错误")
}
})
}
function showAlert(title, content) { function showAlert(title, content) {
let alert = $("#alert") let alert = $("#alert")
let title_elem = $("#alert_title") let title_elem = $("#alert_title")
...@@ -89,5 +182,5 @@ ...@@ -89,5 +182,5 @@
content_elem.html(content) content_elem.html(content)
alert.modal('show') alert.modal('show')
} }
</script> </script>
@endsection @endsection
...@@ -199,7 +199,7 @@ ...@@ -199,7 +199,7 @@
data: { data: {
"email": email, "email": email,
"user_name": user_name, "user_name": user_name,
"passeord": password, "password": password,
"captcha": captcha "captcha": captcha
}, },
success: function (result) { success: function (result) {
......
...@@ -16,5 +16,6 @@ use Illuminate\Support\Facades\Route; ...@@ -16,5 +16,6 @@ use Illuminate\Support\Facades\Route;
| |
*/ */
Route::post(ApiUrl::USER.ApiUrl::REGISTER, [UserController::class,"register"]);
Route::get(ApiUrl::CAPTCHA,[CaptchaController::class,"getCaptcha"]); Route::get(ApiUrl::CAPTCHA,[CaptchaController::class,"getCaptcha"]);
Route::post(ApiUrl::USER.ApiUrl::REGISTER, [UserController::class,"register"]);
Route::post(ApiUrl::USER.ApiUrl::LOGIN,[UserController::class,"login"]);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment