react-laravel redirect issue from middleware - php

I don’t used react-router, just simply used react with blade. Like
following:
articleManage.blade.php
#extends('layout')
#section('content')
<div id="articleManage"></div>
#stop
I try to use jwt authentication, and it works.
Here is my jwt auth middleware:
authJWT.php
try {
$token = JWTAuth::parseToken();
if (! $token->authenticate()) {
return response()->json(['user_not_found'], 404);
}
} catch (Exception $e) {
if ($e instanceof \Tymon\JWTAuth\Exceptions\TokenInvalidException){
return response()->json(['error'=>'Token is Invalid 1']);
}else if ($e instanceof \Tymon\JWTAuth\Exceptions\TokenExpiredException){
return response()->json(['error'=>'Token is Expired 2']);
}else{
return response()->json(['error'=>'Something is wrong 3']);
}
}
return $next($request);
Now I am stuck with redirection on middleware, cause it won’t work when I change it like this:
try {
$token = JWTAuth::parseToken();
if (! $token->authenticate()) {
return response()->json(['user_not_found'], 404);
}
} catch (Exception $e) {
……
return redirect('/');
}
return $next($request);
And this is the error message I got:
TypeError: Cannot read property 'map' of undefined
at ArticleManage.render (app.js:54105)
at app.js:50033
at measureLifeCyclePerf (app.js:49313)
at ReactCompositeComponentWrapper._renderValidatedComponentWithoutOwnerOrContext (app.js:50032)
at ReactCompositeComponentWrapper._renderValidatedComponent (app.js:50059)
at ReactCompositeComponentWrapper._updateRenderedComponent (app.js:49983)
at ReactCompositeComponentWrapper._performComponentUpdate (app.js:49961)
at ReactCompositeComponentWrapper.updateComponent (app.js:49882)
at ReactCompositeComponentWrapper.performUpdateIfNecessary (app.js:49798)
at Object.performUpdateIfNecessary (app.js:2916)
Any idea how to redirect when token error?
10/17: this is my program flow
articleManage.js
let url = 'load-article';
let config = {
headers: {'Authorization': 'Bearer '+localStorage.getItem('token')}
};
axios.get(url,config).then(response=>{
this.setState({'articles':response.data.articles});
}).catch(function (error) {
console.log(error);
});
web.php
Route::get('/load-article', 'API\ArticleController#read')->middleware('jwt-auth');
ArticleController#read
public function read(Request $request){
$header = $request->header('Authorization');
$articles = Article::All();
return response()->json(['articles' => $articles]);
}
now I change middleware, cause I want to try redirection, then I get error.
public function handle($request, Closure $next)
{
// try {
// $token = JWTAuth::parseToken();
// if (! $token->authenticate()) {
// return response()->json(['user_not_found'], 404);
// }
// } catch (Exception $e) {
// if ($e instanceof \Tymon\JWTAuth\Exceptions\TokenInvalidException){
// return response()->json(['error'=>'Token is Invalid 1']);
// }else if ($e instanceof \Tymon\JWTAuth\Exceptions\TokenExpiredException){
// return response()->json(['error'=>'Token is Expired 2']);
// }else{
// return response()->json(['error'=>'Something is wrong 3']);
// }
// }
// return $next($request);
return redirect('/');
}

Shot in the dark here, since you didn't post the whole articleManager component. But, make sure you're passing some sort of failure status code header on all error responses. Otherwise, Axios will read response()->json(['error'=>'Token is Invalid 1']) as a success and attempt to set state. Since response.data.articles is undefined, that's why you're getting the error. So change your middleware in authJWT.php to something like:
} catch (Exception $e) {
if ($e instanceof \Tymon\JWTAuth\Exceptions\TokenInvalidException) {
return response()->json(['error'=>'Token is Invalid 1'], 500);
} else if ($e instanceof \Tymon\JWTAuth\Exceptions\TokenExpiredException) {
return response()->json(['error'=>'Token is Expired 2'], 500);
} else {
return response()->json(['error'=>'Something is wrong 3'], 500);
}
}

Related

Unable to retrieve a one to one polymorphic relationship

