I have tried to used easyAdmin3 for making an admin account quickly, but how do you make a proper impersonate user action ?
I have tried a lot of things but the best option are made custom action so this link appear in page but it's don't works properly...
Impersonate works but on only page linked in url (impersonate has stopped if page change) and User don't change in Symfony Toolbar...
My custom Action :
public function configureActions(Actions $actions): Actions
{
$impersonate = Action::new('impersonate', 'Impersonate')
->linkToRoute('web_account_index', function (User $entity) {
return [
'id' => $entity->getId(),
'?_switch_user' => $entity->getEmail()
];
})
;
return parent::configureActions($actions)
->add(Crud::PAGE_INDEX, Action::DETAIL)
->add(Crud::PAGE_INDEX, $impersonate)
;
}
Result :
Dashboard link for each user
After click on impersonate, I have this url :
https://blog-community.wip/account/7?eaContext=37a8719&?_switch_user=user7#user.com
Content are ok (page account for user 7) but Symfony Profiler show User admin instead of impersonated User :
Symfony profiler user logged
Change page exit impersonate...
Real Symfony impersonate keep impersonation even if page changes because profiler user logged are different Symfony profiler user logged with impersonate directly in url
documentation not refer this functionality, EasyAdmin's Github issues too ans this website too.
Thanks for help
I am not a big fan of using hardcoded rules, so injected the UrlGenerator to my CrudController:
$impersonate = Action::new('impersonate', 'Impersonate')
->linkToUrl(function (User $user): string {
return $this->urlGenerator->generate(
Routes::DASHBOARD,
['_switch_user' => $user->getEmail()],
UrlGeneratorInterface::ABSOLUTE_URL
);
});
Solved !
EasyAdmin add automatically some parameters in url so "?" are already here but I added it too in my custom action...
Example :
https://blog-community.wip/account/7?eaContext=37a8719&?_switch_user=user7#user.com
public function configureActions(Actions $actions): Actions
{
$impersonate = Action::new('impersonate', 'Impersonate')
->linkToRoute('web_account_index', function (User $entity) {
return [
'id' => $entity->getId(),
'_switch_user' => $entity->getEmail()
// removed ? before _switch_user
];
})
;
return parent::configureActions($actions)
->add(Crud::PAGE_INDEX, Action::DETAIL)
->add(Crud::PAGE_INDEX, $impersonate)
;
}
For EasyAdmin 3.2.x the prior solution stopped working. This is working for me now:
public function configureActions(Actions $actions): Actions
{
$impersonate = Action::new('impersonate', false, 'fa fa-fw fa-user-lock')
//changed from linkToRoute to linkToUrl. note that linkToUrl has only one parameter.
//"admin/.. can be adjusted to another URL"
->linkToUrl(function (User $entity) {
return 'admin/?_switch_user='.$entity->getUsername();
})
;
$actions = parent::configureActions($actions);
$actions->add(Crud::PAGE_INDEX, $impersonate);
return $actions;
}
Related
I am creating a small blog-esque site. This site has basically 3 permission levels: Admin (can edit/remove any post AND create a user), a user (can upload posts and pictures) and a guest (no account needed, can just browse the posts).
I am using Laravel 5.5 to create this site.
When someone logs in, after being authenticated, I store their username and user type (admin/user) in a session and after login, they are redirected to their respective pages, as shown in the below code.
I overrided the 'authenticated' method in the AuthenticatesUsers trait:
LoginController.php
protected function authenticated(Request $request, $user)
{
$type = $user->toArray()['type'];//get user type (admin/user)
$username = $user->toArray()['username'];
$request->session()->put('type', $type);
$request->session()->put('username', $username);
if ( $type == 'admin' ) {
return redirect()->route('admin_home');
}
return redirect()->route('user_home');
}
The above code works and my user is redirected upon successful login.
However, if my user accesses the site home (localhost:8000/) I want the user to see the admin home page or user home page (localhost:8000/ just shows the homepage for a not logged in guest)
I did that using the following codes:
Web.php
Route::get('/', 'ContentController#publicHome');
Route::middleware('auth')->group(function(){
Route::get('/user/home', 'ContentController#userHome')->name('user_home');
Route::get('/admin/home', 'ContentController#adminHome')->name('admin_home');
});
Filtering whether user is logged in or just a guest:
ContentController - publicHome function
public function publicHome(Request $request){
$data = [];
$data['home'] = 1;
if($request->session()->has('type')){
switch ($request->session()->pull('type')){
case 'admin':
return redirect()->route('admin_home');
case 'user':
return redirect()->route('user_home');
}
}
return view('public.home', $data);
}
ContentController - userHome function
public function userHome(Request $request){
$data = [];
$data['username'] = $this->getUsername($request);
$data['type'] = $this->getUserType($request);
// dd($data); explanation for this line below
return view('user.home', $data);
}
ContentController - adminHome function
public function adminHome(Request $request){
$data = [];
$data['username'] = $this->getUsername($request);
$data['type'] = $this->getUserType($request);
//dd($data);
return view('admin.home', $data);
}
ContentController - getUsername & getUserType functions
public function getUsername(Request $request){
return $request->session()->has('username') ? $request->session()->pull('username') : 'username not set';
}
public function getUserType(Request $request){
return $request->session()->has('type') ? $request->session()->pull('type') : 'user type not set';
}
I used the dump and die function to see the $data[] array before loading the view
Right after successful login:
array:2 [▼
"username" => "testAdmin"
"type" => "admin"
] //works correctly, session variables seem to be set
So when I type in localhost:8000/ I expect to be redirected to /admin/home (or /user/home depending on login) but I just get sent to localhost:8000/ as if I am not logged in. So now when I manually type in /admin/home I get the following dump and die output:
array:2 [▼
"username" => "username not set"
"type" => "user type not set"
]
If you are using $request->session()->pull('username') it fetches the data i.e. username from session and deletes it at the same time.
Instead, you can use laravel's helper method session() to get data without deleting it. So now you can use session('username') to get the username.
For more info refer : https://laravel.com/docs/5.5/session
Some Suggestions:
You could have used laravel's internal Auth library to build the login system which already has lot many features you don't need to code again. https://laravel.com/docs/5.5/authentication
You can also have multi-user authentication (admin & regular user). Refer this link if you want to implement so: https://scotch.io/tutorials/user-authorization-in-laravel-54-with-spatie-laravel-permission
I have a cart products page, if a person clicks on a product add to cart button they will be redirected to the login page.
After a successful login, I need to send the user back to same products page again.
I used the following way in login controller.
But it's not actually working the way i want.
Means it redirect to the index page again, I have used the return redirect()->back(); also..but doesn't solve the problem
if (auth()->attempt(array('email' => $request->input('email'),
'password' => $request->input('password')))){
if(Auth::user()->name == 'Admin'){
return redirect()->to('home');
}
else{
// return redirect()->back();
return redirect()->intended('/');
}
}
How to solve the issue?
In this case back() and intended() will not work.
You can save last product page to the session. Very simplified example:
session(['last_product_page_id' => $product->id]);
And then use this data to redirect user after login:
if (session()->has('last_product_page_id')) {
return redirect()->route('product', session('last_product_page_id'));
}
May be Mezenin Solution is right But i solve it other way. (I took the concept from above solution)
As I'm using Laravel 5.4 ..I'm giving solution based on recent file directory..
I have changed the showLoginFrom controller which is inside AuthenticateUsers trait to this :
public function showLoginForm()
{
Session::put('url.intended',URL::previous());
return view('auth.login');
}
And inside my login controller I have changed :
if (auth()->attempt(array('email' => $request->input('email'),
'password' => $request->input('password')))){
if(Auth::user()->name == 'Admin'){
return redirect()->to('home');
}
else{
return Redirect::to(Session::get('url.intended'));
}
}
And that's how when a user logged in, he will be automatically redirected to the previous page..
I am using EasyAdminBundle in Symfony 3.1.9.
I managed to customize actions in lists, as well explained here:
https://github.com/javiereguiluz/EasyAdminBundle/blob/master/Resources/doc/tutorials/custom-actions.md
But I didn't found any documentation to add custom entity action in forms.
My goal is to add, near the "Save", "Delete" and "Back to list" buttons, a button which saves current entity and redirect to the current edit form (not return to list as default behavior).
entity form edit actions
Thank you in advance
I've probalby made something dirty but it works.
I've overwrited the editAction :
public function editAction()
{
$response = parent::editAction();
if ($response instanceof RedirectResponse) {
$request = Request::createFromGlobals();
return $this->redirect(urldecode($request->request->get('referer')));
}
return $response;
}
The method $this->getCurrentEntity() were unknown.
I've also overwrited the edit.html.twig to add another button next to the basic one with jQuery:
var cloned = $( "button.action-save" );
var clone = cloned.clone();
cloned.after(clone);
clone.addClass('action-save-stay')
clone.html('<i class="fa fa-save"></i>{{ 'action.save_stay'|trans }}');
$('.action-save-stay').bind('click', function(e) {
e.preventDefault();
$('input[name="referer"]').val(window.location.href);
$('form').submit();
});
It changes the hidden input named referer.
By default, easyadmin redirects to the referer contained in the query string.
Thank you so much to put me in the right direction.
Olivier If your goal is just to redirect back to edit action of same entity form instead of redirection to list action. It's quite simple like this. Let's assume You are on new action of Product entity and want back to edit after saving new product.
public function newProductAction()
{
$response = parent::newAction();
if ($response instanceof RedirectResponse) {
$entity = $this->getCurrentEntity();
return $this->redirectToRoute('admin', [
'entity' => 'Product',
'action' => 'edit',
'id' => $entity->getId()
'menuIndex' => 1
]);
}
return $response;
}
Here 2 points keep in mind menuIndex is for active menu class so, it may be changed as per your sequence. And redirect route 'admin' should be your easyadmin backend route.
I worte a plugin IdentityPlugin to check login status of a user. If the user session gets logout, I want to redirect them to login page. My code is given below.
public function checkLogin($logout=true,$next='login'){
if($this->auth->hasIdentity()){
}elseif ($logout){
return $this->getController()->redirect()->toRoute($next);
}
}
in my controller
// Check identity, if not found- redirect to login
$this->IdentityPlugin()->checkLogin();
Any idea?
You're returning a response to the controller but you're not returning it from the controller itself.
For example you could try this is your controller:
$check = $this->IdentityPlugin()->checkLogin();
if ($check instanceof Response) {
return $check;
}
A more complex solution could be to stop the propagation of the controller's MvcEvent, set whatever response you want, and return directly.
Hi you need to config you plugin in factories in module.config.php and pass service manager to __construct, like below:
'controller_plugins' => array(
'factories' => array(
'CheckLogin' => function($sm){
$checkLogin = new Application\Plugin\CheckLogin($sm);
return $checkLogin;
},
),
),
Then in your plugin you will be able to call all you need using service Manager:
namespace Application\Plugin;
use Zend\Mvc\Controller\Plugin\AbstractPlugin;
class CheckLogin extends AbstractPlugin
{
public function __construct($sm)
{
$auth = $sm->getServiceLocator()->get("Zend\Authentication\AuthenticationService");
if( !$auth->hasIdentity()){
$sm->getController()->plugin('redirect')->toUrl('/login');
}
}
}
I have two controllers, homepage and Security.
In the homepage, I am displaying one view and in the security, I am doing some things, and one of them is the email address validation.
What I would like is that when the email validation code is not valid, display the homepage with a flash message. For that, I will have to render the indexAction of the HomepageController, from the Security controller, by giving him as parameter the flash message.
How can this be done? Can I render a route or an action from another controleller?
Thank you in advance.
I believe the checking should not be done in the Security controller. Right place in my opinion is a separate validator service or right in the entity which uses the email address.
But to your question, you can call another controller's action with $this->forward() method:
public function indexAction($name)
{
$response = $this->forward('AcmeHelloBundle:Hello:fancy', array(
'name' => $name,
'color' => 'green',
));
return $response;
}
The sample comes from symfony2 documentation on: http://symfony.com/doc/2.0/book/controller.html#forwarding
I have found the solution, simply use the forward function by specifying the controller and the action nanme:
return $this->forward('MerrinMainBundle:Homepage:Index', array('flash_message'=>$flash_message));
redirectToRoute : Just a recap with current symfony versions (as of 2016/11/25 with v2.3+)
public function genericAction(Request $request)
{
if ($this->evalSomething())
{
$request->getSession()->getFlashBag()
->add('warning', 'some.flash.message');
$response = $this->redirectToRoute('app_index', [
'flash_message' => $request->getSession()->getFlashBag(),
]);
} else {
//... other logic
}
return $response;
}