I want to access to profile of the current user across the application (read/write). The user profile is an in instance of User model. Is it possible to store it on session as a service? If not, what is best practice?
Here is my login code. (ajax-based login)
function loginAction()
{
$this->view->disable();
{
$request = (array)$this->request->getJsonRawBody();
$user = User::findFirstByUsername($request['username']);
if (password_verify($request['password'], $user->password)) {
$userModel = User::findFirst('username="'.$request['username'].'"');
$this->getDI()['session']->set('auth', $user->id);
$this->user = $user;
jsonResponse($user);
} else {
http_response_code(401);
jsonResponse(['message' => 'invalid']);
}
}
}
There is several ways to achieve that. Let me share with you the one I've used in my own project...
First I've created a Component to deal with authentication related stuff such as checking the current session status (guest, user, admin), storing the current user specs, authentication procedures, etc.
namespace MyApp\Components;
use Phalcon\Mvc\User\Component as PhComponent;
class Authentication extends PhComponent
{
// ...
}
Then, I've registered this component in the main App's DI container:
$di->setShared('authentication', 'MyApp\Components\Authentication');
So I can use from my controllers, views, etc. Like:
function homeAction()
{
//...
if($this->authentication->isGuest()) {
//...
}
Finally to store data using the session. Phalcon provide a persistent session bag that you can use to easily store a serialized version of the model in the current session:
class Authentication extends PhComponent
{
// ...
function authenticate($username, $password)
{
// ... Authentication logic
if($validCredentials) {
$this->persistent->currentUser = $userModel;
}
// ...
}
}
Related
I’m just learning OOP Php, I understand the basic principles of OOP programming, and trying to do exercises. I wanna do a simple messaging application, where users can message each other. Like email, but in a closed system.
My idea is when an user logs in, i create an user object that contains the function that an user can do and if an admin logs in i create an admin object that extends the user class with added admin functions.
My question is Can I check in other class if the object is an admin or an user class without injecting in the classes or create the objects inside the checking class. Like this:
class Checker{
// some variables
public function isAdmin($object ){
if($object istanceof Admin){
return 1;
} else{
return 0;
}
}
}
IMO using reflection and introspection for non-debug purposes is an anti-practice.
PHP 5 Reflection API performance
Do it like this:
class User implements SystemUserInterface
{
public function isAdmin()
{
return false;
}
}
class Admin extends User
{
public function isAdmin()
{
return true;
}
// other stuff that only admin can do..
}
function checkUser($user)
{
echo "You have created ".($user->isAdmin()? "admin":"regular")." user";
}
I have two entites Person and Nursery and a ManyToMany association between them.
A user can have the role ROLE_MANAGER and be a manager for several nurseries.
For that in every action on his dashboard I need to verify if he's linked to the nursery if I don't do it he can modify the nursery slug in the url and have access to a nursery that he is not linked with.
Is there a way to check that on every action in the nursery manager dashboard without copy/paste a verification code in every action ?
As I understood Symfony Events (or Voters ?) can do that but I've never used them before ...
EDIT : Maybe it's easier to understand with a little bit of code !
So my nursery dashboard function is :
public function dashboardAction($nursery_slug)
{
//$currentUser = $this->get('security.token_storage')->getToken()->getUser();
$nurseryRepo = $this->getDoctrine()->getRepository('VSCrmBundle:Nursery');
$nursery = $nurseryRepo->findOneBy(array('slug' => $nursery_slug));
// Sometimes may help
if(!$nursery)
{
throw $this->createNotFoundException("The nursery has not been found or you are not allowed to access it.");
}
return $this->render("VSCrmBundle:Manager:dashboard.html.twig", array(
'nursery' => $nursery
));
}
To protect this dashboard I need to verify if the current user is linked to the nursery, somethink like :
$verification = $nurseryRepo->findOneBy(array('person' => $currentUser));
if(!$verification){throw accessDeniedException();}
But at the moment I'm obliged to do this test on every action in the manager dashboard ....
There are two things you need to implement to make this work smoothly.
First off, you need a NurseryVoter: http://symfony.com/doc/current/security/voters.html
Something like:
class NurseryVoter extends Voter
{
const MANAGE = 'manage';
protected function supports($attribute, $subject)
{
if (!in_array($attribute, array(self::MANAGE))) {
return false;
}
if (!$subject instanceof Nursery) {
return false;
}
return true;
}
protected function voteOnAttribute($attribute, $nursery, TokenInterface $token)
{
$user = $token->getUser();
if (!$user instanceof User) {
// the user must be logged in; if not, deny access
return false;
}
// Check the role and do your query to verify user can manage specific nursery
Wire everything up per the link. And at this point your controller code is reduces to:
$this->denyAccessUnlessGranted('manage', $nursery);
Get all that working first. After that, use a Kernel:Controller event to move the deny access code from the controller to a listener. Follow the docs: http://symfony.com/doc/current/event_dispatcher.html
Your controller listener gets called after the controller is assigned but before the controller action is actually called. The trick here is how to determine which action actually needs the check to be done. There are a couple of approaches. Some folks like to flag the actual controller class perhaps by adding a NurseryManagerInterface. The listeners check the controller to see if it has the interface. But I don't really care for that.
I like to add this sort of stuff directly to the route. So I might have:
// routes.yml
manage_nursery:
path: /manage/{nursery}
defaults:
_controller: manage_nursery_action
_permission: CAN_MANAGE_NURSERY
Your listener would then check the permission.
Updated with a few more details on the kernel listener. Basically you inject the authorization checker and pull _permission from the request object.
class KernelListener implements EventSubscriberInterface
{
// #security.authorization_checker service
private $authorizationChecker;
public function __construct($authorizationChecker,$nuseryRepository)
{
$this->authorizationChecker = $authorizationChecker;
$this->nurseryRepository = $nuseryRepository;
}
public static function getSubscribedEvents()
{
return [
KernelEvents::CONTROLLER => [['onController']],
];
}
public function onController(FilterControllerEvent $event)
{
$request = $event->getRequest();
$permission = $request->attributes->get('_permission');
if ($permission !== 'CAN_MANAGE_NURSERY') {
return;
}
$nursery = $this->nurseryRepository->find($request->attributes->get('nursery');
if ($this->authorizationChecker->isGranted('MANAGE',$nursery) {
return;
}
throw new AccessDeniedException('Some message');
}
First of all sorry about my english, I'll try to do my best.
Im new to Laravel, im trying to implement custom auth throught a SOAP WS, I declare new class that implement UserProviderInterface. I success on implement retrieveByCredentials and validateCredentials methods but since i dont have access to database or global users information i cant implement retrieveByID method. Is there any way to make custom Auth not based on users id's ?
I need:
- Login and validate user throught SOAP WS
- Store User Info returned by WS.
- Remember me functionality
- Secure routes based on logged user and level of access
- Logout
Implemented class:
<?php
namespace Spt\Common\Providers;
use Illuminate\Auth\UserProviderInterface;
use Illuminate\Auth\GenericUser;
use Illuminate\Auth\UserInterface;
class AuthUserProvider implements UserProviderInterface{
private $user;
public function __construct(){
$this->user = null;
}
public function retrieveByID($identifier){
return $this->user;
}
public function retrieveByCredentials(array $credentials){
$client = new \SoapClient('webserviceurl');
$res = $client->Validar_Cliente($credentials);
$res = $res->Validar_ClienteResult;
if($res->infoError->bError === true){
return;
}
$res->id = $res->id_cliente;
$user = new GenericUser((array) $res);
return $user;
}
public function validateCredentials(UserInterface $user, array $credentials){
//Assumed that if WS returned a User is validated
return true;
}
}
I think that re-implement UserProviderInterface its not the solution but i googled and not found other way
Any Idea?
You're almost done, apart from the fact that private variable $user of AuthUserProvider doesn't survive the current http request. If you cannot "retrieve by id" from your web service, I guess the only way is to store the entire user in the session - Laravel itself stores the user's id in the session and the fact that it stores only the id (not the entire user) is one of the reasons why a retrieveByID method is needed.
The following is only to clarify and is untested.
class AuthUserProvider implements UserProviderInterface {
public function retrieveByCredentials(array $credentials) {
$client = new \SoapClient('webserviceurl');
$res = $client->Validar_Cliente($credentials);
$res = $res->Validar_ClienteResult;
if($res->infoError->bError === true) {
return;
}
$res->id = $res->id_cliente;
Session::put('entireuser', $res);
$user = new GenericUser((array) $res);
return $user;
}
public function retrieveByID($identifier) {
$res = Session::get('entireuser');
return new GenericUser((array) $res);
}
// ...
}
If you can't retrieve by id from your web service, I guess you cannot either retrieve by remember token, so it may be impossible for you to implement the "remember me" functionality, unless you store part of users data in a second database (which at that point could be used in place of the session above).
I'm working on my first user login in Zend Framework, but I'm a little confused with Zend_Auth. All the articles I read about it use it directly in the controller. But to me, it makes more sense, to work as a plugin
What do you guys think?
You can use it as a plugin, the only downside is that if you initialize the plugin in your bootstrap, then the plugin will be executed for every controller and action, since it would have to run before your controller.
You could extend Zend_Auth and add extra methods to set up the auth adapter and manage the storage, and then you can just call Your_Custom_Auth::getInstance() to get the auth instance and then you can check for auth in the preDispatcth() part of your controllers that need auth.
This way you can easily work with zend_auth in multiple places with less code
<?php
class My_User_Authenticator extends Zend_Auth
{
protected function __construct()
{}
protected function __clone()
{}
public static function getInstance()
{
if (null === self::$_instance) {
self::$_instance = new self();
}
return self::$_instance;
}
// example using zend_db_adapter_dbtable and mysql
public static function getAdapter($username, $password)
{
$db = Zend_Controller_Front::getInstance()
->getParam('bootstrap')
->getResource('db');
$authAdapter = new Zend_Auth_Adapter_DbTable($db,
'accounts',
'username',
'password');
$authAdapter->setIdentity($username)
->setCredential($password)
->setCredentialTreatment(
'SHA1(?)'
);
return $authAdapter;
}
public static function updateStorage($storageObject)
{
self::$_instance->getStorage()->write($storageObject);
}
}
// in your controllers that should be fully protected, or specific actions
// you could put this in your controller's preDispatch() method
if (My_User_Authenticator::getInstance()->hasIdentity() == false) {
// forward to login action
}
// to log someone in
$auth = My_User_Authenticator::getInstance();
$result = $auth->authenticate(
My_User_Authenticator::getAdapter(
$form->getValue('username'),
$form->getValue('password'))
);
if ($result->isValid()) {
$storage = new My_Session_Object();
$storage->username = $form->getValue('username');
// this object should hold the info about the logged in user, e.g. account details
My_User_Authenticator::getInstance()->updateStorage($storage); // session now has identity of $storage
// forward to page
} else {
// invalid user or pass
}
Hope that helps.
"Plugin" in ZF doesn't only mean "front controller plugin", also Action helpers, view helpers...
ZF guru Matthew Weier O'Phinney wrote an excellent article about creating action helpers, and guess what ?..
He illustrates it with an Auth widget !
http://weierophinney.net/matthew/archives/246-Using-Action-Helpers-To-Implement-Re-Usable-Widgets.html
don't forget to read the articles comments, as a lot of interesting Q&A are handled there
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed last year.
Improve this question
I've just started to play with CodeIgniter 1.7.2 and imendialtly noticed that there is not a built-in library for user authentication.
I don't need anything fancy. It's only to authenticate users in to my back office system. I don't need users and groups, or permissions etc. I just need a script to allow users to login. If a user tries to access a page and they are not logged in they should be denied. But it must be secure and it would be good if it use CI validation library.
Can anyone recommend a library for CI 1.7.2?
I did notice there is a similar post on StackOverflow but it's well out of date and most of the libraries recommended either do not support 1.7.2 or are no longer being maintained.
Most important thing is that is must be secure and simple.
DX Auth or Freak Auth are great libraries that will suit almost every need that you may have
http://codeigniter.com/wiki/DX_Auth/
http://codeigniter.com/wiki/FreakAuth/
I tend to roll my own simple authentication library.
Firstly, this is the authentication library. It keeps a user ID token in the session. When authenticating it checks for the existence of this token.
application/libraries/Auth.php
class Auth
{
var $ci;
var $user_id;
function Auth()
{
// Get CodeIgniter instance
$this->ci = get_instance();
// Fetch token from the session
$this->user_id = $this->ci->session->userdata('user_id');
}
function check()
{
return $this->user_id != null;
}
function login($user_id)
{
// Set token in the session
$this->ci->session->set_userdata('user_id', $user_id);
$this->user_id = $user_id;
}
function logout()
{
// Remove token from the session
$this->ci->session->unset_userdata('user_id');
$this->user_id = null;
}
}
I create my own base controller and authenticate there. For convenience, if authenticated, the base controller loads and stores the current user.
application/libraries/MY_Controller.php
class MY_Controller extends Controller
{
var $user;
function MY_Controller()
{
parent::Controller();
}
function do_auth()
{
if ($this->auth->check())
{
// Authenticated. Fetch current user
$this->user = $this->user_model->get_user($this->auth->user_id);
}
else
{
// Not authenticated. Redirect to login page
redirect('users/login');
}
}
}
Then in any action I can call the authentication function of the base controller.
class Items extends MY_Controller
{
function Items()
{
parent::MY_Controller();
}
function create()
{
// Do authentication
$this->do_auth();
// Continue with handling request
}
}
If I like I can also secure an entire controller.
class Items extends MY_Controller
{
function Items()
{
parent::MY_Controller();
// Secure entire controller
$this->do_auth();
}
}
I place the login and logout actions in a users controller. In the login action I verify the user's credentials and log in the user.
class Users extends MY_Controller
{
function Users()
{
parent::MY_Controller();
}
function login()
{
// Verify form input
$this->load->library('form_validation');
$this->form_validation->set_rules('username', 'Username', 'required');
$this->form_validation->set_rules('password', 'Password', 'required');
if ($this->form_validation->run())
{
// Fetch the user based on credentials supplied
$user = $this->user_model->get_user_by_credentials($this->input->post('username', true), $this->input->post('password', true));
if ($user != null)
{
// Credentials verified. Log the user in.
$this->auth->login($user->user_id);
redirect('');
}
else
{
// Login failed. Show the login page.
$this->load->view('users/login', array('login_failed' => true));
}
}
else
{
// Yet to authenticate. Show the login page.
$this->load->view('users/login', array('login_failed' => false));
}
}
function logout()
{
$this->auth->logout();
redirect('users/login');
}
}
Well, not very specific to CI is a .htaccess user/password system. Especially if you only have a few users.
It's simple to set up, and is built into every Apache server.