I have an issue with my model in EF model first. I have a web app, with security layer and entity layer and mvc3 layer. So in each layer I put a instance of my context db (one for each class in the main declaration section). the problem is when y find any user of my db for validate the login process, simple search, not make any changes in entity, is like this:
var usr = db.Usuarios.First(user => user.UserName.Equals(userName));
If I change the password for example in other layer (in my controller user), and the logout an login again, the linq search (see code up) always return the old password. This is for the context db dont dispose and dont go to database for the data, simple load the user for the model.
So, how I can force the model to refresh the data from the database?
I try, put lazy load in false but not work.
db.Configuration.LazyLoadingEnabled = false;
partial work if I decalre a instance of my context in the metod to validate passwork and dispose this instance, but I think it is the best practice.
like that:
public static bool ValidateUser(string userName, string password)
{
if (!string.IsNullOrEmpty(userName) && !string.IsNullOrEmpty(password))
{
var dbtmp = new ConorContainer();
var usr = dbtmp.Usuarios.First(user => user.UserName.Equals(userName));
if (usr != null)
{
var passDescrypt = Decript(usr.Password);
dbtmp.Dispose();
return passDescrypt.Equals(password);
}
return false;
}
return false;
}
You have to decide the lifetime of the context in each case. It is preferred to use short lived contexts in web applications specially in static methods.
Your method can be improved by employing the using block that will call the Dispose method when going out of scope.
public static bool ValidateUser(string userName, string password)
{
if (!string.IsNullOrEmpty(userName) && !string.IsNullOrEmpty(password))
{
using(var dbtmp = new ConorContainer())
{
var usr = dbtmp.Usuarios.First(user => user.UserName.Equals(userName));
if (usr != null)
{
var passDescrypt = Decript(usr.Password);
return passDescrypt.Equals(password);
}
}
return false;
}
return false;
}
Related
I need some advice on how to proceed with the mvc app I'm building. On my page I type out who is logged in to the page. This I first did by creating a base class where I created a user class which contained the users name and a image representing the user. Then I passed this class on to my views. But I also need to pass other models to my views depending on what view I'm in. Sure I could build a class that contain all different models I need to use on each page but there should be a easy way to pass name and image values across the pages and be persistant? I tried TempData together with TempData.Keep() but that was not persistant. How can I pass theses values between pages?
public ActionResult Validate(AccountModels.LoginModel model)
{
if (ModelState.IsValid)
{
if (Membership.ValidateUser(model.UserName, model.Password))
{
var mu = _repo.GetUser(Membership.GetUser().ProviderUserKey.ToString());
TempData["Name"] = mu.Name;
TempData["Image"] = mu.Image;
TempData.Keep();
FormsAuthentication.RedirectFromLoginPage(model.UserName, model.RememberMe);
}
}
return View("Index");
}
As #Jyoti said, you could use of Keep() method.
To make it easy to work with TempData, I wrote these methods in my BaseController, and I use it in every controller when I need to transfer data between actions or between view and controller.
protected TReturnType GetTempDataValue<TReturnType>(PsmConstants.TempDataKey sessionName, bool peekData =false )
{
object value = peekData ? TempData.Peek(sessionName.ToString()) : TempData[sessionName.ToString()];
return (TReturnType) value;
}
protected void RemoveTempData(PsmConstants.TempDataKey sessionName)
{
if (TempData.ContainsKey(sessionName.ToString()) && TempData[sessionName.ToString()] == null) return;
TempData[sessionName.ToString()] = null;
}
protected void SetTempDataValue(PsmConstants.TempDataKey sessionName, object value)
{
if(TempData.ContainsKey(sessionName.ToString()))
TempData[sessionName.ToString()]=null;
TempData[sessionName.ToString()] = value;
}
protected void KeepTempDataValue(PsmConstants.TempDataKey sessionName)
{
if (TempData.ContainsKey(sessionName.ToString()))
TempData.Keep(sessionName.ToString());
}
And this is the Keys enumeration :
public enum TempDataKey
{
PageError = 1,
PageInfo = 2
}
And this is, the usage of these methods(Set value and Get value from TempData):
SetTempDataValue(PsmConstants.TempDataKey.PageError , 'your error message' );
var originalValues = GetTempDataValue<MyModel>(PsmConstants.TempDataKey.Info, true);
Use session instead of Temp if it is not working.but i think it should work.
TempData["Name"] = mu.Name;TempData["Image"] = mu.Image;TempData.Keep();
How you are passing this into other models,Please share the source code so that it will easy to identify.
I have an web front end calling an ASP Web Api 2 backend. Authentication is managed with ASP Identity. For some of the controllers I'm creating I need to know the user making the call. I don't want to have to create some weird model to pass in including the user's identity (which I don't even store in the client).
All calls to the API are authorized using a bearer token, my thought is the controller should be able to determine the user context based on this but I do not know how to implement. I have searched but I don't know what I'm searching for exactly and haven't found anything relevant. I'm going for something like...
public async Task<IHttpActionResult> Post(ApplicationIdentity identity, WalkthroughModel data)
Update
I found the below which looked very promising... but the value is always null! My controller inherits from ApiController and has an Authorize header.
var userid = User.Identity.GetUserId();
Update 2
I have also tried all of the solutions in Get the current user, within an ApiController action, without passing the userID as a parameter but none work. No matter what I am getting an Identity that is valid and auth'd, but has a null UserID
Update 3
Here's where I'm at now.
[Authorize]
[Route("Email")]
public async Task<IHttpActionResult> Get()
{
var testa = User.Identity.GetType();
var testb = User.Identity.GetUserId();
var testc = User.Identity.AuthenticationType;
var testd = User.Identity.IsAuthenticated;
return Ok();
}
testa = Name: ClaimsIdentity,
testb = null,
testc = Bearer,
testd = true
The user is obviously authenticated but I am unable to retrieve their userID.
Update 4
I found an answer, but I'm really unhappy with it...
ClaimsIdentity identity = (ClaimsIdentity)User.Identity;
string username = identity.Claims.First().Value;
That gets me the username without any db calls but it seems very janky and a pain to support in the future. Would love if anyone had a better answer.
What if I need to change what claims are issued down the road? Plus any time I actually need the user's id I have to make a db call to convert username to ID
A common approach is to create a base class for your ApiControllers and take advantage of the ApplicationUserManager to retrieve the information you need. With this approach, you can keep the logic for accessing the user's information in one location and reuse it across your controllers.
public class BaseApiController : ApiController
{
private ApplicationUser _member;
public ApplicationUserManager UserManager
{
get { return HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>(); }
}
public string UserIdentityId
{
get
{
var user = UserManager.FindByName(User.Identity.Name);
return user.Id;
}
}
public ApplicationUser UserRecord
{
get
{
if (_member != null)
{
return _member ;
}
_member = UserManager.FindByEmail(Thread.CurrentPrincipal.Identity.Name);
return _member ;
}
set { _member = value; }
}
}
I use a custom user authentication (I dont use AspIdentity because my existing user table fields was far different from IdentityUser properties) and create ClaimsIdentity passing my table UserID and UserName to validate my bearer token on API calls.
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
User user;
try
{
var scope = Autofac.Integration.Owin.OwinContextExtensions.GetAutofacLifetimeScope(context.OwinContext);
_service = scope.Resolve<IUserService>();
user = await _service.FindUserAsync(context.UserName);
if (user?.HashedPassword != Helpers.CustomPasswordHasher.GetHashedPassword(context.Password, user?.Salt))
{
context.SetError("invalid_grant", "The user name or password is incorrect.");
return;
}
}
catch (Exception ex)
{
context.SetError("invalid_grant", ex.Message);
return;
}
var properties = new Dictionary<string, string>()
{
{ ClaimTypes.NameIdentifier, user.UserID.ToString() },
{ ClaimTypes.Name, context.UserName }
};
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
properties.ToList().ForEach(c => identity.AddClaim(new Claim(c.Key, c.Value)));
var ticket = new AuthenticationTicket(identity, new AuthenticationProperties(properties));
context.Validated(ticket);
context.Request.Context.Authentication.SignIn(identity);
}
And how I use the ClaimsIdentity to retrieve my User table details on User ApiController Details call.
[HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
[Route("Details")]
public async Task<IHttpActionResult> Details()
{
var user = await _service.GetAsync(RequestContext.Principal.Identity.GetUserId<int>());
var basicDetails = Mapper.Map<User, BasicUserModel>(user);
return Ok(basicDetails);
}
Notice the
ClaimTypes.NameIdentifier = GetUserId() and ClaimTypes.Name = GetUserName()
I have some custom fields on my User object that I want to access with APEX code in my VisualForce trigger. When I access it from a Formula field I get to use a nifty $User reference like this:
$User.my_prop__c
From APEX I have to query the User object by UserId like this:
[select my_prop__c from User where id = :UserInfo.getUserId()].my_prop__c;
Is there something baked into APEX already that would let me get at the user properties without the SOQL query? If not, does anyone know of a utility class for lazy loading and caching user properties so the overhead is minimal.
I would use something similar to the following code sample. It uses a singleton pattern to statically store the information in memory for the duration of your transaction. It's similar to the lazy loading that twamley proposed but I feel this is a much simpler approach.
Usage 1: UserUtil.CurrentUser.Email;
Usage 2: User someUser = UserUtil.getUser(someUserId);
This will allow you to access the same information on the current user or other users in the system. Notice the queryUsers method just returns a query result. This makes it easy to add and remove fields from your query as it is isolated in its own method keeping things simple.
Note: that this code pulls in all users when used. Most orgs do not have multiple hundreds of users so heap size shouldn't be a concern. But if it is you can just modify the queryUsers() method to only return active users or filter down based on other criteria.
public class UserUtil {
//Protected Members
private static final UserUtil instance = new UserUtil();
private Map<Id, User> mapUsers;
//Properties
public static User CurrentUser {
get { return getUser(UserInfo.getUserId()); }
}
//Constructor
private UserUtil() {
mapUsers = new Map<Id, User>(queryUsers());
}
//Public Methods
public static User getUser(Id userId) {
if (instance.mapUsers.containsKey(userId)) {
return instance.mapUsers.get(userId);
}
else {
throw new InvalidUserIdException('Unable to locate user id: ' + userId);
}
}
//Private Methods
private List<User> queryUsers() {
return [SELECT
Id
, Name
, UserName
, Email
, Alias
FROM
User];
}
//Internal Classes
public class InvalidUserIdException extends Exception {}
}
I wrote my own utility class. I'm still interested in better techniques though.
This utility class lazy loads when the first property is accessed. Update_Closed_Won_Opportunities__c and Set_Opportunities_to_Closed_Won__c are my custom fields on the User object (visible only to System Administrators so people can't upgrade their permissions).
public with sharing class MyUserInfo {
private Id userId;
private User myUser; // Hold onto the user object once we've loaded it
// Default constructor uses the active user id
public MyUserInfo() {
userId = UserInfo.getUserId();
}
// Secondary constructor accepts a user id as a parameter
public MyUserInfo(Id someOtherUserId) {
userId = someOtherUserId;
}
// Only called one time when we first need it so grab all of the custom fields now
private void LazyLoadUser() {
System.AssertNotEquals(null, userId);
myUser = [
SELECT Update_Closed_Won_Opportunities__c, Set_Opportunities_To_Closed_Won__c
FROM User
WHERE id = :userId
];
System.AssertNotEquals(null, myUser, 'Unable to load user with id ' + userId); // could return defaults instead
}
// Getters (be sure to include each field in the SOQL of LazyLoadUser)
public boolean UpdateClosedWonOpportunities { get {
if (myUser == null) LazyLoadUser();
return myUser.Update_Closed_Won_Opportunities__c;
} }
public boolean SetOpportunitiesToClosedWon { get {
if (myUser == null) LazyLoadUser();
return myUser.Set_Opportunities_To_Closed_Won__c;
} }
}
Here is my trigger utilizing that class. The first line myUserInfo = new MyUserInfo(); doesn't run any SOQL. That won't happen until the first custom get property is used. Subsequent calls don't need SOQL.
trigger LockClosedOpportunity on Opportunity (before update) {
MyUserInfo myUserInfo = new MyUserInfo();
for (Opportunity o : trigger.old)
{
if (!myUserInfo.UpdateClosedWonOpportunities && o.StageName == 'Closed Won')
trigger.newMap.get(o.Id).addError('You do not have permission to change an Opportunity after it has been set to Closed Won.');
}
for (Opportunity o : trigger.new)
{
if ( !myUserInfo.SetOpportunitiesToClosedWon && o.StageName == 'Closed Won' && trigger.oldMap.get(o.Id).StageName != 'Closed Won' )
o.addError('You do not have permission to set an Opportunity to Closed Won.');
}
}
It reads similar to $User in formulas and I don't have to worry about tacking on multiple SOQL calls when one (or zero) suffices.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 4 years ago.
Improve this question
Ok, so this seems like a common need. A little googling finds a lot of ways to do this. I'm interested in the most "mvc correct" way to do it.
I have, in the upper right hand corner of my app, a greeting that says Hello FirstName LastName. Now, it's quite easy to get at the username of the logged in user, through the IPrincipal (aka User.Identity.Name). However, this won't give me the First and Last name of the user. I have to hit the Membership API to get that.
Hitting the Membership API has its drawbacks. It hits the database every time, which adds an additional db access to every served page. It's easy enough to set some session variables on login, but this only works for that session. If the user clicks the "Remember me", then no login occurs next time and i have to still load these values.
I could create my own membership provider to do some cacheing, but that's a lot of work for a more or less single purpose.
I could use Application_AuthenticateRequest and hit the membership api and store the values in session variables, or something similar. This is ok, but seems a little brute force.
I could register a global filter and handle OnAuthenticate, essentially doing the same thing. This seems a little better, but i'm unusre of the ramifications here.
I could derive a base controller, and simly add properties to provide this information. This seems a bit "old school", and I hate having to make a base class for a single purpose.
I could create a cacheing static method that would get the information on first access. This is basically not much better than a singleton.
I could also create my own IPrincipal, but that means casting it every time to get at the data, and that seems clunky. I could wrap that in another class to simplify it, but still...
I could store the data in the forms authentication cookie, and get it from there. There's some tools available to make that easier.
Are there any methods I haven't thought of? And what is the most "mvc correct" way of doing it?
I think the best way is using Cookies. Here is the solution I used in my project:
Create a class to save data in it
[DataContract]
[Serializable()]
public class AuthData {
[DataMember]
public String UserName { get; set; }
[DataMember]
public String FirstName { get; set; }
[DataMember]
public String LastName { get; set; }
[DataMember]
public String Email { get; set; }
// any other property you need to a light-store for each user
public override string ToString() {
string result = "";
try {
using (MemoryStream stream = new MemoryStream()) {
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, this);
result = Convert.ToBase64String(stream.ToArray());
}
} catch (Exception ex) {
throw new HttpException(ex.Message);
}
return result;
}
static public AuthData FromString(String data) {
AuthData result = null;
try {
byte[] array = Convert.FromBase64String(data);
using (MemoryStream stream = new MemoryStream(array)) {
stream.Seek(0, 0);
BinaryFormatter formatter = new BinaryFormatter();
result = (AuthData)formatter.Deserialize(stream, null);
}
} catch (Exception ex) {
throw new HttpException(ex.Message);
}
return result;
}
}
Signin method:
public static bool SignIn(string userName, string password, bool persistent){
if (Membership.ValidateUser(userName, password)) {
SetAuthCookie(userName, persistent);
return true;
}
return false;
}
Setting AuthCookie:
public static void SetAuthCookie(string userName, bool persistent) {
AuthData data = GetAuthDataFromDB(); // implement this method to retrieve data from database as an AuthData object
var ticket = new FormsAuthenticationTicket(
1,
userName,
DateTime.Now,
DateTime.Now.Add(FormsAuthentication.Timeout),
persistent,
data.ToString(),
FormsAuthentication.FormsCookiePath
);
string hash = FormsAuthentication.Encrypt(ticket);
HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, hash);
cookie.Expires = DateTime.Now.Add(FormsAuthentication.Timeout);
cookie.HttpOnly = false;
cookie.Path = FormsAuthentication.FormsCookiePath;
HttpContext.Current.Response.Cookies.Add(cookie);
}
Getting AuthCookie:
public static AuthData GetAuthCookie() {
if (HttpContext.Current.User != null && HttpContext.Current.User.Identity.IsAuthenticated && HttpContext.Current.User.Identity is FormsIdentity) {
FormsIdentity id = (FormsIdentity)HttpContext.Current.User.Identity;
FormsAuthenticationTicket ticket = id.Ticket;
var data = AuthData.FromString(ticket.UserData);
HttpContext.Current.Items["AuthDataContext"] = data;
return data;
}
return null;
}
In ControllerBase:
private AuthData _authData;
private bool _authDataIsChecked;
public AuthData AuthData {
get {
_authData = System.Web.HttpContext.Current.Items["AuthDataContext"] as AuthData;
if (!_authDataIsChecked && _authData == null) {
SignService.GetAuthCookie();
_authData = System.Web.HttpContext.Current.Items["AuthDataContext"] as AuthData;
_authDataIsChecked = true;
}
return _authData;
}
}
The FormsAuthenticationExtensions project solves this problem storing the additional information in the auth cookie itself. http://formsauthext.codeplex.com/
This spares the database hit, and lives as long as the auth cookie, hence it works if the users asks for "remember me". It can be used the same way (in MVC too) as the standard forms authentication.
To your question, what is the most MVCisch way: I would first decide where I want to keep the information. This part of the question is rather independent of the MVC framework as the concepts (session, post data, cookies, etc.) are given with or without it.
I will implement and extend the IPrincipal and IIdentity, so when you access User.Identity you will find LastName and FirstName.
This way is better imo.
For my projects I have extended IIdentity and IPrincipal with my classes adding the properties I always need "to be there". To me is not this big work, I mean, there are only a bunch of methods that need to be implemented.
For IIdentity the interface requirement are only AuthenticationType (string), IsAuthenticated (bool) and Name (string).
While in IPrincipal Identity (IIDentity) and IsInRole (boolean)
ref:
http://www.lunatech-research.com/playframework-file-upload-blob
I'm uneasy about one point in this example
#{list items:models.User.findAll(), as:'user'}
<img src="#{userPhoto(user.id)}">
#{/list}
At this point I'm already holding the user object (including the image blob). Yet the userPhoto() method makes another dip into the backend to get the Image user.photo
public static void userPhoto(long id) {
final User user = User.findById(id);
notFoundIfNull(user);
response.setContentTypeIfNotSet(user.photo.type());
renderBinary(user.photo.get());
}
Any way to avoid this unnecessary findById call?
You're not actually holding the user object any more though, because the userPhoto action is invoked in a separate request that's sent when the browser tries to load the image from the URL generated by #{userPhoto(user.id)}.
Of course, you could use the cache to store data from each user's photo Blob, which would reduce the likelihood that you had to go to the database on the image request. It's more trouble than it's worth in this case though since you're just doing a simple primary key lookup for the user object, and that should be relatively inexpensive. Plus Blobs aren't serializable, so you have to pull out each piece of information separately.
Still, if you were to try that it might look something like this:
// The action that renders your list of images
public static void index() {
List<User> users = User.findAll();
for (User user : users) {
cachePhoto(user.photo);
}
render(users);
}
// The action that returns the image data to display
public static void userPhoto(long id) {
InputStream photoStream;
String path = Cache.get("image_path_user_" + id);
String type = Cache.get("image_type_user_" + id);
// Was the data we needed in the cache?
if (path == null || type == null) {
// No, we'll have to go to the database anyway
User user = User.findById(id);
notFoundIfNull(user);
cachePhoto(user.photo);
photoStream = user.photo.get();
type = user.photo.type();
} else {
// Yes, just generate the stream directly
try {
photoStream = new FileInputStream(new File(path));
} catch (Exception ex) {
throw new UnexpectedException(ex);
}
}
response.setContentTypeIfNotSet(type);
renderBinary(photoStream);
}
// Convenience method for caching the photo information
private static void cachePhoto(Blob photo) {
if (photo == null) {
return;
}
Cache.set("image_path_user_" + user.id,
photo.getFile.getAbsolutePath());
Cache.set("image_type_user_" + user.id,
photo.getType());
}
Then you'd still have to worry about appropriately populating/invalidating the cache in your add, update, and delete actions too. Otherwise your cache would be polluted with stale data.