I have a pretty complex Laravel application who creates a one to one polymorphic relationship in a middleware if it does not exists. The fact is that I am unable to retrieve the relationship in the same request (create in middleware, then pass it and retrieve it), I have an error 500 when I try to do this. BUT, if I a make an other request I can retrieve it... When I look into my database, I have the userable_id and type defined, I have no idea where this can probably occur.
My middleware look like this:
public function handle(Request $request, Closure $next): mixed
{
if (!Storage::disk('cecurity')->exists(config('coffre_fort.ssl_certificate.name')) ||
!config('coffre_fort.reverse_proxy.username') ||
!config('coffre_fort.reverse_proxy.password') ||
!config('coffre_fort.encryption_key')) {
return response()->json([
'error' => 'Cecurity is not configured correctly.',
], 500);
} elseif (!Auth::user()) {
return response()->json([
'error' => 'You are not authenticated.',
], 401);
}
if (!Auth::user()->cecurityAccount) {
try {
$userType = Auth::user()::class;
/** #phpstan-ignore-next-line */
if ($userType == "App\Models\Admin") {
$this->cecurityRepository->createAdminUser(Auth::user());
} else {
// It enter in this function for creating relationship
$this->cecurityRepository->createFullCustomer(Auth::user());
}
} catch (Exception $e) {
return response()->json([
'error' => $e->getMessage(),
], 500);
}
} elseif (!$this->cecurityRepository->checkConnection()) {
$this->cecurityRepository->connect(
Auth::user()->cecurityAccount->cecurity_user_id,
openssl_decrypt(
Auth::user()->cecurityAccount->password,
'AES-256-CBC',
config('coffre_fort.encryption_key'),
0,
(int) Auth::user()->cecurityAccount->encryption_iv
),
Auth::user()->cecurityAccount->coffre_id
);
}
return $next($request);
}
Then it creates the relationship as this (in the createFulCustomer() function):
$user = new Cecurity;
$user->userable_id = $customer->id_customer;
$user->userable_type = Customer::class;
And then pass the middleware to go to listFiles() function in a controller:
public function listFiles(ListFilesRequest $request): mixed
{
try {
return $this->cecurityRepository->listFiles(
$request->get('nbRowByPage'),
$request->get('pageIndex'),
);
} catch (\Exception $e) {
return response()->json([
'message' => $e->getMessage()
], 500);
}
}
Just after the middleware has passed, my database is completed (Cecurity table related):

Middleware interfering on session messages

I am developing a dashboard and I am trying to handle the errors, for this I have this code on handler.php
public function render($request, Throwable $e)
{
if($e instanceof \Symfony\Component\HttpKernel\Exception\NotFoundHttpException)
{
if(Auth::user() && (Auth::user()->isStaff() || Auth::user()->isAdmin()))
{
return response()->view('dashboard.404error', [], 404);
}
return response()->view('404error', [], 404);
}
elseif ($e instanceof \Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException) {
return response()->view('405error', [], 405);
}
// elseif($this->isHttpException($e) && $e->getStatusCode() == '405')
// {
// return response()->view('404error', [], 404);
// }
return parent::render($request, $e);
}
But to check if the user is logged and what type it is, I have to add this middleware on kernel.php:
Middleware:
\Illuminate\Session\Middleware\StartSession::class,
But I dont know why after that my pop ups stop appering when I edit a staff or create one and I dont know why.
Normally on views I return them with something like this:
return redirect()->route('admin.operadoras')
->with('alert-msg', 'Staff edited with success')
->with('alert-type', 'danger');
And what I have on blade view is this:
#if (session('alert-msg'))
#include('partials.message')
#endif
I dont know why that middleware, interfer with this messages.

Return JSON response instead of 401 Blade file

I am using AuthBasic for API authentication in a Laravel project,
I have this problem: when the API request authentication is invalid instead of displaying the JSON response it returns the 401 default blade view template.
Here is the code:
app\Http\Middleware\AuthBasic.php
public function handle($request, Closure $next)
{
if (Auth::onceBasic()) {
return response()->json(["message", "Authentication Required!"], 401);
} else {
return $next($request);
}
}
Found the Solution:
app\Exceptions\Handler.php
public function render($request, Exception $exception)
{
if ($request->is('api/*') || $request->wantsJson())
{
$json = [
'success' => false,
'error' => [
'code' => $exception->getCode(),
'message' => $exception->getMessage(),
],
];
return response()->json($json, 401);
}
return parent::render($request, $exception);
}
Remove the 401 or change it to 200 from this line:
return response()->json(["message", "Authentication Required!"], 401);
See the reference, the second parameter is defining the http code to send the browser. [401] in you case.
https://laravel.com/api/5.7/Illuminate/Routing/ResponseFactory.html#method_json
This will fix your problem, probably!
public function handle($request, Closure $next)
{
$result = Auth::onceBasic();
if($result === 401)
return response()->json(["message", "Authentication Required!"]);
else
return $next($request);
}
So here is a half Solution for this problem:
vendor\laravel\framework\src\Illuminate\Auth\SessionGuard.php
public function onceBasic($field = 'email', $extraConditions = [])
{
$credentials = $this->basicCredentials($this->getRequest(), $field);
if (! $this->once(array_merge($credentials, $extraConditions))) {
//return $this->failedBasicResponse();
return response()->json(["Message" => "Authentication Required!"], 401);
}
}
So Instead of returning the Failed Basic Response it will return the JSON Message, but I don't want to make changes in Laravel Core Files, because in case of update they will get lost !
So Any Idea ?

slim/csrf implementation not rendering custom error message

