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
...
];
Related
I am using cakephp 3.7.2 with Authentication component
$user = $this->Authentication->getIdentity();
prints:
object(Authentication\Identity) {
'config' => [
'fieldMap' => [
'id' => 'id'
]
],
'data' => object(App\Model\Entity\User) {
'id' => (int) 1,
'email' => 'aa.aaa#gmail.com',
...
}
}
I have tried $user->data but it doesn't work.
How to print user data?
Authentication Component
So I have figured it out.
In User Entity class
Add use Authentication\IdentityInterface;
and then implement the IdentityInterface.
class User extends Entity implements IdentityInterface
{
blablabla...
yale yale yale ...
Now you can print:
$user = $this->Authentication->getIdentity();
debug($user->id);
As per Authentication component documentation
The identity object is returned by the service and made available in
the request. The object provides a method getIdentifier() that can be
called to get the id of the current log in identity.
You can use this accordingly as below to get the user data:
// Service
$identity = $authenticationService
->getIdentity()
->getIdentifier()
// Component
$identity = $this->Authentication
->getIdentity()
->getIdentifier();
// Request
$identity = $this->request
->getAttribute('identity')
->getIdentifier();
The identity object provides ArrayAccess but as well a get() method to
access data. It is strongly recommended to use the get() method over
array access because the get method is aware of the field mapping.
For eg. to access email and username from the identity you can use the below code.
$identity->get('email'); // to access email
$identity->get('username'); // to access username
Reference link: Authentication -> Docs -> Identity Object
Hope this will help.
I´m using AuthComponent in CakePHP 4.xxx.
I can get User data i.e. in a view with
$user = $this->getRequest()->getAttribute('identity');
I found the Information on: http://gotchahosting.com/blog/category/cakephp/4002624
Maybe it helps someone who is looking for information about this in CakePHP4
I'm trying to see if it's possible in an ASP.NET-Core 2 web app, that if a User is authenticated in a request, we can also check in some Filter/ActionMethod Attribute:
They have a specific claim
The route has an string id segment (e.g. HttpPut[("{id}")] ) and that id segment needs to match the Auth'd User's Id.
Request includes a JWT header with the bearer token in it, which is used to 'create' the Authenticated Identity (which works 100% fine).
e.g.
HTTP PUT /accounts/PureKrome | User Id:PureKrome | Claim: Irrelivant. => Can continue. [You are updating yourself. Don't need any special claim when updating yourself].
HTTP PUT /accounts/PureKrome | User is Anonymous or Id:SomethingElse | Claim: irrelivant => Failure (Forbidden response) [Someone else is trying to update you and doesn't have the correct overriding claim. So fail]
HTTP PUT /accounts/SomeoneElse | User is Id:PureKrome | Claim: correct claim. => Can continue [Trying to update a different user BUT you have a claim that allows you to do that]
Right now, I do this in my ActionMethod code ... one of the first things. So I was just curious to see if this could be achieved using an Attribute that decorates the ActionMethod, instead.
That isn’t actually too complicated. All you need to do is have an authorization filter that looks at the route values and then checks it with the current user.
Something simple like this should already work fine:
public class ValidateUserIdRouteAttribute : Attribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationFilterContext context)
{
var user = context.HttpContext.User;
var requestedUserId = context.RouteData.Values["id"] as string;
var currentUserId = user.FindFirstValue(ClaimTypes.NameIdentifier);
if (requestedUserId != currentUserId &&
!user.HasClaim(c => c.Type == "may-edit" && c.Value == requestedUserId))
{
context.Result = new UnauthorizedResult();
}
}
}
And used on a route it would look like this:
[ValidateUserIdRoute]
[HttpGet("/account/update/{id}")]
public IActionResult UpdateAccount(string id)
{
// …
}
That’s all. If you have authentication set up properly, the Bearer token will be used to authenticate the user which may or may not set up the claims properly, and then you just check against those claims to see if accessing the route is allowed or not.
Of course, you can expand on this idea and add some more functionality to it, e.g. support different route data keys or something like that.
I have problem with auth_key , I have login form and it's work correctly without remember me and with remember me , but I read yii document , in that document wrote about remember me work with id and auth_key for create cookie to stay user in long time , i check the framework code and in there have three parameters (id, auth_key, expire_time()) i save auth_key in user table and it's code here
public function generateAuthKey()
{
$this->auth_key = Yii::$app->security->generateRandomString();
}
public function validateAuthKey($authKey)
{
return $this->getAuthKey() === $authKey;
}
public function getAuthKey()
{
return $this->auth_key;
}
but i have problem , it's if a user login in site and i go to the user table and change the auth_key field , and now if user refresh the page it must be throw out the site because it's auth key is changed , but the user stay login in site , where is problem ?
The main use of auth_key is to authenticate the user by cookie (user don't have to put login data again). When you choose to be remembered at Login, this is how you are remembered. The system has to identify and login you somehow. It won't log out user if u change it.
You can try to change the key yourself in the "ValidateAutney" method, but this will be a bad practice, it is better to set the session time.
'session' => [
'class' => 'yii\mongodb\Session',
'writeCallback' => function($session)
{
return [
'user_id' => Yii::$app->user->id,
'agent' => Yii::$app->request->getUserAgent(),
'ip' => Yii::$app->request->getUserIP(),
'auth_key' => Yii::$app->security->generateRandomString(),
];
}
],
public function getAuthKey()
{
Yii::$app->session->open();
$query = new Query();
$query->select(['auth_key'])
->from('cache')
->where(['id'=> Yii::$app->session->id ]);
$row = $query->one();
return $row['auth_key'];
}
Auth :: attempt works perfect, but when you pass the second parameter "true" apparently does not care or does not recover with viaRemember
viaRemember fails to work, check this
controller User
`$`userdata = array(
'email' => trim(Input::get('username')),
'password' => trim(Input::get('password'))
);
if(Auth::attempt(`$`userdata, true)){
return Redirect::to('/dashboard');
}
view 'dashboard', always show 777
#if (Auth::viaRemember())
{{666}}
#else
{{777}}
#endif
I have hit the same obstacle, so looking into the code one can see that viaRemember is not meant to be used as a function to check if the user was logged into the system in one of all the ways a user can be logged in.
'viaRemember' is meant to check if a user was logged into the system specifically via the `viaRemember' cookie.
From what I gather, authentication of user is remembered in two ways:
a via remember cookie.
The cookie value is compared to the via remember field in the users table.
a session cookie.
The cookie value is used in the server to get the session from the
session store. On the session object from the store there is data attached. One of the
data items is the user id connected to the session. The first time
the session was created, the system attached the user id to the data
of the season.
In Illuminate\Auth\Guard class:
public function user()
{
if ($this->loggedOut) return;
// If we have already retrieved the user for the current request we can just
// return it back immediately. We do not want to pull the user data every
// request into the method because that would tremendously slow an app.
if ( ! is_null($this->user))
{
return $this->user;
}
$id = $this->session->get($this->getName());
// First we will try to load the user using the identifier in the session if
// one exists. Otherwise we will check for a "remember me" cookie in this
// request, and if one exists, attempt to retrieve the user using that.
$user = null;
if ( ! is_null($id))
{
$user = $this->provider->retrieveByID($id);
}
// If the user is null, but we decrypt a "recaller" cookie we can attempt to
// pull the user data on that cookie which serves as a remember cookie on
// the application. Once we have a user we can return it to the caller.
$recaller = $this->getRecaller();
if (is_null($user) && ! is_null($recaller))
{
$user = $this->getUserByRecaller($recaller);
}
return $this->user = $user;
}
The getUserByRecaller function is called only if the session cookie authentication did not work.
The viaRemember flag is only set in the getUserByRecaller function. The viaRemember method is only a simple getter method.
public function viaRemember()
{
return $this->viaRemember;
}
So in the end, we can use Auth::check() that does make all the checks including the viaRemember check. It calls the user() function in the Guard class.
It seems also the viaRemember is only an indicator. You need to do a type of Auth::check() the will get the process of authentication started and so the user() function will be called.
It seems that your project is on Laravel 4.0 but viaRemember() is added in Laravel 4.1! So that's expected.
in config\session.php file change the 'expire_on_close' = false to true and once you close restart your browser, it must be ok.
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.