have scoured by couldn't find anything relevant.
I have to this point built a cool web app in MVC using C#. I created a User model as
public class User
{
// Must be named EntityNameId, must have primary key!
public int UserId { get; set; }
[DisplayName("First Name")]
public string firstName { get; set; }
[DisplayName("Last Name")]
public string lastName { get; set; }
[DisplayName("Cell Number")]
public string cellNumber { get; set; }
}
And as such have designed a profile/dashboard for each user
/User/Profile/1
Accessed by their id. Ive also got other sections such as a menu to edit items /Item/Index/1 which shows all items for that user etc. My code works etc to filter and populate those pages just for the user. To this point however I have not implemented any authentication. I would like to use the built in authentication tools through ApplicationServices and have done before with roles:
<Authorize(Roles:="Manager,Administrator")>
However I would like to limit pages to specific users who are logged in? I.e. /User/Profile/1 should only be accessible by that user etc. Rather than the roles they serve.
Does any one know how this could be done? I know this would likely mean tying the account controllers and user controllers together, not quite sure how to do this so that everything works the same? As app is basically finished, quite simple tho, but just requires authentication.
Just do a simple check at the top of the action method, if it's not the current user, perform the redirect.
public ActionResult Profile(int id)
{
if (CurrentUser.Id != id)
{
return RedirectToAction("Index");
}
return View();
}
If you use it a lot, you could refactor it out into a method.
A secondary option would be to not even pass the user Id into the controller/action method, just grab the logged in user's Id and get the information from there.
[Authorize]
public ActionResult Profile()
{
return View(profileService.GetUserProfile(CurrentUser.Id));
}
Related
To prevent showing password when retrieving user from data base I use JsonIgnore atribute and it works fine for logged user, but it prevents registering a new user or logging in another user. How to use JsonIgnore to work when retrieving data from data base but not when registering or logging in, in ASP.NET Core (C#)?
This is my user model:
public class UserModel
{
[Key]
public int Id { get; set; }
[Column(TypeName ="nvarchar (30)")]
public string Name { get; set; }
[Column(TypeName ="nvarchar (100)")]
[JsonIgnore]
public string Password { get; set; }
}
Never retrieve the password from database, even when you are checking it. You should "search" for a user with that password and retrieve an Id or other data if exists. You never should do that.
Suggestion:
Even more, you should have your password encrypted in one way with SHA-256 or SHA-512 and stored in another table that doesn't call "passwords" or related field to that. Also never do a "select *" even as "select all fields" if you won't use them in that business logic. Less is more.
I'm finding this difficult to summarise, hence the poor question name. On my .net web application, which is using Identity, there is a login partial that was auto generated that displays the users 'username' property like so:
#Html.ActionLink(User.Identity.GetUserName(), "Index", "Manage", routeValues: null, htmlAttributes: new {title = "Manage"})
After profiling the SQL database that is holding the user data, I noticed that this call to GetUserName() doesn't actually make a call to the database to retrieve the name. I am looking to access a navigation property of the 'ApplicationUser' class that holds the url for a thumbnail image I want to be displayed.
However I am hoping I can achieve this without the need to call the database for the URL on every page request. An example of this would be on this site, where your profile image is displayed on every page as part of the layout.
The application user class has this property.
public class ApplicationUser : IdentityUser
{
public UserProfile Profile { get; set; }
}
And the user profile class holds this property.
public class UserProfile
{
[Key, ForeignKey("User")]
public string UserId { get; set; }
public ApplicationUser User { get; set; }
[Required]
public string ThumbnailUrl { get; set; }
...
}
How can I do this? Or is there a much better way of trying to achieve this.
You can just add them as claims.
When authenticating you should fetch the User from the DB and add all the properties you would need use later on.
Assuming that you are using CreateIdentity when logging in a user, that should return a ClaimsIdentity object.
var userIdentity = await userManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
userIdentity.AddClaim(new Claim("Thumbnail", user.ThumbnailUrl));
Then you need to create a extension class, let's say IdentityExtensions:
public static class IdentityExtensions{
public static string Thumbnail(this IIdentity identity){
try{
return ((ClaimsIdentity) identity).FindFirst("Thumbnail").Value;
}
catch(Exception ex){
// handle any exception the way you need
}
}
}
Finally, on your views you should be able to use #User.Identity.Thumbnail()
You're right it doesn't make a call... the reason is because it's holding that data in the client's cookies... If it didn't the server would have a meltdown if it had to keep running back and forth to grab such trivial data for large scale systems... so it's cached.
The way it's done in ASP.NET MVC is via the use of the IPrinciple interface... I'll point you in the right direction to learn more about it...
CodeProject: How to implement a custom IPrincipal in MVC
Best thing todo is to create a second table (or add a column to the current table), add a file upload feature to the registration form. When registration is successful add the picture to the db with EntityFramework. Create a page to return the picture by the userid so you can include it in a page somewhere.
you can use this idea
http://blogs.msdn.com/b/webdev/archive/2013/10/16/customizing-profile-information-in-asp-net-identity-in-vs-2013-templates.aspx
Does this property have any verification for itself by default? Like Max. length, etc.? If it does, where can it be found?
I'm asking, because i'm intending to override the UserName property to add more verification. Or should i add the verification in every ViewModel?
I believe the best way for you to enforce the change is at the core, i.e. at the model ApplicationUser level.
modelBuilder.Entity<ApplicationUser>().Property(t => t.Name).HasMaxLength(10);
This way the database is in sync with your view validations and future controllers are scaffolded correctly.
You could just add a Model/ViewModel to handle this for you.
public class LoginViewModel
{
[Required(ErrorMessage="*")]
[StringLength(20, MinimumLength=5)]
public string UserName { get; set; }
[DataType(DataType.Password)]
public string Password { get; set; }
}
This way, in your view, you can notify the user that the length etc does not match.
Check out DataAnnotations here
EDIT
Is this what you are trying to do? I have not tested this code!
public class ApplicationUser : IdentityUser
{
public string UserName
{
get;
set
{
//your validation here
}
}
}
I'm currently developing a SPA in Angular, and so I've created a REST service using ServiceStack. I am also using ServiceStack's default authentication and authorization solution, which allows me to decorate services with the Authenticate attribute, and also allows me to authorize roles.
However, since my application has users, and users own resources, I need a way to restrict non-authorized users from performing certain actions. Furthermore, I would like to be able to create a single service for each discrete entity which can properly figure out what is safe to write to the database and what is safe to return to the user depending on their level of authorization.
So as an example, let's say I've created a service to handle operations on a Group entity. One of the actions I allow on a Group is to get the details for it:
Route: api/groups/{Id}
Response: Name, Description, CoverImageUrl, Members
However, depending on who the user is, I wish to restrict what data is returned:
Not authenticated: Name, CoverImageUrl
Authenticated: Name, CoverImageUrl, Decription
Member of requested group: Full access
Admin of website: Full access
So one simple approach to doing this is to create 3 different response DTOs, one for each type of response. Then in the service itself I can check who the user is, check on their relation to the resource, and return the appropriate response. The problem with this approach is that I would be repeating myself a lot, and would be creating DTOs that are simply subsets of the "master" DTO.
For me, the ideal solution would be some way to decorate each property on the DTO with attributes like:
[CanRead("Admin", "Owner", "Member")]
[CanWrite("Admin", "Owner")]
Then somewhere during the request, it would limit what is written to the database based on who the user is and would only serialize the subset of the "master" DTO that the user is permitted to read.
Does anyone know how I can attain my ideal solution within ServiceStack, or perhaps something even better?
The direct approach is the easiest, but you could also take advantage of custom filters attributes.
[Route("/groups/{Id}"]
public class UpdateGroup
{
public int Id { get; set; }
public string Name { get; set; }
public string CoverImageUrl { get; set; }
public string Description { get; set; }
}
[RequiresAnyRole("Admin", "FullAccess")]
[Route("/admin/groups/{Id}"]
public class AdminUpdateGroup
{
public int Id { get; set; }
public string Name { get; set; }
public string CoverImageUrl { get; set; }
public string Description { get; set; }
//... other admin properties
}
Service implementation:
public object Any(UpdateGroup request)
{
var session = base.SessionAs<AuthUserSession>();
if (session.IsAuthenticated) {
//.. update Name, CoverImageUrl, Description
}
else {
//.. only update Name, CoverImageUrl
}
}
public object Any(AdminUpdateGroup request)
{
//... Full Access
}
What ended up being the most pragmatic solution for me was actually pretty simple. The basic idea is that whichever service requires row-level authorization should implement a GetUserRole method, which in my case returns the user's most permissive role.
protected string GetUserRole(Domain.Group entity)
{
var session = SessionAs<AuthUserSession>();
var username = session.UserName;
if (session.Roles.Contains("Admin"))
{
return "Admin";
}
if (entity.Id == default(int) || entity.Leader.Username.Equals(username))
{
return "Leader";
}
// More logic here...
return session.IsAuthenticated ? "User" : "Anonymous";
}
Then I can use the user's role to figure out what to let them write:
var entityToWriteTo = ... // code that gets your entity
var userRole = GetUserRole(entityToWriteTo);
if (new[] {"Admin"}.Contains(userRole))
{
// write to admin-only entity properties
}
if (new[] {"Admin", "Leader"}.Contains(userRole))
{
// write to admin or leader entity properties
}
// Etc.
And the same logic applies for reads: You populate a DTO with properties set conditionally based on their role. Later on when you return the DTO back to the client, any properties that you haven't set either won't be serialized or will be serialized with a null value.
Ultimately, this solution allows you to use a single service for a resource instead of creating multiple services each with their own request DTO. There are, of course, refactorings you can do that makes this solution more streamlined. For example, you can isolate all of your reads and writes to one part of your code which will keep the services themselves free of role checks and things like that.
I'm designing a new website with ASP.NET MVC 4 (Beta), VS 11 (Beta), EF 5 (Beta), but this question suits for released versions of ASP.NET MVC 3, VS 2010, EF 4, too.
First step: I'm using Entity Framework Code First approach, for example, I've got following user model:
public class User
{
[Key]
public int UserId {get;set;}
public String LoginName { get; set; }
public String Password { get; set; }
}
Now, for registration I need another model, the registration model:
public class Registration
{
public String LoginName { get; set; }
public String Password { get; set; }
public String PasswordConfirm { get; set; }
}
This is where my problems begin: Where should I put my DataValidation Annotations? For example the password should be at minimum 10 characters long and the PasswordConfirmed must match Password and so on. Do I have to write this on every model which could do something with the password (I'm thinking of having a ChangePassword model, too)
Another thing is how to deal with the controller. When I display my Registration ViewModel and everything is fine, do I create a User model and assign the variables from Registration ViewModel to it?
Sometimes I've a lot of properties which go to database, but not shown to the user (foreign keys, calculated values etc.).
As thinkink on DRY, I don't want to repeat my self.
What is the best practice for this one?
To be clear: Annotations isn't a need. If there a better ways to validate, I will be glad, if you show them.
I can't say objectively which is 'the best practice', but here's how I see it.
If you're binding to the view model, verify the view model, so:
public class Registration
{
public String LoginName { get; set; }
[Required]
[StringLength(50, MinimumLength=10)]
public String Password { get; set; }
[Required]
[StringLength(50, MinimumLength=10)]
public String PasswordConfirm { get; set; }
}
You can either do the validation 'by hand' in the controller, check on the POST if the password and confirmation matches, if not add an entry to the ModelState (but that may cause code repetition and is a bit cumbersome) OR use nice IValidatableObject interface on the model:
public class Registration : IValidatableObject
{
public String LoginName { get; set; }
[Required]
[StringLength(50, MinimumLength=10)]
public String Password { get; set; }
[Required]
[StringLength(50, MinimumLength=10)]
public String PasswordConfirm { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext context)
{
if(Password != PasswordConfirm)
yield return new ValidationResult("Confirmation doesn't match", new[] {"PasswordConfirm"})
//etc.
}
}
Now with that, when you have your model bound after POST, the validation is done by simply calling ModelState.IsValid, and if it isn't valid, it returns the list of errors - including your custom errors.
Now of course you can put the DataAnnotations on the DB-model too as an additional measure, just 'in case' to avoid string truncation exceptions etc. if you somehow forgot and tried to push a longer string to the database anyway
As for the mapping, yes, after you have your model validated, at the end of the POST action you usually you map the properties from the model to either a new User instance (when adding to the DB) or to the existing one for update. You can use AutoMapper or write a naive mapper yourself using reflection - it's a relatively easy task, but it might be better to leave that as a stand-alone exercise, there is no point in reinventing the wheel.
You should create your entities only in domain layer. But when you need some DataValidation Annotations for your entity, you can use MvcExtensions for this. And if you have some composite or nested entities and you want to get them as a flatten objects, you should use automapper. This will be a best practice for you!