I'm having an issue with Laravel session create and read.
I can create session values , but problem is access the data.
If I create an session value in POST request, then I can't access it on GET request.
Here is my route
Route::get('/', 'HomeController#index');
Route::get('/admin/dashboard', 'AdminController#dashBoard');
Route::post('/admin/login_admin', 'AdminController#doLogin');
Route::post('/admin/login_test', 'AdminController#test');
Route::get('/admin/login', 'AdminController#seeLogin');
Here the doLogin using post method:
public function doLogin(Request $request){
$email = $request->input("email");
$password = $request->input("password");
$checkerInfo = AdminGetLoginChecker($email, $password);
//if logged in
if($checkerInfo){
$request->session()->put('loggedIn', '1');
$request->session()->put('userId', $checkerInfo);
$request->session()->save();
return response()->json([
'success' => true,
'message' => 'logged In'
]);
}
return response()->json([
'success' => false,
'message' => 'Incorrect User Email, Password'
]);
}
Now problem is if request to access the session value in other get request section, then it doesn't allow to access.
public function dashboard(Request $request)
{
$data = $request->session()->all();
print_r($data);
return view('welcome', ['name' => 'James']);
}
Here it doesn't show the saved session data, because it's a GET request.
Now if try to get request in any another method using POST request it'll show the saved data earlier in doLogin Method
//it's a POST requset
public function test(Request $request)
{
$data = $request->session()->all();
print_r($data);
}
How can I access the session data in GET requested methods?
Thanks in Advance,
Update:
Please note that add the url "'/admin/login_admin'" in excepts area of verifyCsrfToken middelwere to avoid csrf token issue while posting data
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as BaseVerifier;
class VerifyCsrfToken extends BaseVerifier
{
/**
* The URIs that should be excluded from CSRF verification.
*
* #var array
*/
protected $except = [
//
'url' => '/admin/login_admin'
];
}
Why are you trying to manually authenticate user?
For session operation use "Session" facade.
eg:
Session::set('your_session_key', 'Session Value');
Session::save();
$yourSessionKey = Session::get('your_session_key');
let's try it like this
$input = $request->all();
// imagine you have Admin.php model
$query = Admin::login($input['email'], $input['password'])->first();
if ($query)
{
Session::put('userId', $query->id);
Session::save();
return "u're in";
}
else{
return "User name or password is wrong";
}
and in your test function
return $request->session()->get('userId');
Related
I'm trying to implement authentication & authorization of users between my microservices and API Gateway.What I have now:
API Gateway which can request to any microservice.
User microservice - where I'm storing all users. laravel/passport implemented to authenticate user in this microservice. Works as it should be, login route returns token which I'm using to authenticate user in this microservice.
Other 5 microservices without any authentication or authorization.
Question is: what is the right way to use authentication & authorization with microservices? I know that I should authenticate users in my API Gateway and authorization will happen inside microservices. But how authorization in other microservices happening if they don't know anything about users?
I'm planning to use somehow JWT token with information about user roles but haven't found yet how to put that information into token
I'll try to explain with a basic example for API.
Let's say you have currently 3 microservices :
Users
Posts
Core
I assume you're using httpOnly cookie to store user token.
In Core microservice I have this route structure:
Route::prefix('core')->group(function () {
Route::post('register', [AuthController::class, 'register']);
Route::post('login', [AuthController::class, 'login']);
Route::middleware('scope.trader')->group(function () {
Route::get('user', [AuthController::class, 'user']);
});
});
Now i want to login which i should send an API request, and I should think of a solution to send token anytime I need it.
login(this is where you get token) and register don't need token
user need token (this is where you asked for solution)
So in addition to get a result, I should create a service for user, and here how I've done it :
UserService :
class UserService extends ApiService
{
public function __construct()
{
// Get User Endpoint Microservice API URL
$this->endpoint = env('USERS_MS') . '/api';
}
}
ApiService :
abstract class ApiService
{
protected string $endpoint;
public function request($method, $path, $data = [])
{
$response = $this->getRequest($method, $path, $data);
if ($response->ok()) {return $response->json();};
throw new HttpException($response->status(), $response->body());
}
public function getRequest($method, $path, $data = [])
{
return \Http::acceptJson()->withHeaders([
'Authorization' => 'Bearer ' . request()->cookie('token')
])->$method("{$this->endpoint}/{$path}", $data);
}
public function post($path, $data)
{
return $this->request('post', $path, $data);
}
public function get($path)
{
return $this->request('get', $path);
}
public function put($path, $data)
{
return $this->request('put', $path, $data);
}
public function delete($path)
{
return $this->request('delete', $path);
}
}
If you're wondering where, this UserService come from, then I should say, I've created a package to use it in other microservices, so you can do the same or just create a service and use it in your microservices or etc.
Everything is obvious about ApiService, but I'll try to explain the base.
Anytime we want to do an API call, we can simply call Allowed methods in this class, then our methods, will call request, to pass common arguments, and eventually using those arguments to do the API call.
getRequest method, is doing the call and get the stored token from httpOnly cookie, and will send it as an Authorization header to the target endpoint, and eventually it'll return whatever it get from target.
So If we want to use this, we can simply do like this in our controller :
class AuthController extends Controller
{
// use Services\UserService;
public UserService $userService;
/**
* #param UserService $userService
*/
public function __construct(UserService $userService)
{
$this->userService = $userService;
}
public function register(RegisterRequest $request)
{
$data = $request->only('name', 'email', 'password') + ['additional_fileds' => 0 ];
// additional fields can be used for something except from request and
// optional, like is it admin or user or etc.
// call the post method, pass the endpoint url(`register`), pass $data
$user = $this->userService->post('register', $data);
// get data from target endpoint
// and ...
return response($user, Response::HTTP_CREATED);
}
public function login(Request $request)
{
// same thing here again, but this time i passed scope to help me
// get the specific user scope
$data = $request->only('email', 'password') + ['scope' => 'writer'];
$response = $this->userService->post('login', $data);
// as you can see when user do success login, we will get token,
// which i got that token using Passport and set it to $cookie
$cookie = cookie('token', $response['token'], 60 * 24); // 1 day
// then will set a new httpOnly token on response.
return response([
'message' => 'success'
])->withCookie($cookie);
}
public function user(Request $request)
{
// Here, base on userService as you saw, we passed token in all requests
// which if token exist, we get the result, since we're expecting
// token to send back the user informations.
$user = $this->userService->get('user');
// get posts belong to authenticated user
$posts = Post::where('user_id', $user['id'])->get();
$user['posts'] = $posts;
return $user;
}
}
Now, how about user microservice? well Everything is clear here, and it should work like a basic app.
Here's the routes :
Route::post('register', [AuthController::class, 'register']);
Route::post('login', [AuthController::class, 'login']);
Route::middleware(['bunch','of', 'middlewares'])->group( function (){
Route::get('user', [AuthController::class, 'user']);
});
And in controller :
class AuthController extends Controller
{
public function register(Request $request)
{
$user = User::create(
$request->only('first_name', 'email', 'additional_field')
+ ['password' => \Hash::make($request->input('password'))]
);
return response($user, Response::HTTP_CREATED);
}
public function login(Request $request)
{
if (!\Auth::attempt($request->only('email', 'password'))) {
return response([
'error' => 'user or pass is wrong or whatever.'
], Response::HTTP_UNAUTHORIZED);
}
$user = \Auth::user();
$jwt = $user->createToken('token', [$request->input('here you can pass the required scope like trader as i expalined in top')])->plainTextToken;
return compact('token');
}
public function user(Request $request)
{
return $request->user();
}
}
So here's the complete example and you can use the Core microservice approach on other microservices to get your information related to authenticated user, and as you can see everything will be authenticated due to those requests from core to other microservices.
So I'm trying to make a laravel API for a escorts-like site, anyway, i use Passport for authentification and the register part works but the login one doesnt, and i dont know why, i'll let the passportAuthController down as code and a ss of the database
class passportAuthController extends Controller
{
/**
* handle user registration request
*/
public function registerUserExample(RegisterUserRequest $request){
///TODO: TEST THE CRUD FEATURES IMPLEMENTED IN THE USER CONTROLLER AFTER U CHECK LOGIN FEATURE
$attributes = $request -> validated();
$user = User::create($attributes);
$access_token_example = $user->createToken('RegisterToken')->accessToken;
//return the access token we generated in the above step
return response()->json(['token'=>$access_token_example],200);
}
/**
* login user to our application
*/
public function loginUserExample(Request $request){
$login_credentials=[
'email'=>$request->email,
'password'=>$request->password,
];
if(auth()->attempt($login_credentials)){
//generate the token for the user
$user_login_token= auth()->user()->createToken('LoginToken')->accessToken;
//now return this token on success login attempt
return response()->json(['token' => $user_login_token], 200);
}
else{
//wrong login credentials, return, user not authorised to our system, return error code 401
return response()->json(['error' => 'UnAuthorised Access'], 401);
}
}
/**
* This method returns authenticated user details
*/
// index function
public function authenticatedUserDetails(){
//returns details
return response()->json(['authenticated-user' => auth()->user()], 200);
}
}
The request as well:
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class RegisterUserRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'name'=>'required|max:255|min:3',
'email'=>'required|email',
'password'=>'required|min:7|max:255',
'gender'=>'required|min:4|max:6',
'interest'=>'required|min:4|max:6',
'Country'=>'required|max:255',
'County'=>'required|max:255',
'City'=>'required|max:255',
'birthday'=>'required|date'
];
}
}
and the ss of the database:
and the routes (api.php):
<?php
use App\Http\Controllers\passportAuthController;
use App\Http\Controllers\UserController;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/
Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
return $request->user();
});
//routes/api.php
//login & register routes
Route::post('register',[passportAuthController::class,'registerUserExample']);
Route::post('login',[passportAuthController::class,'loginUserExample']);
//CRUD and search routes
Route::post('storeUser',[UserController::class,'store']);
Route::get('showAll',[UserController::class, 'index']);
Route::put('updateUser/{id}',[UserController::class,'update']);
Route::delete('delete/{id}', [UserController::class,'deleteUser']);
Route::get('search/{name}',[UserController::class,'search']);
//add this middleware to ensure that every request is authenticated
Route::middleware('auth:api')->group(function(){
Route::get('user', [passportAuthController::class,'authenticatedUserDetails']);
});
Your password in users table is not encrypted.
The reason is this line
$attributes = $request->validated();
$user = User::create($attributes);
You have not encrypted your password and the method auth()->attempt($login_credentials) uses compares the encrypted password request with stored encrypted password in your db.
You can use bcrpyt() to encrypt your password, laravel comes with bcrypt() as a helper function.
Change to this in your registerUserExample(RegisterUserRequest $request)
$attributes = $request->validated();
foreach($attributes as $key => $attribute){
if($key == 'password') {
$attributes[$key] = bcrypt($attribute);
}
}
$user = User::create($attributes);
so if you see the response is mean that wrong login credentials, return, user not authorised to our system, return error code 401 ,
So with a little observation you will know that your code work fine but your logic is not good ,
So the answer simply is because the password insert in your database is note crypted and laravel passport when they are trying to make login they use a function of check ,
so if you want your code work your password must be crypted in the register exemple
$user->password = hash::make($request->password);
Or
$user->password = Crypt::encrypt($request->password);
Conclusion you can't make authentification with laravel passport if your password not crypted
The attempt method accepts an array of key / value pairs as its first argument. The password value will be hashed. The other values in the array will be used to find the user in your database table. So,
You try this
public function loginUserExample(Request $request){
$user = User::where('account', $request->account)
->where('password', $request->password)
->first();
if($user) {
Auth::loginUsingId($user->id);
// -- OR -- //
Auth::login($user);
return redirect()->route('home');
} else {
return redirect()->back()->withInput();
}
}
I am using Laravel Passport and have a logout function in the controller. See below:
public function logout(Request $request){
auth()->user()->token()->revoke();
$response = ['message' => 'You have been successfully logged out!'];
return response($response, 200);
}
I am now trying to write a unit test for this but the user stays logged in even after the logout and the token being revoked. I have found this Method Illuminate\Auth\RequestGuard::logout does not exist Laravel Passport but even this solution does not work for me. I am guessing it might be because I am using Laravel 8. My Unit test looks like this:
public function testLogout()
{
//Random email and password
$email = $this->faker->email;
$password = $this->faker->password(8);
//Create a user
$this->createUser($this->faker->name, $email, $password);
//Data for the post request
$data = [
'email' => $email,
'password' => $password
];
//Try login
$response = $this->json('POST','api/login', $data);
//Assert it was successful
$response->assertStatus(200);
//Assert we received a token
$this->assertArrayHasKey('token', $response->json());
//Get the token
$token = $response->json()['token'];
//Setup authenticated header
$header = [
'Authorization' => 'Bearer '.$token
];
//try to access authenticated route
$response = $this->json('get', 'api/ads', [], $header);
//Assert it was successful
$response->assertStatus(200);
$this->resetAuth();
//Logout the user
$response = $this->post('api/logout', [], $header);
//Assert it was successful
$response->assertStatus(200);
//try to access authenticated route
$response = $this->json('get', 'api/ads', [], $header);
//Assert it returns unathorized error
$response->assertStatus(401);
//Delete the user
User::where('email', $email)->delete();
}
And the result is the following:
Expected status code 401 but received 200.
Failed asserting that 401 is identical to 200.
You are doing too much in a single test. But other than that, I couldn't really spot any issues in your code. But this worked for me:
class LogoutController extends Controller
{
public function __construct()
{
$this->middleware('auth:api');
}
public function logout()
{
Auth::user()->token()->revoke();
$tokenId = Auth::user()->token()->id;
$refreshTokenRepository = app('Laravel\Passport\RefreshTokenRepository');
$refreshTokenRepository->revokeRefreshTokensByAccessTokenId($tokenId);
return response(null, Response::HTTP_NO_CONTENT);
}
}
And the test can simply do something like:
public function testAnAuthenticatedUserCanLogout()
{
$user = User::factory()->create();
Passport::actingAs($user);
$this->postJson('/api/logout')
->assertNoContent();
}
Your logout method looks strange. I would do this
use Illuminate\Support\Facades\Auth;
// ... other controller methods
public function logout(Request $request)
{
Auth::logout();
$request->session()->invalidate();
$request->session()->regenerateToken();
// ...do a redirect or other stuff
}
to logout out. This should properly logout the user. This is also the proposed way in the Laravel docs.
For logging out from Laravel Passport you can run
if (Auth::check()) {
Auth::user()->token()->revoke();
}
to revoke the current token used. This will definitely log the user out from the current device where he requested to log out.
Make sure in your routes/web.php you have your logout route inside the group(['middleware' => 'auth:api'] group.
If you want to log out from all the devices where he's logged in, you can also remove the token from database.
This question already has an answer here:
Class 'App\Http\Controllers\admin\Auth' not found in Laravel 5
(1 answer)
Closed 10 months ago.
Here Is my routes in api.php. After Authentication i am not getting the user details in other route
Route::post('/login','CustomLogin#userLogin');
Route::group(['middleware' => 'auth:api'], function(){
Route::post('/change-password','ChangePassword#changePassword');
});
public function changePassword(ChangepassRequest $request){
$user = Auth::user();
print_r($user);
die();
}
Update: I was new in laravel then.. So the Actual Problem was class Auth not found! Thank You For the Comments!
I am updating my answer as well !
Maybe something wrong with your login method if you have set up all correctly in the token system.
you can use the below snippet to log in users, which might change as per your credentials.
<?php
class AuthController extends Controller
{
/**
* Get a JWT via given credentials.
*
* #return \Illuminate\Http\JsonResponse
*/
public function login()
{
if (request::has(['email', 'password'])) {
$user = User::whereEmailAndPassword(request()->get('email'),request()->get('password'))->first();
$credentials = request(['email', 'password']);
if ($user and $token = auth()->attempt($credentials)) {
return response()->json(['message' => 'Login Successful', 'jwt_token'=>$token], 200);
} else {
return response()->json(['message' => 'Unauthorized'], 401);
}
} else {
return response()->json(['message' => 'Pease provide your email and password to login'], 401);
}
}
}
And Of course, there is a thousand of way to do this same thing
You comment $user line so this variable not declare at all.
// $user = Auth::user();
You should uncomment it :))
The Solution Was adding The use Auth in my Controller! That's All
I am using Facebook PHP SDK to log my user.
I created a guard called login for this
Here is my config file of auth.php
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
],
'admin'=>[
'driver'=>'session',
'provider'=>'adminusers',
],
'verify'=>[
'driver'=>'session',
'provider'=>'verify',
],
'login'=>[
'driver'=>'session',
'provider'=>'users'
]
],
to access Facebook api i created a class in App\services namespace called it Facebook
App\Services\Facbook.php
<?php
namespace App\Services;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Config;
use App\Extensions\Facebook\FacebookLaravelPersistentDataHandler;
use Facebook\Facebook as FB;
use App;
class Facebook{
protected $fb;
protected $helper;
protected $permission;
protected $log;
protected $canvashelper;
protected $persistentDataHandler;
function __construct()
{
$this->fb = new FB([
'app_id'=>Config::get('facebook.app_id'),
'app_secret'=>Config::get('facebook.app_secret'),
'default_graph_version' => Config::get('facebook.default_graph_version'),
'persistent_data_handler' => new FacebookLaravelPersistentDataHandler(),
]);
$this->helper = $this->fb->getRedirectLoginHelper();
$this->permission = Config::get('facebook.permission');
$this->log = new Logging(Config::get('facebook.logfile'),'Facebook Log');
$this->canvashelper = $this->fb->getCanvasHelper();
$this->persistentDataHandler = new FacebookLaravelPersistentDataHandler();
}
public function FBAuthUrl()
{
if($this->isFBAuth())
{
return $this->helper->getLogoutUrl($this->persistentDataHandler->get('facebook_access_token'),route('facebook.logout'));
}
else
{
return $this->helper->getLoginUrl(route('facebook.callback'),$this->permission);
}
}
public function LoginCallback()
{
$accessToken = $this->helper->getAccessToken();
if(isset($accessToken))
{
$this->persistentDataHandler->set('facebook_access_token',(string) $accessToken);
}
}
public function isFBAuth()
{
return $this->persistentDataHandler->has('facebook_access_token');
}
public function getFBUser()
{
if($this->isFBAuth())
{
$this->fb->setDefaultAccessToken($this->persistentDataHandler->get('facebook_access_token'));
/*,user_birthday,user_tagged_places*/
$response = $this->fb->get("/me?fields=id,name,first_name,last_name,age_range,link,gender,locale,picture,timezone,updated_time,verified,email");
return $response->getGraphUser();
}
else
{
return false;
}
}
public function logout()
{
$this->persistentDataHandler->delete('facebook_access_token');
$this->persistentDataHandler->delete('state');
}
}
And Here is my UserController Where i write my login logic
class UserController extends Controller
{
.....
/*
* Facebook login callback function
* #param Object App\services\Facebook
* return redirect
*/
public function fbLogin(Facebook $facebook)
{
$facebook->LoginCallback();
/*
* get the usergraphnode from facebook
*/
$fbUser = $facebook->getFBUser();
/*
* Convert UserGraphNode User To Eloquent User
*/
$user = $this->getFBLoggedUser($fbUser);
/*
* Here Log the user in laravel System
*/
Auth::guard('login')->login($user);
//dump(Auth::guard($this->guard)->user());
dump(session()->all());
return reidrect('/');
}
public function getFBLoggedUser($fbUser)
{
if(User::where('email','=',$fbUser->getField('email'))->count())
{
$user = User::where('email','=',$fbUser->getField('email'))->first();
if($user->fb_app_id){
$user->fb_app_id = $fbUser->getField('id');
$user->save();
}
}
else
{
$user = $this->FBregister($fbUser);
}
return $user;
}
/**
* Register The user logged in from Facebook
*
* #param \Facebook\GraphNodes\GraphUser;
*
* return \App\Models\User
*/
public function FBregister($fbUser)
{
$user = new User();
$user->fname = $fbUser->getField('first_name');
$user->lname = $fbUser->getField('last_name');
$user->gender = $fbUser->getField('gender');
$user->email = $fbUser->getField('email');
$user->fb_app_id = $fbUser->getField('id');
$picture = $fbUser->getField('picture');
if($picture->isSilhouette()){
$user->profile_image = $picture->getUrl();
}
$user->save();
return $user;
}
.........
}
On Successful Facebook login redirect i am calling UserController#fbLogin
after calling Auth::guard()->login() i dump session it successfully show a login_login_randomstring=>UserId i session . but When i redirect it all session data lost.
But the weird thing is that it only happen when it calling through facebook redirect. If i use this function like normal login routes it works perfactaly like this
in route.php
Route::get('/login','UserController#login');
and in UserController
function login(){
$user = User::find(12);
Auth::guard('login')->login($user);
return redirect('/');
}
Using this method i can easily access Session data after redirecting from here but in facebook case it doesn't happening.
I stuck here for two days please anyone can help me
[Note: Please don't mention in your answer that i should grouped my routes in web middleware. ]
After digging very deep in laravel i finally found what i was doing wrong. And i am posting may be it help some in future.
Important thing :- Laravel save session very last in its request life-cycle. It saves session it sends header response. So if we echo something in controller class then it will send header response without doing saving session and our session will not save. In my case i use dump function in my controller which terminate the laravel default life-cycle and forcefully send header response to browser. that's why all of session data is lost. i remove dump() form my code and everything start working correctly
According to API documentation https://laravel.com/api/5.2/Illuminate/Auth/Guard.html you should call user() method to get the currently authenticated user. So i would suggest that instead of Auth::guard() use Auth::user($user).
try to use plugin socialite for login with facebook socialite
Facebook php sdk use $_SESSION.In laravel you cannot access this variable,laravel use personal class for session.
According to api code and your facebook documentation. Simple session working with request. You can save your data with
For put session in value
Session::put('userid','1');
Retrieve the value
$request->session()->get('userid') //or
{!! Session::get('userid') !!}
Very useful thing in your case.