Now when I want to log out my user, I send a post request to my API (with Bearer token)
Route::group(['middleware' => ['auth:api']], function () {
Route::post('/logout', 'UserApiController#logout');
});
UserApiController.php
public function logout(){
if (Auth::check()) {
Auth::user()->token()->revoke();
return response()->json(['success' =>'logout_success'],200);
}else{
return response()->json(['error' =>'api.something_went_wrong'], 500);
}
}
The answers here are all great. If revoke() does not work i.e
Auth::user()->token()->revoke();
does not work, use,
public function logout(Request $request)
{
$response = self::HTTP_CREATED;
$user= $request->user();
unset($user->api_token);
$user->save();
return response()->json([
'response' => 'true',
'result' => '',
'message' => 'User logged out'
], $response);
}
The goal is to remove the token from the table which the above code does manually.
Also tested with laravel 7.24, if you do not use middleware in api-routes.:
api.php
Route::post('/logout', 'LoginController#logout');
Use the api-guard (= passport) and then the standard laravel passport "revokeAccessToken" method.
public function logout ()
{
$tokenRepository = app('Laravel\Passport\TokenRepository');
$user = auth('api')->user();
if ($user) {
$tokenRepository->revokeAccessToken($user->token()->id);
return 'logged out';
} else {
return 'already logged out';
}
}
Related
Im making a api with laravel 9 about a fitness app. This app will have 2 roles Admin and Normal user. What im struggling with is making an Authentication system for the users, so that an Admin can have access to certain routes that a normal user wont. To do that i created a middleware called AdminMiddleware
{
if(Auth::check()){
//if admin role = 1
$user = Auth::guard('api')->user();
if(Auth::user()->role == 1){
return $next($request);
}
else{
return redirect('/login')->with('message', 'Access Denied');
}
}
else{
return redirect('/login')->with('message', 'Log In to gain access');
}
return $next($request);
}
This checks whether the user is an admin or not.
This is the routes where the middleware is used
Route::middleware(['auth', 'isAdmin'])->get('/admin', function () {
Route::post('/addProducts', [ProductController::class, 'store']);
Route::delete('/deleteProducts/{id}', [ProductController::class, 'destroy']);
Route::post('/addRecipe', [RecipeController::class, 'store']);
Route::put('/updateRecipe/{id}', [RecipeController::class, 'update'], function (Request $id) {
return 'Recipe '.$id;
});
Route::delete('/deleteRecipe/{id}', [RecipeController::class, 'destroy']);
Route::post('/addEvent', [SpecialEventsController::class, 'store']);
Route::get('event/{id}', [SpecialEventsController::class, 'show'], function (Request $id) {
return 'Events '.$id;
});
Route::put('/updateEvent/{id}', [SpecialEventsController::class, 'update'], function (Request $id) {
return 'Recipe '.$id;
});
Route::delete('/deleteEvent/{id}', [SpecialEventsController::class, 'destroy']);
});
And this is the Login Controller, where im having my problems:
public function login(Request $request)
{
//(Auth::guard('api')->attempt(['email' => $request->email, 'password' => $request->password]))
if(Auth::guard('api')(['email' => $request->email, 'password' => $request->password])){
$user = Auth::guard('api')->user();
if($user){
$success['token'] = $user->createToken('MyApp')->accessToken;
$success['name'] = $user->name;
$success['role'] = $user->role;
return $this->sendResponse($success, 'User login successfully.');
}
else{
return $this->sendError('Unauthorised.', ['error'=>'Unauthorised']);
}
}
else{
return $this->sendError('Unauthorised.', ['error'=>'Unauthorised']);
}
}
}
This code is returning
Error: Object of type Laravel\Passport\Guards\TokenGuard is not callable in file C:\xampp\htdocs\Ritwell-App - Copy (2)\app\Http\Controllers\API\RegisterController.php on line 52
The part
Auth::guard('api')(['email' => $request->email, 'password' => $request->password])){
was originally
if(Auth::attempt
but that code gave me an exception
BadMethodCallException: Method Laravel\Passport\Guards\TokenGuard::attempt does not exist. in file C:\xampp\htdocs\Ritwell-App - Copy (2)\vendor\laravel\framework\src\Illuminate\Macroable\Traits\Macroable.php on line 113
I tried using resources online to help with answers but this is what i could come up with so far and it isnt working.
Can someone tell me what am i doing wrong and what is missing in my code?
I'm able to register successfully which should imply that the user's authenticated but it turns out that's not the case for some reason.
Upon trying to logout on the frontend:
When running dd(Auth::check()); - it always returns false when it's OUTSIDE of the middleware('auth:api');.
However, when running dd(Auth::check()); - it always returns {message: "Unauthenticated."} when it's INSIDE of the middleware('auth:api');.
Can anyone show me what I'm doing wrong?
api.php:
Route::middleware('auth:api')->group( function () {
Route::post('/logout', [RegisterController::class, 'logout']);
});
RegisterController.php:
public function logout(Request $request) {
$headers = collect($request->header())->transform(function ($item) {
return $item[0];
});
$success['cookie'] = 'Bearer' . $headers['cookie'];
$success['content-type'] = $headers['content-type'];
$success['authenticated'] = Auth::check();
dd(Auth::check());
return response()->json([
'message' => 'Successfully logged out',
'cookie' => $success['cookie'],
'content-type' => $success['content-type'],
'authenticated' => $success['authenticated']
]);
}
Please Help! I want to authenticate my app, so that user cannot enter through URL in the browser to user panel without login, how can I do it in Vue.js and Laravel? If he write the URL like this: http://127.0.0.1:8000/users even if he did not put his credencials in login page
Bellow is my code:
AppController
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
//use illuminate\Support\Facades\Auth;
use Auth;
use App\User;
use Illuminate\Support\Facades\Hash;
/**vc pode pegar o usuário logado de várias formas, usando Auth::user(), usando helper auth()->user() e também pela request fazendo $request->user(); ou pela fachada da request tb, Request::user(); */
class AppController extends Controller
{
public function init(){
$user = Auth::user();
//$user = auth()->user();
return response()->json(['user' => $user], 200);
}
public function login(Request $request)
{
if (Auth::attempt(['email' => $request->email, 'password' => $request->password], true)) {
return response()->json(Auth::user(), 200);
}
else{
return response()->json(['error' => 'Could not allow you in. Sorry'], 401);
}
}
public function register(Request $request)
{
$user = User::where('email', $request->email)->first();
if (isset($user->id)) {
return response()->json(['error' => 'User already exist.'], 401);
}
$user = new User();
$user->name = $request->name;
$user->email = $request->email;
$user->password = Hash::make($request->password);
$user->save();
Auth::login($user);
return response()->json($user, 200);
}
public function logout()
{
Auth::logout();
}
}
Vue template LOGIN:
<script>
export default {
name: 'login',
props:['app'],
data(){
return {
email: '',
password: '',
errors: [],
}
},
methods: {
onSubmit(){
this.errors = [];
if(!this.email){
this.errors.push('Email is require.');
}
if(!this.password){
this.errors.push('Password is require.');
}
if(!this.errors.length){
const data = {
email : this.email,
password : this.password
}
this.app.req.post('auth/login' , data).then(response => {
this.app.user = response.data;
//this.$eventHub.$emit('onSubmit', this.MainHeader);
this.$router.push('/users');
//this.app.MainHeader = 'main-header';
console.log(this.app.MainHeader);
}).catch(error => {
this.errors.push(error.response.data.error);
});
}
}
}
}
</script>
app.js file
const router = new VueRouter({
//mode: 'history',
routes // short for `routes: routes`
})
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth)) {
// this route requires auth, check if logged in
// if not, redirect to login page.
if (!auth.loggedIn()) {
next({
path: '/login',
query: { redirect: to.fullPath }
})
} else {
next()
}
} else {
next() // make sure to always call next()!
}
});
Routers
path: '/users',
component: Users,
name: 'users',
meta:{requiresAuth:true},
children: [
{
path: 'dashboard',
component: Dashboard,
name: 'dashboard'
},
}
You dont show your /users route so we cant show you the exact change you need. That said, you need to apply the auth middleware to that route. Something like this is what you want:
You'll need to update the namespace and controller names of course
Route::group([
'middleware' => ['web','auth'], // <---- note the auth middleware here
'namespace' => 'App\Http\Controllers',
],
static function () {
Route::get('/users', 'UserController#render')->name('users');
}
);
I am creating API with Default api-authentication
I am using laravel 6.x
Its run when i generate on user register and pass generated token with request.
But
when i pass a wrong token, Then it shows a Login page HTML, i want to show some custom JSON response instead of HTML
Also is there any way to check that passed token is same with passed user id or not. Because user can pass different user id with token.
My api route file as below
Route::middleware('auth:api')->post('/listUser', 'ApiController#listUser');
I have manage my points as below
For Point 1
when i pass a wrong token, Then it shows a Login page HTML, i want to show some custom JSON response instead of HTML
I made change in App/Exceptions/handler.php
Modify render function as below
public function render($request, Exception $exception)
{
if ($exception instanceof NotFoundHttpException) {
if ($request->is('api/*')) {
return response()->json(['error' => 'Not Found'], 404);
}
//return response()->view('404', [], 404);
}
return parent::render($request, $exception);
}
It workrs well because i have an api based routes
My api route look likes
// Request with Authentication v1
Route::group(['prefix' => 'v1', 'namespace' => 'Api\v1', 'middleware' => ['api','auth:api'] ], function () {
Route::post('/myProfile', 'ApiController#myProfile');
});
// Request without Authentication v1
Route::group(['prefix' => 'v1', 'namespace' => 'Api\v1', 'middleware' => 'api'], function () {
Route::post('/register', 'ApiController#register');
});
For Point 2
Also is there any way to check that passed token is same with passed user id or not. Because user can pass different user id with token.
For that i have created a function checkValidations in ApiController and check user id is associated with particular token or not as below:
In that function i check in way that
Check for all validation passed from called method
Match token associated with user id then return success
else return invalid token response
Function Code
public function checkValidations($required = [], $request = [])
{
$validator = Validator::make($request->all(), $required);
if ($validator->fails()) {
$this->response[] = array(
'status' => 'false',
'response_msg' => implode(",",$validator->messages()->all()),
);
return array('response' => $this->response);
} else if(isset($request['api_token']) && auth('api')->user()->id ==
$request['id']) {
return 'success';
} else {
$this->response[] = array(
'status' => 'false',
'response_msg' => 'Invalid token',
);
return array('response' => $this->response);
}
}
And call that checkValidations from any function and can reuse it as
public function myProfile(Request $request)
{
$validation = [
'id' => 'bail|required|exists:users',
'api_token' => 'bail|required|min:60|max:60'
];
if( $this->checkValidations($validation, $request) == 'success'){
$this->response[] = array(
'status' => 'true',
'response_msg' => 'Success',
'data' => auth('api')->user()
);
}
return array('response' => $this->response);
}
May be there is many other best way to manage that points, but i didn't found, so i manage in above ways.
You can configure a custom response in the Authenticate middleware. e.g.
public function handle($request, Closure $next, $guard = null)
{
if (Auth::guard($guard)->guest()) {
if ($guard === 'api') {
return response('Unauthorized.', 401);
} else {
return redirect()->guest('login');
}
}
return $next($request);
}
You can do this by extending the TokenGuard, with your custom logic. Or you can create a new Middleware, which asserts that user authenticated by API matches the passed user ID.
I just verified the kind of exception if is related with authentication and then the URL( as API guard use '/api' just verify it) and fire the response.
if($exception instanceof \Illuminate\Auth\AuthenticationException){
if($request->is('api/*')){
return response()->json([
'success' => false,
'message' => 'User not logged'
]);
}
}
I made the below change in app/Exceptions/Handler.php.
protected function unauthenticated($request, AuthenticationException $exception)
{
if ($request->expectsJson()) {
return response()->json(['error' => 'Not Authorized'], 404);
}
return redirect()->guest(route('login'));
}
Add use Illuminate\Auth\AuthenticationException in the document. Also, do not forget to add X-Requested-With:XMLHttpRequest to your request header. (Or Headers in postman)
return redirect()->guest(route('login')); is to redirect you to login page when you are not using the APIs.
I've got same login page for every CRM.
These are the steps:
Enter password and login
Send curl to CRM on crm.dev/api/auth/check with user data, which checks if user exists in CRM
CRM returns success if user exists, after this authenticates user via Auth::user('user_data_here') and redirects to main page of CRM
My problem is that auth doesn't work. And no user data is stored in session (because of previous problem).
CRM auth code:
public function checkUserExists(Request $request)
{
$this->redirectIfAuthorized();
$user = User::find($request->uid);
if ($user) {
return ['response' => 'LOGIN_SUCCESS'];
}
return ['response' => 'DB_ERROR'];
}
public function login(Request $request)
{
$this->validateLogin($request);
$user = User::find($request->uid);
$user->remember_token = $request->token;
if ($user->update()) {
Auth::login($user, true);
return redirect()->intended($this->redirectPath());
} else {
return redirect($this->redirectAfterLogout);
}
}
public function redirectIfAuthorized()
{
if (Auth::check()) {
return redirect($this->redirectTo);
}
}
Api route:
Route::group(['prefix' => 'auth'], function () {
Route::post('check', 'LoginController#checkUserExists');
Route::get('login', 'LoginController#login');
Route::get('logout', 'LoginController#logout');
});
And login page's logic for this CURL request
private function sendToken($action, $user, $token)
{
$query = DB::table('user_base')->join('bases', 'bases.id', '=', 'user_base.base_id')
->where('user_base.user_id', $user);
$result = $query->get();
foreach ($result as $row) {
$urlAPI = $row->url_api;
if ($urlAPI == 'http://appliance.dev/api/auth') {
$urlAPI .= '/check';
}
$rsp = $this->curl($urlAPI, array(
'apiKey' => $this->apiKey,
$action => true,
'uid' => $row->base_uid,
'token' => $token
));
}
}
I needed to use routing in web.php file instead of api.php