slim/csrf not rendering the custom error message.
why it is not outputting the cutstom error message
$container['csrf'] = function ($c) {
$guard = new \Slim\Csrf\Guard();
$guard->setFailureCallable(function ($request, $response, $next) {
$request = $request->withAttribute("csrf_status", "FAILED");
return $next($request, $response);
});
return $guard;
};
this is my post route
$app->post('/welcome',function($request,$response){
if ('FAILED' === $request->getAttribute('csrf_status')) {
return $response->write('fail to validate');
} else {
return $this->view->render($response,'welcome.php');
}
});
it is not outputting the custom error message. it just output
the default text error message(Failed CSRF check!).

Multiple User Models Laravel JWT Auth

I have to user models in my eloquent:
User
OfficeUser
OfficeUser is in defined in the JWT config as standard model.
Now I have written a Middleware for authenticate each of them
authUser:
public function handle($request, Closure $next)
{
Config::set('auth.providers.users.model', \App\User::class);
try {
if (! $user = JWTAuth::parseToken()->authenticate()) {
return response()->json(['user_not_found'], 404);
}
} catch (Tymon\JWTAuth\Exceptions\TokenExpiredException $e) {
return response()->json(['token_expired'], $e->getStatusCode());
} catch (Tymon\JWTAuth\Exceptions\TokenInvalidException $e) {
return response()->json(['token_invalid'], $e->getStatusCode());
} catch (Tymon\JWTAuth\Exceptions\JWTException $e) {
return response()->json(['token_absent'], $e->getStatusCode());
}
return $next($request);
}
authOfficeUser
public function handle($request, Closure $next)
{
try {
if (! $user = JWTAuth::parseToken()->authenticate()) {
return response()->json(['user_not_found'], 404);
}
} catch (Tymon\JWTAuth\Exceptions\TokenExpiredException $e) {
return response()->json(['token_expired'], $e->getStatusCode());
} catch (Tymon\JWTAuth\Exceptions\TokenInvalidException $e) {
return response()->json(['token_invalid'], $e->getStatusCode());
} catch (Tymon\JWTAuth\Exceptions\JWTException $e) {
return response()->json(['token_absent'], $e->getStatusCode());
}
return $next($request);
}
Additionally I have a login function for each of them:
LoginUser
if ($user){
if (Hash::check($request->password, $user->password)) {
// grab credentials from the request
$credentials = $request->only('email', 'password');
try {
// attempt to verify the credentials and create a token for the user
Config::set('auth.providers.users.model', \App\User::class);
if (! $token = JWTAuth::attempt($credentials)) {
return response()->json(['error' => 'invalid_credentials'], 401);
}
} catch (JWTException $e) {
// something went wrong whilst attempting to encode the token
return response()->json(['error' => 'could_not_create_token'], 500);
}
LoginOfficeUser
if ($user){
if (Hash::check($request->password, $user->password)) {
// grab credentials from the request
$credentials = $request->only('email', 'password');
try {
// attempt to verify the credentials and create a token for the user
Config::set('auth.providers.users.model', \App\OfficeUser::class);
if (! $token = JWTAuth::attempt($credentials)) {
return response()->json(['error' => 'invalid_credentials'], 401);
}
} catch (JWTException $e) {
// something went wrong whilst attempting to encode the token
return response()->json(['error' => 'could_not_create_token'], 500);
}
Unfortunately when I login and try to call a route behind the authUser Middleware I get an "user_not_found"
Does anybody have an idea why this happens?
OfficeUser authentication works fine
Posting for anyone who finds this questions
Although it's not recommended to have two user tables, but I had a similar requirement of setting up JWT with one of our clients. This is how I solved the issue.
No need to make any changes to the providers in `config/auth.php'
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\User::class,
],
]
In your authentication controller, dynamically modify the model used by the providers by setting
\Config::set('auth.providers.users.model', \App\Trainer::class);
Example code
In authenticate() method
if ($credentials['user_type'] == 'consultant') {
\Config::set('auth.providers.users.model', \App\Trainer::class);
} else {
\Config::set('auth.providers.users.model', \App\User::class);
}
//Find the user
//Create the token
if ($user) {
$customClaims = ['user_type' => $credentials['user_type']];
$token = JWTAuth::fromUser($user,$customClaims);
} else {
return response()->json(['error' => 'invalid_credentials'], 401);
}
You will have to do the same while parsing the token to authenticate the user as well. Example code
In getAuthenticatedUser() method
$payload = JWTAuth::parseToken()->getPayload();
$user_type = $payload->get('user_type');
if($user_type === 'consultant'){
\Config::set('auth.providers.users.model', \App\Trainer::class);
}else{
\Config::set('auth.providers.users.model', \App\User::class);
}
if (!$user = JWTAuth::parseToken()->authenticate()) {
return response()->json(['user_not_found'], 404);
}
You can change the __construct function in each of your controllers as follows. So that jwt know which model to authenticate.
OfficeUserController
function __construct()
{
Config::set('jwt.user', OfficeUser::class);
Config::set('auth.providers', ['users' => [
'driver' => 'eloquent',
'model' => OfficeUser::class,
]]);
}

Categories