In my Symfony project I'm using UserInterface in my User entity to handle authentication. I also use EquatableInterface to check if user's email is changed while he's logged in.
public function isEqualTo(UserInterface $user)
{
if (!$user instanceof Account) {
return false;
}
if ($this->email !== $user->getEmail()) {
return false;
}
return true;
}
All works as expected, but when I change user's email in DB I'm not logged out, just not authenticated as you can see in the following screenshot.
So I would know how can I check in a controller if user is authenticated? And how can I force user to log out when isEqualTo returns false?
I found the solution and I want to share it if someone else have the same problem.
To check if user is authenticated, we need TokenInterface which is implemented by TokenStorage. Then we just need to call isAuthenticated() method.
$tokenInterface = $this->get('security.token_storage')->getToken();
$isAuthenticated = $tokenInterface->isAuthenticated()
Fast Method: see method getUser in Symfony\Bundle\FrameworkBundle\Controller at link. If you need this behavior somewhere in the service, then use the security.token_storage service as a dependency.
Try way method (symfony-like): you need use Symfony Security Voters
Related
I'm using laravel basic policy system to protect unauthorized user from update post. For Example User have Id 1 and In posts Table User_id is also 1.
Now in $this->authorize('update',$post); way I can pass only one variable $post to authenticate. while in can method I can also use $user variable $user->can('update',$post) for authorize.
Here is code:
In PostPolicy.php :
public function update(User $user, Post $post)
{
return $user->id === $post->user_id;
}
In AuthServiceProvider.php :
protected $policies = [
Post::class => PostPolicy::class
]
In Controller Authorize way :
public function update(Request $request, $id)
{
$post=Post::find(1);
$user=User::find(1);
$this->authorize('update',$post);
return 'Hello Everything Access For You ';
}
Using can method in Controller :
public function update(Request $request, $id)
{
$post=Post::find(1);
$user=User::find(1);
if($user->can('update',$post)){
return 'Your are allowed';
}
else
{
return 'Your are Not allowed';
}
}
Is I'm right for these two functions. Is there any Difference. Which method I have to use. Thanks in Advance.
If you are using any of authorize() or can(), the purpose is to validate if user is authorized to do certain tasks.
But :
In case of authorize(), if it fails(returns false from policy method), the authorize method will throw an Illuminate\Auth\Access\AuthorizationException, which the default Laravel exception handler will convert to an HTTP response with a 403
In case of can(), it like just a basic method to check if user is authorized or not and then you need to handle the rest on your own. Like what to do if its unauthorized.
Considering above factors, I would say $this->authorize('update',$post); is easier to be used in controller.
Check more about the same in documentation
Also you can do :
$request->user()->can() if you want to check authorization of current requesting user.
Update :
authorize() is designed to authorize current user who is logged in, where laravel passes current user automatically to policy.
Whereas you can use can on any user instance.
$request->user()->can() if you want to check authorization of current requesting user.
$user = $user::find($id); $user->can(...) if its any other user
$this->authorize() checks if the current user is authorized. $user->can() checks if the user in $user is authorized. Both rely on the same underlying policy to make the decision.
The main difference between the two is that $this->authorize() throws an exception if the current user isn't authorized (as it's intended for use within a controller), whereas $user->can() just returns true/false.
If you want a controller to act as if it's doing $this->authorize() for a different user than the current one, you can do this:
// where "123" is the user you want to check against
$user = App\User::find(123);
if(!$user->can('update', $post) {
throw new \Illuminate\Auth\Access\AuthorizationException;
}
That said, this is rarely what you want to do - it doesn't (usually) make much sense to determine if the current user can do something based on another user's permissions.
I'm currently adding Socialite to my website to allow users to log in from Facebook.
public function redirectToProviderFacebook() {
return Socialite::driver('facebook')->redirect();
}
public function handleProviderCallbackFacebook() {
$userSocial = Socialite::driver('facebook')->user();
$email = $userSocial->getEmail();
if (User::where('email', $email)->count() > 0) {
// log them in
Auth::login(User::where('email', $email)->first());
return redirect()->route('home')->with('info', "You are now signed in.");
} else {
// register an account and log them in
}
}
During normal user registration, I ask for three things: username, email and password. The username and email are things you cannot change on my site, ever, as their usernames are bound to many things.
The problem with logging in with Facebook is that I have to register new users in the callback function. Therefore, I can't ask them for what they want their usernames to be.
Is there a way I could perhaps prompt the user for their preferred username? Then do the redirect like this:
return Socialite::driver('facebook')->with('username', $request->username)->redirect();
Then retrieve that data to use it for auth registration in the callback function?
For some reason, Optional Parameters didn't work for me, so i ended up by using session to pass variables from redirect method to the callback method. it's not the best way to do it, but it does the trick.
public function redirectToFacebookProvider()
{
// save anything you will need later, for example an url to come back to
Session::put('url.intended', URL::previous());
return Socialite::driver('facebook')->redirect();
}
public function handleFacebookProviderCallback()
{
// handling....
$url = Session::get('url.intended', url('/'));
Session::forget('url.intended');
return redirect($url);
}
Obtained this answer from https://laracasts.com/discuss/channels/laravel/socialite-return-parameters-in-callback?page=0
And from Sending additional parameters to callback uri in socialite package for laravel
i am not sure about facebook, but for github its working fine. Try this:
public function socialLogin($loginFrom){
return Socialite::driver('github') >redirectUrl('http://your-domain.com/callback?data=123')->redirect();
}
on github app you need to put only: http://your-domain.com/callback
I understand that the auth functions allows a user to login etc, but I wanted a confirmation on what exactly was happening in the background.
My guess is that it's just a cookie that holds the login details, correct?
Or is it only storing the remember_token and then automatically comparing that with what is stored in the users table?
So if I wanted to create an account edit page. Would I have to do anything like comparing the auth id with the users table id that the e-mail matches up with? Or is it handling all that automatically?
Laravel Auth is nothing but its class where already all authentication methods or functions are written in laravel out of box.so you need not required to write all that function which is relating to user login.for example to check user we simply use
Auth::check();
but in laravel auth class they written like this
public function check()
{
return !is_null($this->user());
}
in the same way for login attempt we are passing parameter to attempt method .Here also laravel built in function is there
public function attempt(array $credentials = [], $remember = false, $login = true)
{
$this->fireAttemptEvent($credentials, $remember, $login);
$this->lastAttempted = $user = $this->provider->retrieveByCredentials($credentials);
// If an implementation of UserInterface was returned, we'll ask the provider
// to validate the user against the given credentials, and if they are in
// fact valid we'll log the users into the application and return true.
if ($this->hasValidCredentials($user, $credentials)) {
if ($login) {
$this->login($user, $remember);
}
return true;
}
return false;
}
Here you are passing all credentials in array and remember password and all
I don't know how to use AuthComponent then this is the way I do user authentication with multiple roles is as follows:
There is 3 roles: Administrators, Resales and Clients.. one controller for each one, for individual views, and this is my beforeFilter for each Role/Controller:
AdministratorsController:
function beforeFilter(){
if (!$this->isAuth('Administrator'))
$this->redirect('/');
}
AppController:
function isAuth($strRole = NULL){
$data = $this->Session->read('User');
if (!$this->Session->check('User') || (!is_null($strRole) && $data['Role']['nome'] != $strRole))
return false;
return true;
}
In UsersController I do only authentication checking if $this->Session->read('User') exists, if the user exists, he gets all info and put in Session like this: $this->Session->write('User', $user); assuming that $user is the find from Model with all user information.
the question is, will I have problems? is that "right"? do not know if I was clear, if missing information, ask..
You're replicating logic the framework already implements for you.
See http://book.cakephp.org/2.0/en/tutorials-and-examples/blog-auth-example/auth.html#authorization-who-s-allowed-to-access-what
Taken from that page (you should still read it..):
public function isAuthorized($user) {
// Admin can access every action
if (isset($user['role']) && $user['role'] === 'admin') {
return true;
}
// Default deny
return false;
}
The user data gets passed to it, no need to fetch the user data yourself.
And if you ever have to fetch the user data use $this->Auth->user():
// Some field
$this->Auth->user('someField');
// Whole data
$this->Auth->user();
If the session key ever changes for some reason all you direct calls to the Session->read('User') will be in trouble. A good and not so unlikely example here is when the application has to be extended with a 2nd auth adapter that is not using the session. Auth will know about the data, Session won't have it.
I am busy writing an API in Symfony2. One of the API functions is to return all the users (not uncommon). Obviously before I return a list of users I must ensure that a user is logged in and has at least ROLE_ADMIN before returning the users. Currently I am doing it like this:
public function getAllUsersAction()
{
$user = $this->getUser();
if ($user == null) die("Unauthorized");
$userRoles = $user->getRoles();
$bAuthorized = false;
foreach ($userRoles as $userRole)
if ($userRole->getRole() == "ROLE_ADMIN" || $userRole->getRole() == "ROLE_SUPER_ADMIN")
$bAuthorized = true;
if ($bAuthorized) return createJsonResponse($this->getDoctrine()->getRepository('PmbLicensingBundle:User')->findAll());
else die("Unauthorized");
}
My question is simply whether there is an easier way in Symfony to determine whether a user is logged in and has ROLE_ADMIN than the process that I am taking, as it seems to be quite lumbersome.
Try:
if (!$this->get('security.context')->isGranted('ROLE_ADMIN')) die('Nope Nope Nope');
Or of course you can follow #artworkad's advice and setup a firewall which would prevent the action from ever being called in the first place.
The authentication logic does not belong into the controller's action. Your software has to check if the user is logged in before the action is accessed redirecting the response if authentication fails or the given roles are not sufficient.
FosUserBundle is a great tool that does a lot of security and authentication for you. On SO there are already answers how to configure FosUserBundle to work with REST e.g.
How to restfully login, Symfony2 Security, FOSUserBundle, FOSRestBundle?