In yii i am creating login module. I want to give access to users only if username and passwords are correct and need to store this user's id into 'Success' table. But when only username is correct and password is wrong,i want to store that user's id into 'attempt' table in order to give only 3 chance to him for entering correct password. But when i am implementing this,when password is wrong entry doesnt get enterd into attempt table. i had created ActionLogin() method as-
public function actionLogin()
{
$model=new LoginForm;
$command = Yii::app()->db->createCommand();
// if it is ajax validation request
if(isset($_POST['ajax']) && $_POST['ajax']==='login-form')
{
echo CActiveForm::validate($model);
Yii::app()->end();
}
// collect user input data
if(isset($_POST['LoginForm']))
{
$model->attributes=$_POST['LoginForm'];
// validate user input and redirect to the previous page if valid
if ($model->validate())
{
if($model->login()) {
$command->insert('attempt', array(
'id'=>Yii::app()->user->getId(),
));
$this->redirect(Yii::app()->user->returnUrl);
}
if(!$model->login())
{
$command->insert('attempt', array(
'id'=>Yii::app()->user->getId(),
));
}
}
}
// display the login form
$this->render('login',array('model'=>$model));
}
What changes i need to do in order to make entry of user's id into attempt table when password is wrong. Please help me.
As stated in the comments:
A user that is visiting a Yii based website doesn't have a user id assigned, only logged in users have a userId assigned (which makes sense...).
The best approach would be to do IP based checks on the login attempts. You can retrieve a user his IP by the following piece of code:
Yii::app()->request->userHostAddress
Also credits for this answer to #Stu and #Nikos-Tsirakis
Related
I am working on a micro service. It has basically login and registration. I followed the Yii2 official guide. But now i am facing an issue. When i try to send request to the endpoints which are protected ( Only users with access_token can make request ) It works but very strange it checks all the rows in the database and if access_token is matches any rows in the database then it allows the request. But what i want - I am trying to get users information, if i pass the token i want only the information which belongs to current user ( Whose token is in request ) .
I am doing this in my UserController -
public function behaviors() {
$behaviors = parent::behaviors();
$behaviors['authenticator'] = [
'class' => HttpBearerAuth::className(),
];
$behaviors['authenticator']['only'] = ['view'];
return $behaviors;
}
And in User model have implemented this method -
public static function findIdentityByAccessToken($token, $type = null) {
return static::findOne(['access_token' => $token]);
}
Where i am doing wrong?
If the access_token in the request matches the access_token value for any of the users in the database, then, like you say, the authentication filter will forward the request to the corresponding action on your controller.
At this point the application user component points to the user that was found, you can use the user's component id to recover the record matching the request's user from the database.
// Get the user record
$current_user = Yii::$app->user->identity;
// Do something with the user record
return [
'username' => $current_user->username,
'last_update' => $current_user->updated_at
...
];
I'm simply want to show the user that is currently logged in. My code for the Auth section came from 2.x cookbook.
The issue is the following:
I have 2 users currently in the system. User A and User B. User B was created second. Instead of showing the current user, it just shows User B. I assume it is because User B was the last to be created, because if I create User C, it will show user C instead.
Here is my action:
public function index($id = null) {
$this->set('strains', $this->Strain->find('all'));
$this->loadModel('User');
$users = $this->User->find('all');
$this->set('users', $users);
$this->set('userDataName', $this->Auth->user('id'));
if($this->Auth->user()) {
$this->User->id = $id;
$user = $this->Session->write('user', $this->User->findById($id));
$this->set('user', $user);
}
}
Here is the line in my view that should show the current user:
<?php echo $user['User']['username']; ?>
I've read several stack questions, but none seem to go over this specific scenario. I'm open to completely re-writing code if necessary. Thanks
the simplest way to display the username of the current session user is to use the auth component:
in controller
$user = $this->Auth->user(); // returns array with user data or null
$this->set('user', $user);
in view
echo $user['username'];
It's a logic error
Here is the line in my view that should show the current user:
<?php echo $user['User']['username']; ?>
In the template the username is taken from the $user variable.
public function index($id = null) {
...
$this->User->id = $id;
$user = $this->Session->write('user', $this->User->findById($id));
$this->set('user', $user);
}
}
The user variable depends on the $id parameter, not directly the currently logged-in user.
How to access the logged in user data
The simplest way to access the logged in user data is to use AuthComponent::user i.e. in a template:
<?php echo AuthComponent::user('username'); ?>
I am building a website using Woocommerce.By default the username is the user's email address.I want to provide the users the feature to login through their phone number also. How can i do that? Please help!
This is an interesting one. There are a couple of things to consider:
Has the user actually entered their phone number against their account already, or given their number when they've made a purchase?
Are we using the billing phone number for their login?
Assuming both of those things are true, you can hook into the authenticate filter, search for users with matching billing_phone meta, and return that user's actual username:
<?php
///
// Allow login via phone number
///
function vnmAdmin_emailLogin($user, $username, $password) {
// Try logging in via their billing phone number
if (is_numeric($username)) {
// The passed username is numeric - that's a start
// Now let's grab all matching users with the same phone number:
$matchingUsers = get_users(array(
'meta_key' => 'billing_phone',
'meta_value' => $username,
'meta_compare' => 'LIKE'
));
// Let's save time and assume there's only one.
if (is_array($matchingUsers)) {
$username = $matchingUsers[0]->user_login;
}
}
return wp_authenticate_username_password(null, $username, $password);
}
add_filter('authenticate', 'vnmAdmin_loginWithPhoneNumber', 20, 3);
?>
NOTE: This method isn't absolutely robust; for example it doesn't check for whitespace (either in the 'login' number or the retrieved user meta number); and it simply makes the assumption that the first user it finds is the correct one - not ideal if, for whatever reason, you have more than one user using the same phone number. But having said that, I've tested it and it works.
Function name was not same as given in add_filter callback in #indextwo answer. I wanted to authenticate using email and phone number. Used #indextwo answer and came up with this.
///
// Allow login via phone number and email
///
function vnmAdmin_loginWithPhoneNumber($user, $username, $password) {
// Try logging in via their billing phone number
if (is_numeric($username)) {
// The passed username is numeric - that's a start
// Now let's grab all matching users with the same phone number:
$matchingUsers = get_users(array(
'meta_key' => 'billing_phone',
'meta_value' => $username,
'meta_compare' => 'LIKE'
));
// Let's save time and assume there's only one.
if (is_array($matchingUsers) && !empty($matchingUsers)) {
$username = $matchingUsers[0]->user_login;
}
}elseif (is_email($username)) {
// The passed username is email- that's a start
// Now let's grab all matching users with the same email:
$matchingUsers = get_user_by_email($username);
// Let's save time and assume there's only one.
if (isset($matchingUsers->user_login)) {
$username = $matchingUsers->user_login;
}
}
return wp_authenticate_username_password(null, $username, $password);
}
add_filter('authenticate', 'vnmAdmin_loginWithPhoneNumber', 20, 3);
I am trying to login the user with google account in my application. I am having a problem when the user is logged in for the first time with google account in my app it shows this error:
Argument 1 passed to Illuminate\Auth\Guard::login() must implement interface Illuminate\Auth\UserInterface, null given
In my controller I have this:
public function loginWithGoogle() {
// get data from input
$code = Input::get('code');
// get google service
$googleService = Artdarek\OAuth\Facade\OAuth::consumer("Google");
if (!empty($code)) {
// This was a callback request from google, get the token
$token = $googleService->requestAccessToken($code);
// Send a request with it
$result = json_decode($googleService->request('https://www.googleapis.com/oauth2/v1/userinfo'), true);
$user = User::whereEmail($result['email'])->first(['id']);
if (empty($user)) {
$data = new User;
$data->Username = $result['name'];
$data->email = $result['email'];
$data->google_id = $result['id'];
$data->first_name = $result['given_name'];
$data->last_name = $result['family_name'];
$data->save();
}
Auth::login($user);
return Redirect::to('/');
}
// if not ask for permission first
else {
// get googleService authorization
$url = $googleService->getAuthorizationUri();
// return to facebook login url
return Redirect::to((string) $url);
}
}
I know the problem is with Auth::login($user); as insert is performed at the same time with Auth::login($user); and it doesn't find data from database for the first time, but I don't know how to avoid this error and instead redirects to the main page even when the user is logged in for the first time. After this error the user is logged in, but how to avoid this?
Without knowing whether the rest of the code works, you definitely have a problem here:
if (empty($user)) {
$data = new User;
(...)
$data->save();
}
Auth::login($user);
When you're done creating your user, the $user variable is still empty. Your user is actually called $data. You should either rename the variable, or do the login with $data instead. Hopefully, that's enough to make the code work. :)
I have login form with input text fields:
Group Name
User Name
User Password
I have two tables
groups
id
name
users
id
name
group_id
I have its mapping entities and associations.
But user name not unique within table users, because different groups can include users with equal names. Therefore i need:
find group by name in table groups
find user by name in table users with condition where group_id=<group_id>
How to do it correctly in Zend Framework 2 using Doctrine 2?
All official documentation and examples depict situation, where identity property is single column (example).
Sorry for my bad language. Thanks.
Instead of making my own implementation of Doctrine's authentication services i decide to implement it via form validation inside isValid() method of my authentication form.
Example:
<?php
namespace My\Form\Namespace;
use Zend\Form\Form;
use Zend\ServiceManager\ServiceLocatorInterface;
use Zend\InputFilter\InputFilterProviderInterface;
class Auth extends Form implement InputFilterProviderInterface
{
protected $_em;
public function __construct(ServiceLocatorInterface $sm)
{
parent::__construct('auth');
// inject Doctrine's Entity Manager
$this->_em = $sm->get('Doctrine\ORM\EntityManager');
// login field
$this->add(...);
// password field
$this->add(...);
// group_name field
$this->add(...);
}
public function getInputFilterSpecification()
{
//Input filter specification here
...
}
public function isValid()
{
/*
* input filter validations
*/
if (!parent::isValid())
return false;
/*
* group exists validation
*/
$group = $this->_em
->getRepository('<Group\Entity\Namespace>')
->findOneBy(array(
'name' => $this->get('group_name')->getValue(),
));
if (!$group){
$this->get('group_name')
->setMessages(array(
'Group not found',
));
return false;
}
/*
* user exists validation
*/
$user = $this->_em
->getRepository('<User\Entity\Namespace>')
->findOneBy(array(
'group_id' => $group->getId(),
'name' => $this->get('login')->getValue(),
));
if (!$user){
/*
* It's not good idea to tell that user not found,
* so let it be password error
*/
$this->get('password')
->setMessages(array(
'Login or password wrong',
));
return false;
}
/*
* password validation
*/
$password = $this->get('password')->getValue();
// assume that password hash just md5 of password string
if (md5($password) !== $user->getPassword()){
$this->get('password')
->setMessages(array(
'Login or password wrong',
));
return false;
}
return true;
}
}
Inside controller it is enough to call $form->isValid() to make sure that user entered correct authentication data.
I have the same problem.
I have to do two authentications in same application, because my boss doesn't wanna two databases. So, I had to make two user tables and two login pages.
One route to admin -> /admin/login
And the front-end for other users -> /login
I've tried to put on more authenticate in doctrine authentication array but it didn't work.
I think I'll open a issue on doctrine github page.