I created a custom guard with a validate method
public function validate(array $credentials = [])
{
if (!isset($credentials['login']) || empty($credentials['login']) || !isset($credentials['password']) || empty($credentials['password'])) {
return false;
}
$user = $this->provider->retrieveById($credentials['login']);
if (!isset($user)) {
return false;
}
if ($this->provider->validateCredentials($user, $credentials)) {
$this->setUser($user);
return true;
} else {
return false;
}
}
. I also created a custom authorization provider with a validateCredentials method
public function validateCredentials(Authenticatable $user, array $credentials)
{
if ((strcmp($credentials['login'], $this->retrieveByCredentials($credentials)->login) === 0)) {
if (Hash::check($credentials['password'], $user->getAuthPassword())) {
return true;
}
}
return false;
}
. added them to (providers file, code) and to the config/auth
'defaults' => [
'guard' => 'custom',
'passwords' => 'users',
],
'guards' => [
'custom' => [
'driver' => 'custom',
'provider' => 'custom',
]
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\User::class,
],
'custom' => [
'driver' => 'custom'
],
],
And in AuthServiceProvider:
public function boot()
{
$this->registerPolicies();
Auth::provider('custom', function ($app, array $config) {
return new CustomerAuthProvider($app->make('App\Models\User'));
});
Auth::extend('custom', function ($app, $name, array $config) {
return new CustomAuthGuard(Auth::createUserProvider($config['provider']), $app->make('request'));
});
}
.
In the login controller I check the entered data
if (Auth::validate($attemptData)) {
return response()->redirectToIntended('cabinet');
}
, but for some reason no redirect or authorization occurs.
But if I do this
if (Auth::validate($attemptData)) {
$user = Auth::user();
$id = Auth::id();
dd($user);
return response()->redirectToIntended('cabinet');
}
, then the correct user will be inside it
Related
Why does this error appears when the guard exists in auth.php
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'manager' => [
'driver' => 'jwt',
'provider' => 'managers',
],
'admin' => [
'driver' => 'jwt',
'provider' => 'admins',
],
],
And the providers also sets with right format. In the controller the register function is down below:
public function register(Request $request)
{
$validator = Validator::make($request->all(), [
'username' => 'required|string|max:255',
'password' => 'required|string|min:6',
]);
if ($validator->fails()) {
return response()->json($validator->errors(), 422);
}
$user = new Manager();
$user->username = $request->username;
$user->password = bcrypt($request->password);
$user->save();
$token = JWTAuth::guard('manager')->attempt($request->only('username', 'password'));
return response()->json(compact('user', 'token'));
}
The JWTMiddleware
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class JWTAuth
{
public function handle($request, Closure $next, $guard)
{
try {
$user = JWTAuth::parseToken()->authenticate($guard);
if (!$user) {
throw new \Exception('User not found');
}
} catch (\Exception $e) {
return response()->json(['error' => 'Unauthorized'], 401);
}
return $next($request);
}
}
In kernel.php I have included these inside aliases array:
'jwt.manager' => \App\Http\Middleware\JWTManagerMiddleware::class,
'jwt.admin' => \App\Http\Middleware\JWTAdminMiddleware::class,
'jwt.auth' => \App\Http\Middleware\JWTAuth::class,
What am I doing wrong and how can I solve this?
i'm working on a graphql API using Laravel GraphQL.
As shown in the documentation "Privacy" section, it should be possible to add callback function to a GraphQLType fields privacy attribute. The field is supposed to return null, when the callback returns false.
Similar to the example in the laravel graphql Docs, i've added a privacy callback like so:
public function fields(): array {
return [
'email' => [
'type' => Type::string(),
'description' => 'The email of user',
'privacy' => function(User $user): bool {
return $user->isMe();
}
],
];
}
It appears to me, that this callback function never gets called.
I read something about a possible requirement, that i should resolve my query using the $getSelectFields function to query the $fields manually $with the selected columns. But unfortunately the $select
public function resolve($root, $args, $context, ResolveInfo $info, Closure $getSelectFields) {
$fields = $getSelectFields();
$with = $fields->getRelations(); // empty array
$select = $fields->getSelect(); // empty array
return User::select($select)->with($with)->get();
}
In my case this does not make any difference.
In my query resolver i do as following:
public function resolve($root, $args, $context, ResolveInfo $info, Closure $getSelectFields) {
/** #var SelectFields $fields */
$fields = $getSelectFields();
$select = $fields->getSelect();
$with = $fields->getRelations();
exit(var_dump($fields)); // #RESULT
}
My result looks like this:
object(Rebing\\GraphQL\\Support\\SelectFields)#4668 (2) {
[\"select\":\"Rebing\\GraphQL\\Support\\SelectFields\":private]=> array(0) {}
[\"relations\":\"Rebing\\GraphQL\\Support\\SelectFields\":private]=> array(0) {}
}
So my question is: "How do i use the privacy attribute callback in Laravel Rebing GraphQL?"
I'm using:
PHP 7.3
Laravel 7.17
Rebing Graphql Laravel 5.1
Thanks in advance,
greets Jules
Some more Details about my use case
EpUser.php
namespace App\GraphQL\Type;
use App\CommunityImage;
use App\User;
use Carbon\Carbon;
use GraphQL\Type\Definition\Type;
use Illuminate\Support\Facades\Auth;
use Rebing\GraphQL\Support\Facades\GraphQL;
use Rebing\GraphQL\Support\Type as GraphQLType;
class EpUser extends GraphQLType {
protected $attributes = [
'name' => 'EpUser',
'description' => 'A type',
'model' => User::class,
];
public function fields(): array {
return [
'id' => [
'type' => Type::nonNull(Type::int()),
'description' => 'The id of the user',
'privacy' => function(User $user): bool {
return false;
}
],
'email' => [
'type' => Type::string(),
'description' => 'The email of user',
'privacy' => function(User $user): bool {
return $user->isMe();
}
],
'firstName' => [
'type' => Type::string(),
'description' => 'The firstName of user'
],
'lastName' => [
'type' => Type::string(),
'description' => 'The lastName of user'
],
'fullName' => [
'type' => Type::string(),
'description' => 'The fullName of user',
'selectable' => false,
'resolve' => function(User $user) {
return $user->firstName . " " . $user->lastName;
}
],
'gender' => [
'type' => Type::string(),
'description' => 'The gender of the user'
],
'isOnline' => [
'type' => Type::boolean(),
'description' => '',
'selectable' => false,
'resolve' => function(User $user, $args) {
return $user->isOnline();
}
]
];
}
[...]
And this is the UsersQuery which should respond with a user pagination object, that contains an array of users with a privacy attribute:
UsersQuery.php
namespace App\GraphQL\Query;
use App\Artist;
use App\FilePath;
use Closure;
use GraphQL\Type\Definition\Type;
use Rebing\GraphQL\Support\Query;
use Illuminate\Support\Facades\Auth;
use GraphQL\Type\Definition\ResolveInfo;
use Rebing\GraphQL\Support\Facades\GraphQL;
use App\User;
class UsersQuery extends Query {
protected $attributes = [
'name' => 'UsersQuery',
'description' => 'A query',
'model' => User::class,
];
public function type(): Type {
return GraphQL::type('userPagination');
}
public function authorize($root, array $args, $ctx, ResolveInfo $resolveInfo = NULL, $getSelectFields = NULL): bool {
return Auth::check();
}
public function args(): array {
return [
'id' => [
'type' => Type::int(),
'description' => 'The id of the user'
],
'slug' => [
'type' => Type::string(),
'description' => 'The slug of the user'
],
'pagination' => [
'type' => Type::nonNull(GraphQL::type('paginationInput')),
'description' => 'The pagination of the users to query',
'rules' => 'required',
],
'search' => [
'type' => Type::string(),
'description' => 'a string to search for users'
],
'roles' => [
'type' => Type::listOf(Type::string()),
'description' => 'The roles of the user',
'rules' => 'sometimes|required|array|in:user,developer,administrator'
]
];
}
public function resolve($root, $args, $context, ResolveInfo $info, Closure $getSelectFields) {
if(isset($args['id']) || isset($args['slug'])) {
if(isset($args['slug'])) {
$user = User::where('slug', $args['slug'])->first();
} else {
$user = User::find($args['id']);
}
return [
'items' => $args['pagination']['limit'] > 0 && $user ? [$user] : NULL,
'itemTotal' => $user ? 1 : 0
];
}
$sortBy = $args['pagination']['sortBy'] ?? 'id';
$sortByDesc = isset($args['pagination']['sortByDesc']) ? $args['pagination']['sortByDesc'] : true;
$sortByType = $sortByDesc ? 'desc' : 'asc';
$search = false;
if(isset($args['search']) && $args['search']) {
$search = true;
$query = User::search($args['search']);
} else {
$query = User::query();
}
if(!empty($sortBy)) {
$query->orderBy($sortBy, $sortByType);
}
// Todo: eloquent search can't serach for whereHas
if(isset($args['roles']) && !$search) {
if(is_array($args['roles'])) {
foreach($args['roles'] as &$role) {
$query->whereHas('roles',
function($q) use ($role) {
$q->where('name', $role);
});
}
} else {
$query->whereHas('roles',
function($q) use ($args) {
$q->where('name', $args['roles']);
});
}
}
if($search) {
$userPaginationObject = [
'itemTotal' => $query->count(),
'items' => $query->getWithLimitAndOffset($args['pagination']['limit'],
$args['pagination']['offset'])
];
} else {
$userPaginationObject = [
'itemTotal' => $query->count(),
'items' => $query->limit($args['pagination']['limit'])->offset($args['pagination']['offset'])->get()
];
}
return $userPaginationObject;
}
}
So I have login page that the admin or users can use to login. It went well until such time we have some changes and added the admin side. I only uses 1 table for all user types and I have role_id column that defines the users role. So if the role_id is 0, I have to redirect them to the dashboard page whereas if it's a user, will redirect to user page. I have tried as what is suggested in the internet but can't make it work. Here's what I have:
class UserLoginController extends Controller
{
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('guest:user')->except('logout');
}
public function showLoginForm()
{
return view('auth.user-login');
}
public function login(UserLoginRequest $request)
{
// Attempt to log the user in
if (Auth::guard('user')->attempt(['email' => $request->email, 'password' => $request->password])) {
// if successful, then redirect to their intended location
return redirect()->intended(route('user.dashboard'));
}
// if unsuccessful, then redirect back to the login with the form data
if (! User::where('email', $request->email)->where('password', bcrypt($request->password))->first() ) {
return redirect()->back()
->withInput($request->only('email'))
->withErrors(['status' => 'Incorrect username or password.']);
}
}
public function logout()
{
Auth::guard('user')->logout();
return redirect()->route('user.login');
}
}
config/auth
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
'hash' => false,
],
'guest' => [
'driver' => 'session',
'provider' => 'guests',
],
'user' => [
'driver' => 'session',
'provider' => 'users',
],
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\User::class,
],
'guests' => [
'driver' => 'eloquent',
'model' => App\Guest::class,
],
],
MODEL
<?php
namespace App\Models;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
protected $guard = 'user';
protected $fillable = [
//fillable cols
];
//change role id data type to integer
protected $casts = [
'role_id' => 'integer',
];
}
Now, where should I insert the condition to check if it's an admin or a user?
You can try it
public function login(UserLoginRequest $request)
{
// Attempt to log the user in
if (!Auth::guard('user')->attempt(['email' => $request->email, 'password' => $request->password])) {
return redirect()->back()
->withInput($request->only('email'))
->withErrors(['status' => 'Incorrect username or password.']);
}
$user = Auth::guard('user')->user();
if ($user->role_id === 0) {
return redirect()->route('user.dashboard');
}
return redirect()->route('user.page');
}
Check below i have edited the method of login:
public function login(UserLoginRequest $request)
{
// Attempt to log the user in
if (Auth::guard('user')->attempt(['email' => $request->email, 'password' => $request->password])) {
// Over here this condition will be true when user is successfully login
// Below is the user data i have printed in that you can check the role of user which is login.
$user = Auth::user();
print_r($user);
}
// if unsuccessful, then redirect back to the login with the form data
if (! User::where('email', $request->email)->where('password', bcrypt($request->password))->first() ) {
return redirect()->back()
->withInput($request->only('email'))
->withErrors(['status' => 'Incorrect username or password.']);
}
}
I use Session in laravel, but when I get session in controller, it's not work.
web.php
Route::get('locale/{locale}',function ($locale){
//Session::put('locale',$locale);
session(['locale' => $locale]);
Session::save();
return redirect()->back();
});
Localization.php
public function handle($request, Closure $next)
{
if(\Session::has('locale')){
\App::setLocale(\Session::get('locale'));
session(['locale' => \Session::get('locale')]);
\Session::save();
}
return $next($request);
}
Kernel.php
protected $middleware = [
\App\Http\Middleware\CheckForMaintenanceMode::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
\App\Http\Middleware\TrustProxies::class,
];
/**
* The application's route middleware groups.
*
* #var array
*/
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\App\Http\Middleware\Localization::class,
],
'api' => [
\App\Http\Middleware\EventLogMiddle::class,
'throttle:600,1',
'bindings',
],
];
MachCtrl.php (extends Controller)
public function index()
{
$lang = session('locale');
$config = json_encode([
"table" => "Machine_list",
"title" => "machine list",
"rows" => 20,
"column" => [
"Machine_id", "VM_name", "Machine_location","IP_address",
"Network_status", "Current_status"
],
"CUDP" => "0111",
"CreateRoute" => route('machine.create'),
"DeleteRoute" => route('machine.destroy'),
"UpdateRoute" => route('machine.editInfo'),
"locale" => $lang,
]);
return view('table.show')->with(['config' => $config, 'lang' =>
$lang]);
}
I save Session in router and middlemare, it's not work.
But when I put Session in Controller, it's work. As following code:
public function index()
{
session(['locale' => 'en']);
$lang = session('locale');
$config = json_encode([
"table" => "Machine_list",
"title" => "machine list",
"rows" => 20,
"column" => [
"Machine_id", "VM_name", "Machine_location","IP_address",
"Network_status", "Current_status"
],
"CUDP" => "0111",
"CreateRoute" => route('machine.create'),
"DeleteRoute" => route('machine.destroy'),
"UpdateRoute" => route('machine.editInfo'),
"locale" => $lang,
]);
return view('table.show')->with(['config' => $config, 'lang' =>
$lang]);
}
I really want to know what happen in my project.
Thanks.
Edit:
I use dd(session()) in my code:
-web.php
Route::get('locale/{locale}',function ($locale){
Session::put('locale',$locale);
Session::save();
dd(session());
return redirect()->back();
});
Result:
-Localization.php
public function handle($request, Closure $next)
{
if(\Session::has('locale')){
\App::setLocale(\Session::get('locale'));
session(['locale' => \Session::get('locale')]);
//dd(session());
\Session::save();
}
return $next($request);
}
Result:
-MachCtrl.php
public function index()
{
dd(session());
$lang = session('locale');
$config = json_encode([
"table" => "Machine_list",
"title" => "machine list",
"rows" => 20,
"column" => [
"Machine_id", "VM_name", "Machine_location","IP_address",
"Network_status", "Current_status"
],
"CUDP" => "0111",
"CreateRoute" => route('machine.create'),
"DeleteRoute" => route('machine.destroy'),
"UpdateRoute" => route('machine.editInfo'),
"locale" => $lang,
]);
return view('table.show')->with(['config' => $config, 'lang' =>
$lang]);
}
Result:
Try using a different session driver to round down your issue a little bit.
EDIT: Sorry I can't comment yet, <50rep :(
I checked my working code. I set the whole cycle as:
Language middleware:
class Language
{
protected $app;
public function __construct(Application $app, Request $request) {
$this->app = $app;
}
public function handle($request, Closure $next)
{
$this->app->setLocale(session('user_locale', config('app.locale')));
return $next($request);
}
}
In my middleware Kernel.php:
protected $middlewareGroups = [
'web' => [
\Illuminate\Session\Middleware\StartSession::class,
//...
\App\Http\Middleware\Language::class,
]
];
And in route:
Route::get('locale/{locale}',function ($locale){
session(['user_locale' => $locale]);
});
I have managed to create jwtauth to connect my mobile app to octobercms backend
from this reference
but the last_login field is always empty, I believe this is not set by default.
this is authenticated function that I have
use Tymon\JWTAuth\JWTAuth;
public function __construct(JWTAuth $auth)
{
$this->auth = $auth;
}
public function authenticate(Request $request)
{
try {
if (! $token = $this->auth->attempt($request->only('email', 'password'))) {
return response()->json([
'errors' => [
'root' => 'Could not sign you in with those details.',
],
], 401);
}
} catch (JWTException $e) {
return response()->json([
'errors' => [
'root' => 'Failed.',
],
], $e->getStatusCode());
}
return response()->json([
'data' => $request->user(),
'meta' => [
'token' => $token,
],
]);
}
it's called by this route.php from jwtauth folder
Route::group(['prefix' => 'api'], function () {
Route::post('auth/login','Autumn\JWTAuth\Http\Controllers\AuthController#authenticate');
Route::post('auth/register', 'Autumn\JWTAuth\Http\Controllers\AuthController#register');
Route::post('auth/logout', 'Autumn\JWTAuth\Http\Controllers\AuthController#logout');
Route::group(['middleware' => 'jwt.auth'], function () {
Route::get('auth/me', 'Autumn\JWTAuth\Http\Controllers\AuthController#user');
});
how do we set user last_login timestamp?
I hope my question is clear to understand.
added plugin.php where i extended user plugin as requested by #HardikSatasiya since i got exception implementing his suggestion
use System\Classes\PluginBase;
use Rainlab\User\Controllers\Users as UsersController;
use Rainlab\User\Models\User as UserModels;
use Event;
class Plugin extends PluginBase
{
public function registerComponents()
{
}
public function registerSettings()
{
}
public function boot()
{
UserModels::extend(function($model){
$model->bindEvent('model.beforeSave',function() use ($model) {
$users = \BackendAuth::getUser();
$model->backend_users_id = $users->id;
//above line result exception when calling method as #HardikSatasiya suggested
if(!empty($model->avatar)){
$model->image_path = $model->avatar->getPath();
}
if(!empty($model->groups)){
$model->membership = $model->groups[0]['name'];
}
});
$model->addJsonable('users_detail','membership');
});
UsersController::extendFormFields(function($form,$model,$context){
$form->addTabFields([
'users_detail[0][gender]' => [
'label' => 'Jenis Kelamin',
'span' => 'left',
'tab' => 'User Profile',
'type' => 'radio',
'options' => [
'Pria' => 'Pria',
'Wanita' => 'Wanita'
]
],
'users_detail[0][ttl]' => [
'label' => 'Tempat/Tanggal Lahir',
'type' => 'text',
'span' => 'left',
'tab' => 'User Profile'
],
]);
});
}
i add additional fields to user table by this separate plugin..
Ok, may be because internal hooks are not called when this plugin externally logsin user.
May be we need to call it manually, this code snippet can do it, just put given code after successful login.
// this will fire hooks and update `last_login`
// get authenticated user from the jwt authmanager
$user = $this->auth->authenticate($token);
$user->afterLogin();
Added in your code below.
public function authenticate(Request $request)
{
try {
if (! $token = $this->auth->attempt($request->only('email', 'password'))) {
return response()->json([
'errors' => [
'root' => 'Could not sign you in with those details.',
],
], 401);
}
} catch (JWTException $e) {
return response()->json([
'errors' => [
'root' => 'Failed.',
],
], $e->getStatusCode());
}
// this will fire hooks and update `last_login`
// get authenticated user from the jwt authmanager
$user = $this->auth->authenticate($token);
$user->afterLogin();
// ^ this code
return response()->json([
'data' => $request->user(),
'meta' => [
'token' => $token,
],
]);
}
this snippet will update last_login as expected. i did not test it but it will work as it should.
if any doubt or problem please comment.