Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
A
aphp1_75classwork
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Egor Kremnev
aphp1_75classwork
Commits
3d29669b
Commit
3d29669b
authored
Jul 18, 2023
by
Egor Kremnev
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
add laravel passport. add register and auth in frontend
parent
76bc2b67
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
1712 additions
and
229 deletions
+1712
-229
PassportAuthController.php
api/app/Http/Controllers/Api/PassportAuthController.php
+44
-0
RegisterRequest.php
api/app/Http/Requests/Api/RegisterRequest.php
+30
-0
User.php
api/app/Models/User.php
+1
-3
AppServiceProvider.php
api/app/Providers/AppServiceProvider.php
+2
-1
composer.json
api/composer.json
+1
-0
composer.lock
api/composer.lock
+1256
-155
auth.php
api/config/auth.php
+4
-0
sanctum.php
api/config/sanctum.php
+1
-0
api.php
api/routes/api.php
+3
-10
TestCase.php
api/tests/TestCase.php
+15
-0
Errors.jsx
frontend/src/components/Errors/Errors.jsx
+23
-0
Navbar.jsx
frontend/src/components/common/Navbar/Navbar.jsx
+78
-19
ArticlesPage.jsx
frontend/src/containers/ArticlesPage/ArticlesPage.jsx
+39
-41
Login.jsx
frontend/src/containers/Auth/Login/Login.jsx
+85
-0
Register.jsx
frontend/src/containers/Auth/Register/Register.jsx
+85
-0
router.js
frontend/src/routes/router.js
+10
-0
request.js
frontend/src/services/request.js
+35
-0
No files found.
api/app/Http/Controllers/Api/PassportAuthController.php
0 → 100644
View file @
3d29669b
<?php
namespace
App\Http\Controllers\Api
;
use
App\Http\Controllers\Controller
;
use
App\Http\Requests\Api\RegisterRequest
;
use
App\Models\User
;
use
Illuminate\Http\JsonResponse
;
use
Illuminate\Http\Request
;
class
PassportAuthController
extends
Controller
{
/**
* @param RegisterRequest $request
* @return JsonResponse
*/
public
function
register
(
RegisterRequest
$request
)
:
JsonResponse
{
$user
=
User
::
create
([
'name'
=>
$request
->
name
,
'email'
=>
$request
->
email
,
'password'
=>
bcrypt
(
$request
->
password
)
]);
return
response
()
->
json
(
[
'token'
=>
$user
->
createToken
(
'LaravelAuthApp'
)
->
accessToken
],
201
);
}
/**
* @param Request $request
* @return JsonResponse
*/
public
function
login
(
Request
$request
)
:
JsonResponse
{
if
(
auth
()
->
attempt
(
$request
->
only
([
'email'
,
'password'
])))
{
return
response
()
->
json
([
'token'
=>
auth
()
->
user
()
->
createToken
(
'LaravelAuthApp'
)
->
accessToken
]);
}
return
response
()
->
json
([
'error'
=>
'Unauthorised'
],
401
);
}
}
api/app/Http/Requests/Api/RegisterRequest.php
0 → 100644
View file @
3d29669b
<?php
namespace
App\Http\Requests\Api
;
use
Illuminate\Foundation\Http\FormRequest
;
class
RegisterRequest
extends
FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public
function
authorize
()
:
bool
{
return
true
;
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array|string>
*/
public
function
rules
()
:
array
{
return
[
'name'
=>
'required|min:4'
,
'email'
=>
'required|email|unique:users'
,
'password'
=>
'required|min:6'
];
}
}
api/app/Models/User.php
View file @
3d29669b
...
...
@@ -2,13 +2,11 @@
namespace
App\Models
;
// use Illuminate\Contracts\Auth\MustVerifyEmail;
use
Illuminate\Database\Eloquent\Factories\HasFactory
;
use
Illuminate\Database\Eloquent\Relations\BelongsTo
;
use
Illuminate\Database\Eloquent\Relations\HasMany
;
use
Illuminate\Foundation\Auth\User
as
Authenticatable
;
use
Illuminate\Notifications\Notifiable
;
use
Laravel\
Sanctum
\HasApiTokens
;
use
Laravel\
Passport
\HasApiTokens
;
class
User
extends
Authenticatable
{
...
...
api/app/Providers/AppServiceProvider.php
View file @
3d29669b
...
...
@@ -3,6 +3,7 @@
namespace
App\Providers
;
use
Illuminate\Support\ServiceProvider
;
use
Laravel\Passport\Passport
;
class
AppServiceProvider
extends
ServiceProvider
{
...
...
@@ -11,7 +12,7 @@ class AppServiceProvider extends ServiceProvider
*/
public
function
register
()
:
void
{
//
Passport
::
ignoreRoutes
();
}
/**
...
...
api/composer.json
View file @
3d29669b
...
...
@@ -8,6 +8,7 @@
"php"
:
"^8.1"
,
"guzzlehttp/guzzle"
:
"^7.2"
,
"laravel/framework"
:
"^10.10"
,
"laravel/passport"
:
"^11.8"
,
"laravel/sanctum"
:
"^3.2"
,
"laravel/tinker"
:
"^2.8"
},
...
...
api/composer.lock
View file @
3d29669b
This diff is collapsed.
Click to expand it.
api/config/auth.php
View file @
3d29669b
...
...
@@ -40,6 +40,10 @@ return [
'driver'
=>
'session'
,
'provider'
=>
'users'
,
],
'api'
=>
[
'driver'
=>
'passport'
,
'provider'
=>
'users'
,
],
],
/*
...
...
api/config/sanctum.php
View file @
3d29669b
...
...
@@ -64,4 +64,5 @@ return [
'encrypt_cookies'
=>
App\Http\Middleware\EncryptCookies
::
class
,
],
'routes'
=>
false
];
api/routes/api.php
View file @
3d29669b
...
...
@@ -14,15 +14,8 @@ use Illuminate\Support\Facades\Route;
|
*/
Route
::
middleware
(
'auth:sanctum'
)
->
get
(
'/user'
,
function
(
Request
$request
)
{
return
$request
->
user
();
});
Route
::
post
(
'register'
,
[
App\Http\Controllers\Api\PassportAuthController
::
class
,
'register'
]);
Route
::
post
(
'login'
,
[
App\Http\Controllers\Api\PassportAuthController
::
class
,
'login'
]);
Route
::
resource
(
'/articles'
,
\App\Http\Controllers\Api\ArticleController
::
class
)
->
only
(
'index'
);
//Route::resource('/articles', \App\Http\Controllers\Api\ArticleController::class)
// ->except('edit', 'create');
//Route::resource('/articles/{article}/comments', \App\Http\Controllers\Api\CommentController::class)
// ->except('edit', 'create');
->
middleware
(
'auth:api'
);
api/tests/TestCase.php
View file @
3d29669b
...
...
@@ -2,11 +2,26 @@
namespace
Tests
;
use
App\Models\User
;
use
Illuminate\Foundation\Testing\TestCase
as
BaseTestCase
;
use
Illuminate\Foundation\Testing\RefreshDatabase
;
use
Illuminate\Foundation\Testing\WithFaker
;
use
Laravel\Passport\Passport
;
abstract
class
TestCase
extends
BaseTestCase
{
use
CreatesApplication
,
RefreshDatabase
,
WithFaker
;
/** @var User $user */
protected
$user
;
/**
* @return void
*/
public
function
setUp
()
:
void
{
parent
::
setUp
();
$this
->
user
=
User
::
factory
()
->
create
();
Passport
::
actingAs
(
$this
->
user
);
}
}
frontend/src/components/Errors/Errors.jsx
0 → 100644
View file @
3d29669b
import
React
from
"react"
;
import
{
Message
}
from
"semantic-ui-react"
;
const
Errors
=
({
errorMessage
,
errors
})
=>
{
return
<
Message
negative
>
<
Message
.
Header
>
{
errorMessage
}
</
Message
.
Header
>
<
div
>
{
Object
.
keys
(
errors
).
map
(
key
=>
(
<
div
key=
{
key
}
>
<
div
>
{
key
.
charAt
(
0
).
toUpperCase
()
+
key
.
slice
(
1
)
}
</
div
>
<
ul
className=
"list"
>
{
errors
[
key
].
map
(
error
=>
(<
li
key=
{
error
}
className=
"content"
>
{
error
}
</
li
>))
}
</
ul
>
</
div
>
)
)
}
</
div
>
</
Message
>
};
export
default
Errors
;
frontend/src/components/common/Navbar/Navbar.jsx
View file @
3d29669b
import
React
,
{
Component
}
from
"react"
;
import
React
,
{
useEffect
,
useState
}
from
"react"
;
import
{
Container
,
Menu
}
from
"semantic-ui-react"
;
import
{
Link
}
from
"react-router-dom"
;
import
{
Link
,
useLocation
,
useNavigate
}
from
"react-router-dom"
;
export
default
class
Navbar
extends
Component
{
render
()
{
const
Navbar
=
()
=>
{
const
[
state
,
setState
]
=
useState
({
isAuth
:
false
,
activeItem
:
'home'
});
const
location
=
useLocation
();
const
navigate
=
useNavigate
();
useEffect
(()
=>
{
const
token
=
localStorage
.
getItem
(
'token'
);
if
(
token
)
{
setState
(
prevState
=>
({...
prevState
,
isAuth
:
true
}));
}
},
[
location
]);
const
handleItemClick
=
(
e
,
{
name
})
=>
setState
(
prevState
=>
({...
prevState
,
activeItem
:
name
}));
const
handleLogOut
=
(
e
)
=>
{
setState
({
isAuth
:
false
,
activeItem
:
'logout'
});
localStorage
.
removeItem
(
'token'
);
navigate
(
"/login"
);
};
const
authButtons
=
()
=>
{
return
(
<
div
>
<
Menu
fixed=
"top"
inverted
>
<
Container
>
<
Menu
.
Item
as=
{
Link
}
header
to=
"/"
>
Home
</
Menu
.
Item
>
<
Menu
.
Item
as=
{
Link
}
to=
"/articles"
id=
"articles-button"
>
<>
<
Menu
.
Item
as=
{
Link
}
to=
"/login"
name=
'login'
active=
{
state
.
activeItem
===
'login'
}
onClick=
{
handleItemClick
}
/>
<
Menu
.
Item
as=
{
Link
}
to=
"/register"
name=
'register'
active=
{
state
.
activeItem
===
'register'
}
onClick=
{
handleItemClick
}
/>
</>
);
};
const
logOutButton
=
()
=>
{
return
(
<>
<
Menu
.
Item
name=
'logout'
active=
{
state
.
activeItem
===
'logout'
}
onClick=
{
handleLogOut
}
/>
</>
)
};
return
(
<
div
>
<
Menu
fixed=
"top"
inverted
>
<
Container
>
<
Menu
.
Item
name=
'home'
active=
{
state
.
activeItem
===
'home'
}
as=
{
Link
}
to=
"/"
header
onClick=
{
handleItemClick
}
>
Home
</
Menu
.
Item
>
{
state
.
isAuth
&&
<
Menu
.
Item
name=
'articles'
active=
{
state
.
activeItem
===
'articles'
}
as=
{
Link
}
to=
"/articles"
onClick=
{
handleItemClick
}
>
Articles
</
Menu
.
Item
>
</
Container
>
</
Menu
>
</
div
>
);
}
}
}
<
Menu
.
Menu
position=
'right'
>
{
state
.
isAuth
?
logOutButton
()
:
authButtons
()
}
</
Menu
.
Menu
>
</
Container
>
</
Menu
>
</
div
>
);
};
export
default
Navbar
;
frontend/src/containers/ArticlesPage/ArticlesPage.jsx
View file @
3d29669b
import
React
,
{
Component
}
from
"react"
;
import
React
,
{
useEffect
,
useState
}
from
"react"
;
import
'./ArticlesPage.css'
;
import
{
API_BASE_URL
}
from
"../../config"
;
import
{
Header
,
Message
}
from
"semantic-ui-react"
;
import
ArticlesPageTable
from
"../../components/ArticlesPageTable/ArticlesPageTable"
;
import
{
useNavigate
}
from
"react-router-dom"
;
import
{
get
}
from
"../../services/request"
;
export
default
class
ArticlesPage
extends
Component
{
constructor
(
props
)
{
super
(
props
);
this
.
state
=
{
articles
:
null
,
isLoading
:
false
}
}
const
ArticlesPage
=
()
=>
{
const
[
state
,
setState
]
=
useState
({
articles
:
null
,
isLoading
:
false
});
const
navigate
=
useNavigate
();
const
getArticles
=
()
=>
{
const
token
=
localStorage
.
getItem
(
'token'
);
if
(
!
token
)
navigate
(
'/login'
);
async
getArticles
()
{
if
(
!
this
.
state
.
articles
)
{
try
{
this
.
setState
({
isLoading
:
true
});
const
response
=
await
fetch
(
API_BASE_URL
+
'/articles'
,
{
headers
:
{
Accept
:
"application/json"
}
}
)
const
articlesData
=
await
response
.
json
();
this
.
setState
({
articles
:
articlesData
.
data
,
isLoading
:
false
});
}
catch
(
e
)
{
this
.
setState
({
isLoading
:
false
});
console
.
error
(
e
);
}
try
{
setState
(
prevState
=>
({...
prevState
,
isLoading
:
true
}));
const
response
=
get
(
API_BASE_URL
+
"/articles"
,
token
);
response
.
then
(
data
=>
setState
({
articles
:
data
.
data
,
isLoading
:
false
}));
}
catch
(
e
)
{
setState
(
prevState
=>
({...
prevState
,
isLoading
:
false
}));
console
.
error
(
e
);
}
}
componentDidMount
()
{
this
.
getArticles
();
}
useEffect
(()
=>
{
const
token
=
localStorage
.
getItem
(
'token'
);
if
(
!
token
)
navigate
(
'/login'
);
if
(
!
state
.
articles
)
getArticles
();
},
[]);
return
(
<
div
>
<
Header
as=
"h1"
>
Articles
</
Header
>
{
state
.
isLoading
&&
<
Message
info
header=
"Loading articles..."
/>
}
{
state
.
articles
&&
<
ArticlesPageTable
articles=
{
state
.
articles
}
/>
}
</
div
>
);
};
export
default
ArticlesPage
;
render
()
{
return
(
<
div
>
<
Header
as=
"h1"
>
Articles
</
Header
>
{
this
.
state
.
isLoading
&&
<
Message
info
header=
"Loading articles..."
/>
}
{
this
.
state
.
articles
&&
<
ArticlesPageTable
articles=
{
this
.
state
.
articles
}
/>
}
</
div
>
);
}
}
frontend/src/containers/Auth/Login/Login.jsx
0 → 100644
View file @
3d29669b
import
React
,
{
useEffect
,
useState
}
from
'react'
;
import
{
Button
,
Form
,
Message
}
from
'semantic-ui-react'
;
import
{
API_BASE_URL
}
from
"../../../config"
;
import
{
post
}
from
"../../../services/request"
;
import
{
useNavigate
}
from
"react-router-dom"
;
import
Errors
from
"../../../components/Errors/Errors"
;
const
Login
=
()
=>
{
const
[
state
,
setState
]
=
useState
({
email
:
null
,
password
:
null
,
isLoading
:
false
,
errorMessage
:
null
,
errors
:
null
,
error
:
null
});
const
navigate
=
useNavigate
();
useEffect
(()
=>
{
const
token
=
localStorage
.
getItem
(
'token'
);
if
(
token
)
{
navigate
(
"/"
);
}
},
[]);
const
handleSubmit
=
(
e
)
=>
{
setState
(
prevState
=>
({...
prevState
,
isLoading
:
true
}));
const
data
=
{
email
:
state
.
email
,
password
:
state
.
password
};
const
res
=
post
(
API_BASE_URL
+
"/login"
,
data
);
res
.
then
(
response
=>
{
if
(
Object
.
keys
(
response
).
includes
(
'token'
))
{
localStorage
.
setItem
(
'token'
,
response
.
token
);
navigate
(
'/'
);
}
else
if
(
Object
.
keys
(
response
).
includes
(
'error'
))
{
setState
(
prevState
=>
({...
prevState
,
error
:
response
.
error
}));
}
setState
(
prevState
=>
({
...
prevState
,
errorMessage
:
response
.
message
,
errors
:
response
.
errors
,
isLoading
:
false
}));
}
);
};
const
onChangeInputHandler
=
e
=>
{
const
{
name
,
value
}
=
e
.
currentTarget
;
setState
(
prevState
=>
({
...
prevState
,
[
name
]:
value
,
errors
:
null
}));
};
return
(
<
div
>
{
state
.
error
&&
<
Message
negative
><
Message
.
Header
>
{
state
.
error
}
</
Message
.
Header
></
Message
>
}
{
state
.
errors
&&
<
Errors
errors=
{
state
.
errors
}
errorMessage=
{
state
.
errorMessage
}
/>
}
<
Form
>
<
Form
.
Field
>
<
label
>
Email
</
label
>
<
input
type=
"email"
placeholder=
'Email'
name=
'email'
onChange=
{
onChangeInputHandler
}
/>
</
Form
.
Field
>
<
Form
.
Field
>
<
label
>
Password
</
label
>
<
input
type=
"password"
placeholder=
'Password'
name=
'password'
onChange=
{
onChangeInputHandler
}
/>
</
Form
.
Field
>
<
Button
loading=
{
state
.
isLoading
}
type=
'submit'
onClick=
{
(
event
)
=>
handleSubmit
(
event
)
}
>
Login
</
Button
>
</
Form
>
</
div
>
);
};
export
default
Login
;
frontend/src/containers/Auth/Register/Register.jsx
0 → 100644
View file @
3d29669b
import
React
,
{
useEffect
,
useState
}
from
'react'
;
import
{
Button
,
Form
}
from
'semantic-ui-react'
;
import
{
API_BASE_URL
}
from
"../../../config"
;
import
{
post
}
from
"../../../services/request"
;
import
{
useNavigate
}
from
"react-router-dom"
;
import
Errors
from
"../../../components/Errors/Errors"
;
const
Register
=
()
=>
{
const
[
state
,
setState
]
=
useState
({
name
:
null
,
email
:
null
,
password
:
null
,
passwordConfirmation
:
null
,
isLoading
:
false
,
errors
:
null
});
const
navigate
=
useNavigate
();
useEffect
(()
=>
{
const
token
=
localStorage
.
getItem
(
'token'
);
if
(
token
)
{
navigate
(
"/"
);
}
},
[]);
const
handleSubmit
=
(
e
)
=>
{
setState
(
prevState
=>
({...
prevState
,
isLoading
:
true
}));
const
data
=
{
name
:
state
.
name
,
email
:
state
.
email
,
password
:
state
.
password
};
const
res
=
post
(
API_BASE_URL
+
"/register"
,
data
);
res
.
then
(
response
=>
{
if
(
Object
.
keys
(
response
).
includes
(
'token'
))
{
localStorage
.
setItem
(
'token'
,
response
.
token
);
navigate
(
'/'
);
}
setState
(
prevState
=>
({
...
prevState
,
errorMessage
:
response
.
message
,
errors
:
response
.
errors
,
isLoading
:
false
}));
});
};
const
onChangeInputHandler
=
e
=>
{
const
{
name
,
value
}
=
e
.
currentTarget
;
console
.
log
(
name
,
value
);
setState
(
prevState
=>
({
...
prevState
,
[
name
]:
value
,
errors
:
null
}));
};
return
(
<
div
>
{
state
.
errors
&&
<
Errors
errors=
{
state
.
errors
}
errorMessage=
{
state
.
errorMessage
}
/>
}
<
Form
>
<
Form
.
Field
>
<
label
>
Name
</
label
>
<
input
type=
"text"
placeholder=
'Name'
name=
'name'
onChange=
{
onChangeInputHandler
}
/>
</
Form
.
Field
>
<
Form
.
Field
>
<
label
>
Email
</
label
>
<
input
type=
"email"
placeholder=
'Email'
name=
'email'
onChange=
{
onChangeInputHandler
}
/>
</
Form
.
Field
>
<
Form
.
Field
>
<
label
>
Password
</
label
>
<
input
type=
"password"
placeholder=
'Password'
name=
'password'
onChange=
{
onChangeInputHandler
}
/>
</
Form
.
Field
>
<
Button
loading=
{
state
.
isLoading
}
type=
'submit'
onClick=
{
handleSubmit
}
>
Register
</
Button
>
</
Form
>
</
div
>
);
}
export
default
Register
;
frontend/src/routes/router.js
View file @
3d29669b
...
...
@@ -4,6 +4,8 @@ import Root from "./Root";
import
React
from
'react'
;
import
Error
from
"./Error"
;
import
ArticlesPage
from
"../containers/ArticlesPage/ArticlesPage"
;
import
Register
from
"../containers/Auth/Register/Register"
;
import
Login
from
"../containers/Auth/Login/Login"
;
const
router
=
createBrowserRouter
([
{
...
...
@@ -18,6 +20,14 @@ const router = createBrowserRouter([
{
path
:
'/articles'
,
element
:
<
ArticlesPage
/>
},
{
path
:
'/register'
,
element
:
<
Register
/>
},
{
path
:
'/login'
,
element
:
<
Login
/>
}
]
}
...
...
frontend/src/services/request.js
0 → 100644
View file @
3d29669b
function
playWithResponsePromise
(
response
)
{
return
new
Promise
(
function
(
resolve
,
reject
)
{
if
(
response
.
status
<
400
)
response
.
json
().
then
(
resolve
);
else
response
.
json
().
then
(
resolve
);
});
}
export
function
get
(
url
,
token
)
{
return
fetch
(
url
,
{
method
:
'GET'
,
headers
:
{
'Accept'
:
'application/json'
,
'Content-type'
:
'application/json'
,
...
token
&&
{
'Authorization'
:
'Bearer '
+
token
}
}
}
).
then
(
playWithResponsePromise
);
}
export
function
post
(
url
,
data
,
token
)
{
return
fetch
(
url
,
{
method
:
'POST'
,
body
:
JSON
.
stringify
(
data
),
headers
:
{
'Accept'
:
'application/json'
,
'Content-type'
:
'application/json'
,
...
token
&&
{
'Authorization'
:
'Bearer '
+
token
}
}
}
).
then
(
playWithResponsePromise
);
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment