In this doc exist $response variable
https://github.com/hwi/HWIOAuthBundle/blob/master/Resources/doc/internals/response_object_and_paths.md
but i I do not understand, how $response came to the controller.
Help, please! Give me example, please!
You have to implement own custom User Provider which is gonna use HWIOAuthBundle for loading user's data (analogically as if you want to load users from own SQL table, for example).
Here is good example: https://gist.github.com/danvbe/4476697
And the Symfony's doc How to Create a custom User Provider
EDIT
The controller doesn't have access to HWIOAuthBundle's UserResponseInterface, your UserProvider does, so if you want to access realName of the user in the controller, you have to do it through user entity.
User provider:
...
public function loadUserByOAuthUserResponse(UserResponseInterface $response)
{
$userEmail = $response->getEmail();
$user = $this->userManager->findUserByEmail($userEmail);
// if null just create new user and set it properties
if (null === $user) {
$realName = $response->getRealName();
$user = new User();
$user->setRealName($realName);
...
Controller:
...
public function defaultAction(Request $request)
{
$this->getUser()->getRealName();
...
Related
In a ZF2 project i am using the AuthenticationService to validate a users log in credentials. This is working fine, except it only stores in the session a string containing the users name.
What i would like would be for subsequent calls to AuthenticationService::getIdentity to return a custom Identity object, that is populated with the users database id, roles and permissions (popualted from an RBAC service), so that the object in the session is a bit more useful.
I am able to create this object, but am unsure of the best way to keep it in the session; ideally i would like to override the entry with the key Zend_Auth, but this does not seem to be working.
My code so far:
<?php
namespace Authentication\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Zend\Authentication\AuthenticationService;
use Authentication\Form\Login\LoginForm;
use Zend\Form\Form;
use Authentication\Model\Identity\AuthenticatedIdentity;
class AuthenticationController extends AbstractActionController
{
/**
*
* #var AuthenticationService
*/
protected $authenticationService;
/**
*
* #var LoginForm
*/
protected $loginForm;
/**
*
* #param AuthenticationService $authenticationService
* #param LoginForm $loginForm
*/
public function __construct(AuthenticationService $authenticationService, LoginForm $loginForm){
$this->authenticationService = $authenticationService;
$this->loginForm = $loginForm;
}
public function indexAction(){
$form = $this->loginForm;
$viewModel = new ViewModel();
$viewModel->setVariables([
'loginForm' => $form
]);
if($this->getRequest()->isPost() === false){
return $viewModel;
}
$form->setData($this->getRequest()->getPost());
if($form->isValid() === false){
return $viewModel;
}
$data = $form->getData();
$authenticationAdapter = $this->authenticationService->getAdapter();
$authenticationAdapter->setIdentity($data['credentials']['username'])
->setCredential($data['credentials']['password']);
$authenticationResult = $this->authenticationService->authenticate($authenticationAdapter);
if($authenticationResult->isValid() === false){
$viewModel->setVariable('validCredentials', false);
return $viewModel;
}
/**
* Create a user model and save it to the session.
*/
$authenticationResultRow = $authenticationAdapter->getResultRowObject(null, ['password']);
$permissions = $this->rbacService->getPermissionsForUser($authenticationResultRow->user_id);
$roles = $this->rbacService->getRolesForUser($authenticationResultRow->user_id);
$identity = new AuthenticatedIdentity(
$authenticationResult->getIdentity(),
'admin',
$permissions,
$roles
);
$identity->setUserId($authenticationResultRow->user_id);
//how to store this Identity object in session so AuthenticationService will return it?
return $this->redirect()->toRoute('dashboard');
}
}
Check out https://github.com/zendframework/zend-authentication/blob/master/src/AuthenticationService.php#L75 and https://github.com/zendframework/zend-authentication/blob/master/src/Storage/StorageInterface.php
You can write the AuthenticatedIdentity object directly to the storage like so:
$this->authenticationService->getStorage()->write($identity);
However, I would advice against doing so because:
If the user's permissions/roles change during the session he/she would have to log out and back in to see any changes which is not very user-friendly.
Your AuthenticatedIdentity object and all objects it contains need to be serializable, which can become problematic to maintain.
I would (and do) fetch the user object and/or roles when needed, either from DB or some form of cache but don't store it in the session.
Can anyone give me solution for this issue (or article, keyword ):
One user create a product, and back-end will be send mail for admin to approve the product, this mail has contained the link:
http://localhost:11260/#/productHandle/116796
I want admin don't need login in system, and can access this link.
because the current code in Global.asax check cookies:
protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
{
HttpCookie ck = Request.Cookies[FormsAuthentication.FormsCookieName];
if (ck != null && !String.IsNullOrEmpty(ck.Value))
{
FormsAuthenticationTicket fat = FormsAuthentication.Decrypt(ck.Value);
UserProfile profile = JsonConvert.DeserializeObject<UserProfile>(fat.UserData);
MyPrincipal myPrincipal = new MyPrincipal(profile.Username);
myPrincipal.UsrProfile = profile;
HttpContext.Current.User = myPrincipal;
}
}
---after access successfully, i intended to encrypt this link. but step above don't work..
thank for help me!
We have a similar application that involves a user requesting access to our document imaging system, and then an email is sent to our application admins for approval. The general idea looks like this:
[HttpPost]
public ActionResult RegisterNewUser(NewUser model)
{
if (ModelState.IsValid)
{
var pwSalt = repository.CreateSalt();
var newUser = User();
newUser.Username = model.Username;
newUser.Email = model.Email;
newUser.PasswordSalt = pwSalt;
newUser.Password = repository.CreatePasswordHash(model.Password, pwSalt);
newUser.IsApproved = false;
newUser.RegisterDate = DateTime.Now;
db.Users.Add(newUser);
db.SubmitChanges();
ConfirmationEmail(model.Username);
return RedirectToAction("RegistrationSuccess");
}
}
The above code is the post-action for a new user who's just registered for our application. It adds the user to the db table. The model contains fields like name, username, email, etc (I also have a function "CreatePasswordHash" which uses the user's password and a generated SALT to created an encrypted password). One thing to note is that the Users table contains a column "IsApproved", which sets to "false" by default. Without this value changing to "true", the user won't be able to use the application. Within this action is another function named "ConfirmationEmail" which is where we send an email to one of the admins for approval.
public void ConfirmationEmail(string username)
{
var user = db.Users.Single(u => u.Username == username);
string mailBody = "A new user requires approval for document imaging.\n\n"
+ "Name: " + user.Name + "\n\n"
+ "\n\n"
+ "If you approve, follow the link below: \n\n"
+ "http://example.com/Imaging/Account/Approval/" + user.UserId;
MailMessage msg = new MailMessage();
msg.Priority = MailPriority.High;
msg.To.Add(admin#example.com);
msg.Subject = "New User registration approval";
msg.Body = mailBody;
msg.IsBodyHtml = false;
SmtpClient smtp = new SmtpClient();
smtp.Send(msg);
msg.Dispose();
}
The above function takes a username param from the original registration action, which we use to find the user record (note: Username in the Users table is a UNIQUE column, so it will fail validation if it's not unique). I create the body of the email using plain text, and attach the URL of the approval action for the admin to confirm approval. Everything else is standard mail code (SMTP settings are stored in my web.config file).
Account controller -- Approval action:
public ActionResult Approval(int id)
{
var user = db.Users.Find(id);
user.IsApproved = true;
db.SubmitChanges();
EmailApproval(id);
return View(user);
}
Simple action that changes the "IsApproved" flag to true, which grants the user access to the application. The View that is returned contains basic user information displayed in a nice confirmation window. Lastly, there's a function "EmailApproval" which sends an email to the user about being approved. It uses the same emailing practices as the other function above.
Hope this helps.
You can make action insecure ([AllowAnonymous] will help you) and implement security for this action via IP address.
In this case you need to implement you own Authorization filter (read there how to do it) and check that it is called from predefined admin's IP and call is local (use HttpRequest.IsLocal for checking this).
Frankly, I never will do something insecure in my projects so you have to think twice before doing something similar for this.
From other hand you can extend your session timeout.
MVC 5 with asp.net identity 2.0
I understand how to get the currently logged in user id. I have a need to get the user id of a different user in the system. How is this done?
Ex. I need to get the user id of user names "fsmith" ...
Inside the AccountController you can call the following method to get user object and then get the User Id.
var user = await UserManager.FindByNameAsync(userName);
var userId = user.Id;
If you are not inside AccountController you can get the UserManager reference using the following code
var UserManager = HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
To add to Shashi's useful answer...
If you're inside the account controller you can use the existing UserManager:
var user = await UserManager.FindByNameAsync(userName);
var userId = user.Id;
In other controllers (and maybe select other places where HttpContext is available) you create a User Manager with:
var um = HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
But what it took me a while to realize is you can get at it just about anywhere with this last bit. For instance I used it in my seed method (in Configuration.cs) so I could seed the User property of another model:
var um = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(*insert-your-db-context-here*));
One way would to use the FindByNameAsync method of your user manager (or the generic version of it). It takes the name of the user (in your case "fsmith") and returns a task of a user object. This user object contains all the information available about that user.
A code snippet could look similar to the following one (if you're looking for the database ID):
var user = await UserManager.FindByNameAsync("fsmith");
var userId = user.Id;
EDIT
The UserManager instance is normally declared as follows (keep in mind that there are many ways of declaring it, for example when using Dependency Injection):
public AccountController()
: this(new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext())))
{
}
public AccountController(UserManager<ApplicationUser> userManager)
{
UserManager = userManager;
}
public UserManager<ApplicationUser> UserManager { get; private set; }
If you are using Bearing Token Auth, the above sample do not return an Application User.
Instead, use this:
ClaimsPrincipal currentUser = this.User;
var currentUserName = currentUser.FindFirst(ClaimTypes.NameIdentifier).Value;
ApplicationUser user = await _userManager.FindByNameAsync(currentUserName);
return user.Id;
This works in apsnetcore 2.0. Have not tried in earlier versions.
i new to zenframework 2. i have correctly set up zendframework 2,doctrine and zfcUser.All work correctly.
my issue now is now regarding how to prepoulated a form if a member is already logged in.
this is where i extend zfcUser to obtain the Id of a loggged in member:
public function setid( $id)
{
$this->id = $id;
}
public function getId()
{
if (!$this->id) {
$this->setid($this->zfcUserAuthentication()->getAuthService()->getIdentity()->getId());
}
return $this->id;
}
i know want to use that Id to obtain the values from the database and then populate the form with those values.
this is my form:
public function aboutYouAction()
{
$id = $this->getId() ;
$form = new CreateAboutYouForm($this->getEntityManager());
$aboutYou = new AboutYou();
$form->setInputFilter($aboutYou->getInputFilter());
$form->bind($aboutYou);
if ($this->request->isPost())
{
$form->setData($this->request->getPost());
if ($form->isValid())
{
$post = $this->request->getPost();
$this->getEntityManager()->persist($aboutYou);
$this->getEntityManager()->flush();
return $this->redirect()->toRoute('worker', array('action' => 'aboutYou'));
}
}
$messages='';
// return array('form' => $form);
return new ViewModel(array('form' => $form, 'messages' => $messages));
}
To set the values on the form all you need to do is $form->bind($aboutYou)
The bind() method is designed to take the passed entity instance and map it to the forms elements; This process being referred to as form hydration.
Depending on the hydrator attached to the form or fieldset (With doctrine this would normally be the DoctrineModule\Stdlib\Hydrator\DoctrineObject) this should be able to evaluate the AboutYou fields, including any entity references/associations, and set the corresponding form elements values. I'm assuming that one of these fields is user.
In you specific case it seems you are binding a new entity (which therefore will not have any properties set, such as your user)
$aboutYou = new AboutYou(); // Brand new entity
$form->bind($aboutYou); // Binding to the form without any data
What this means is that the form is trying to set the values of the elements but the provided AboutYou class has no data to set (as its new and was not loaded via doctrine) and/or the properties of the AboutYou class to not correctly map to the form's elements.
If you wish to bind the user you will need to fetch the populated instance. This can be done using doctrine ($objectManager->find('AboutYou', $aboutYouId)) or if you need to set the current logged in user call the controller plugin ZfcUser\Controller\Plugin\ZfcUserAuthentication from within the controller and no where else.
You workflow should be similar to this (illustration purposes only)
// Controller
public function aboutYouAction()
{
// Get the id via posted/query/route params
$aboutYouId = $this->params('id', false);
// get the object manager
$objectManager = $this->getServiceLocator()->get('ObjectManager');
// Fetch the populated instance
$aboutYou = $objectManager->find('AboutYou', $aboutYouId);
// here the about you entity should be populated with a user object
// so that if you were to call $aboutYou->getUser() it would return an user object
// Get the form from the service manager (rather than creating it in the controller)
// meaning you should create a factory service for this
$form = $this->getServiceLocator()->get('MyForm');
// Bind the populated object to the form
$form->bind($aboutYou);
//... rest of the action such as handle edits etc
}
In my web application registered users can add new content and edit it later. I want only the content's author to be able to edit it. Is there any smart way of doing this other than manually writing code in all the action methods that checks if the logged user is the same as the author? Any attribute that I could use for the whole controller?
Any attribute that I could use for the whole controller?
Yes, you could extend the Authorize attribute with a custom one:
public class AuthorizeAuthorAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
var isAuthorized = base.AuthorizeCore(httpContext);
if (!isAuthorized)
{
// the user is either not authenticated or
// not in roles => no need to continue any further
return false;
}
// get the currently logged on user
var username = httpContext.User.Identity.Name;
// get the id of the article that he is trying to manipulate
// from the route data (this assumes that the id is passed as a route
// data parameter: /foo/edit/123). If this is not the case and you
// are using query string parameters you could fetch the id using the Request
var id = httpContext.Request.RequestContext.RouteData.Values["id"] as string;
// Now that we have the current user and the id of the article he
// is trying to manipualte all that's left is go ahead and look in
// our database to see if this user is the owner of the article
return IsUserOwnerOfArticle(username, id);
}
private bool IsUserOwnerOfArticle(string username, string articleId)
{
throw new NotImplementedException();
}
}
and then:
[HttpPost]
[AuthorizeAuthor]
public ActionResult Edit(int id)
{
... perform the edit
}
I would:
Save the db.aspnet_Users columm UserId (Guid) against the content record
Write an extension method for your content model which verifies the current users Guid against the saved contents User Guid
I would write some code that overrides this functionality for your Admin logins (I would create an Admin Role).