I have added the authentication plugin and changed the code as per the CakePHP 4 documentation (https://book.cakephp.org/4/en/tutorials-and-examples/cms/authentication.html). by default they using "users" table for authenticating. how can I change the default "users" table to the table "clients"?
Thank You.
Using Authentication ORM to solve this issue
Edit under src/Application.php
// Load identifiers, ensure we check email and password fields
$authenticationService->loadIdentifier('Authentication.Password', [
'fields' => [
'username' => 'staff_email',
'password' => 'staff_password',
],
'resolver'=>[
'className'=>'Authentication.Orm',
'userModel' => 'myStaffs',
],
]);
In src/Application.php in the getAuthenticationService function try to add the following:
$authenticationService->loadAuthenticator('Authentication.Form', [
'fields' => [
'username' => 'email',
'password' => 'password',
],
'userModel' => 'Clients',
'loginUrl' => '/clients/login',
]);
Related
I've got a User model that hasOne Membership model, with a users table and a memberships table (each entry in the memberships table has a foreign key linked to a user_id).
I've made a registration page that lets the user have a 7 days trial period on the membership but I'm having trouble storing the data.
This is the dd() of the data in the registration form:
"_token" => "ckRlMligEyTwu7ssOi4TmesycbsPpVQlrJ4jQaBd"
"username" => "JaneDoe"
"password" => "password"
"password_confirmation" => "password"
"expiration" => "2021-04-30"
Now in my controller I've got the following store() method:
public function store(Request $request) {
// validating
$this->validate($request, [
'username' => ['required', 'max:200'],
'password' => 'required|confirmed',
'expiration' => 'required'
]);
// storing
User::create([
'username' => $request->username,
'password' => Hash::make($request->password),
'expiration' => $request->expiration
]);
}
This won't store anything in the memberships table and I have no idea how to correctly write the store method using the Model's Eloquent Relationships declared.
Thanks for the help.
EDIT:
While trying to make some sense i've modified the store() function, now looks like this:
public function store(Request $request) {
// validating
$this->validate($request, [
'username' => ['required', 'max:200'],
'password' => 'required|confirmed',
'expiration' => 'required'
]);
// storing
User::create([
'username' => $request->username,
'password' => Hash::make($request->password)
])->membership(Membership::create([
'expiration' => $request->expiration
]));
}
Now seems like Laravel doesn't know where to get the user_id of the newly created user, like the error suggests:
SQLSTATE[HY000]: General error: 1364 Field 'user_id' doesn't have a default value (SQL: insert into `memberships` (`expiration`, `updated_at`, `created_at`)
Your solution is to do:
User::create([
'username' => $request->username,
'password' => Hash::make($request->password)
])->membership()->create([
'expiration' => $request->expiration
]);
Using the relation (membership() not membership as an attribute) will already know the relation key (user_id in this case).
You can see more info about this in the documentation.
Other way of doing same is:
$membership = new Membership([
'expiration' => $request->expiration
]);
User::create([
'username' => $request->username,
'password' => Hash::make($request->password)
])->membership()->save($membership);
More info about save() on the documentation.
I installed the authentication plugin on a fresh CakePHP 4 project. Enabled regarding the documentation and it works for session-based auth. I want to add remember me functionality, so added
->add(new EncryptedCookieMiddleware(['CookieAuth'], Configure::read('Security.cookieKey'))) to the $middlewareQueue variable in Application#middleware. There is no any explanation how to generate the cookieKey actually, but I used a random string to test. Also added
$service->loadAuthenticator('Authentication.Cookie', [
'fields' => $fields,
'loginUrl' => '/users/login',
]);
remember me field is remember_me by default. So I added <?= $this->Form->control('remember_me', ['type' => 'checkbox']); ?> to the login form. I tried to check it and login, but it doesn’t add the cookie to the browser when I check with Chrome DevTools.
auth service config is like that in getAuthenticationService:
$service = new AuthenticationService();
// Define where users should be redirected to when they are not authenticated
$service->setConfig([
'unauthenticatedRedirect' => Router::url([
'prefix' => false,
'plugin' => null,
'controller' => 'Users',
'action' => 'login',
]),
'queryParam' => 'redirect',
]);
$fields = [
IdentifierInterface::CREDENTIAL_USERNAME => 'email',
IdentifierInterface::CREDENTIAL_PASSWORD => 'password'
];
// Load the authenticators. Session should be first.
$service->loadAuthenticator('Authentication.Session');
// If the user is on the login page, check for a cookie as well.
$service->loadAuthenticator('Authentication.Cookie', [
// 'rememberMeField' => 'remember_me',
'fields' => $fields,
'loginUrl' => '/users/login',
]);
$service->loadAuthenticator('Authentication.Form', [
'fields' => $fields,
'loginUrl' => Router::url([
'prefix' => false,
'plugin' => null,
'controller' => 'Users',
'action' => 'login',
]),
]);
// Load identifiers
$service->loadIdentifier('Authentication.Password', compact('fields'));
return $service;
What am I missing?
Thanks in advance.
I configure a Auth component to "Admin page", using the users model. But now, I also want create/configure a Auth to the clients. I try "rewrite" the inialize()
//This is in my ClientsController.php
public function initialize()
{
$this->loadComponent('RequestHandler');
$this->loadComponent('Flash');
$this->loadComponent('Auth', [
'authenticate' => [
'Form' => [
'userModel' => 'clients',
'fields' => ['username' => 'client_email', 'password' => 'client_password']
]
],
'loginRedirect' => [
'controller' => 'Clients',
'action' => 'index'
],
'logoutRedirect' => [
'controller' => 'Clients',
'action' => 'login'
],
]);
}
With this, I receive this log(if uses parent::initalize() receive the same)
[RuntimeException] The "Auth" alias has already been loaded with the following config: array (...
I not want create a "Auth" manualy. How to use more of one Auth?
Thanks....
Reconfigure
You don't necessarily need to use multiple auth component instances, you can simply reconfigure it in the extended controller, using the components config() method, something along the lines of:
public function initialize()
{
parent::initialize();
// ...
$this->Auth->config(
[
'authenticate' => [
'Form' => [
'userModel' => 'clients',
'fields' => [
'username' => 'client_email',
'password' => 'client_password'
]
]
],
'loginRedirect' => [
'controller' => 'Clients',
'action' => 'index'
],
'logoutRedirect' => [
'controller' => 'Clients',
'action' => 'login'
],
'storage' => [
'className' => 'Session',
'key' => 'Auth.Client'
]
],
null,
false
);
}
Note the use of the storage option, you should define a different key here (the default is Auth.User), otherwise an authenticated client might be able to access the admin area and vice versa, as the user data would get stored in the same session key!
Use aliasing
You could use multiple auth components if required, to do so you'd have to use aliasing, so that the components don't try to override each other:
$this->loadComponent('ClientAuth', [
'className' => 'Auth',
// ....
]);
Don't forget to use a different session key in this case too!
You'd access that component instance as $this->ClientAuth accordingly, and you may have to allow access to the login() method via $this->Auth, ie. in ClientsController::initialize() or beforeFilter() do:
$this->Auth->allow('login');
There might be further side-effects, so be careful.
See also
Cookbook > Controllers > Components > Authentication > Configuration options
Cookbook > Controllers > Components > Aliasing Components
I have one table whose name is admins. Its contains username and password fields. My sales user use admins table for the sales login. I want to login sales using AuthComponent. I have write code for this as below.
AppController
public $components = [
'Auth' => [
'loginAction' => [
'controller' => '',
'action' => 'login'
],
'logoutRedirect' => [
'controller' => '',
'action' => 'login'
],
'loginRedirect' => [
'controller' => '',
'action' => 'deshboard'
],
'className' => 'MyAuth'
]]
public function beforeFilter() {
$this->Auth->authenticate = [
'Form' => ['userModel' => 'admin', "fields" => ["username" => "username",
"password" => "password"]
]];
}
SalesController
function login() {
$post = $this->request->data('Admin');
if ($this->request->is('post') && !empty($post)) {
//var_dump($this->Auth->login());exit;
if ($this->Auth->login()) {
return $this->Auth->redirect($this->Auth->redirectUrl());
}
// perform login throttling (failure and block) if Sales or Admin portal
// set an appropriate failure message
}
}
When I have print the return value of auth->login() function. Its always return false.
I have search a lots for this issue but I am unable to find any proper answer.
Thanks in advance for helping me.
I have find the solution for my above issue.
This issue is because of passwordHaser. I use difference password in the add or update password so we have to define the passwordHaser in the component configuration, if we don’t use simple encription.
'Auth' => [
'className' => 'MyAuth',
'authenticate' => [
'Form' => [
'userModel' => 'Admin',
'fields' => [
'username' => 'username',
'password' => 'password'
],
'passwordHasher' => [
'className' => 'Simple'
]
]
],
],
In one laravel project, I would have two auth method:
API client authentication (to check if client can query the API) with dedicated eloquent model (something like APIUser)
User authentication (to check user credential) with another dedicated model (Something User)
I would like to authenticate through first auth system then check a user credential through second auth system. Example :
curl -u a:b myapi/?user=c&pass=d
So a&b are login and password for API client authentication and c&d are login and password for user authentication. What can be the best way to do that: create a multi-auth system ? or consider only one system is for auth, the other is just querying database ? or something else ? (hope my question is clear enough, I can edit if you need)
Multiauth works like a build-in laravel auth, but allow few independent auth sessions (you can login on first, second or both accounts).
Use Ollieread's MultiAuth extension for Laravel. It sets everything up for you. Just open up the file app/config/auth.php and replace this array:
return array(
'driver' => 'eloquent',
'model' => 'User',
'table' => 'users',
'reminder' => array(
'email' => 'emails.auth.reminder',
'table' => 'password_reminders',
'expire' => 60,
),
);
with
return array(
'multi' => array(
'admin' => array(
'driver' => 'eloquent',
'model' => 'Admin'
),
'user' => array(
'driver' => 'database',
'table' => 'users'
)
),
'reminder' => array(
'email' => 'emails.auth.reminder',
'table' => 'password_reminders',
'expire' => 60,
),
);
Of course, you can add as many as you want. Then copy paste the default User.php model for your Admin.php table.