Extending a User class to subclasses or having a field in the class that denotes user type? - software-design

I'm making a small record application for school work that has a login system with different user types. Each user type will have have different permissions on the app. Is there anything wrong with me having an int field in the User class that varies depending on permissions? E.g. 0 would have all access, 1 slightly less, etc.
Is there anything wrong with approaching the task like this instead of extending the default User class to other types of User?

A better way would be to model the permission as enum
enum Permission {
FULL_ACCESS, RESTRICTED, NO_ACCESS;
}
public class User {
//other fields
private Permission permission;
}
Edit: The above example was demonstrated in Java. You can have it changed to the way your language allows it to.

Related

How to map entity associations with doctrine 2 to retrieve specific data?

Introduction:
The title of the question is a bit generic because I was not able to make a more specific one, but now I will try to give a better description of my problem.
It's my first big project with Symfony (>=3.*) and Doctrine ORM (>=2.5) and I hope to get some tips about what to keep in mind to improve my understanding about modelling entity associations.
Minimized Use Case (ps: CodeStyled words are Doctrine Entities):
I have the AccountType entity where are defined 4 account types.
A User can register his credentials and must choose one AccountType.
I have 5 profile types in the relative entities ProfileOne, ProfileTwo, ProfileThree, ProfileFour, ProfileFive.
The User with AccountType:A can create only 1 ProfileOne and only 1 ProfileTwo.
The User with AccountType:B can create unlimited ProfileOne and ProfileTwo.
The User with AccountType:C can create unlimited ProfileFour.
The User with AccountType:D can create only 1 ProfileFive.
Actual Entity Associations:
User have a unidirectional OneToOne with AccountType.
The Question (UPDATED):
I'm forced to manage the logic outside (es: in a repository) or exist a way to map entities to retrieve the right data based on the AccountType (as showed in the use-case)?
Maybe I've to create a ProfileAccountA, ProfileAccountB, ProfileAccountC and a ProfileAccountD, where to store the relative associations based on the AccountType to then be able to have something like $profile = $user->getProfile() where inside the function getProfile() I manage the logic to returns the right data (like in a Factory class)? If Yes, is this a common and valid approach or there are better alternatives for this use-case?
Create a class for each account type (eg.: AccountTypeA, AccountTypeB, etc.). The properties, associations, and rules that tell which and how many profiles a User can have should be encapsulated in those classes.
Your associations will look like this: User has an (oneToOne) Account that has one or more (oneToMany) Profile
You will probably want an AccountInterface:
interface AccountInterface
{
public function getProfiles(): Collection;
}
An example of an Account class. It's better naming them accordingly to their nature (FreeAccount, MasterAccount...):
class MasterAccount implements AccountInterface
{
private $masterProfile;
private $expirationDate;
private $anotherAccountRelatedProperty;
public function getProfiles(): Collection
{
return new ArrayCollection([$this->masterProfile]);
}
}
Any property, association, or behavior related to the account should live in these classes.
In order to get the User profiles it should delegate to the account:
//User class
private $account;
public function getProfiles(): Collection
{
return $this->account->getProfiles();
}
This is a decent OOP approach to be used as guideline in your situation.

ASP.NET Identity - what the difference between UserName and Id in IUser interface?

We are working on an application which uses ASP.NET Identity (v 1.0). We defined an User class that implements the IUser interface. Our repository class UserRepository implements IUserStore.
Now when I call UserManager.CreateAsync(user, password) it calls FindByNameAsync() method of UserRepository to check (I guess) if this new user has an unique ID.
However I don't understand why it calls this method instead of FindByIdAsync?
I supposed that the UserName property on the IUser interface is something like person name (e.g. "John Smith") and Id is an internal unique identifier of an user.
From this default implementation I guess I was wrong.
The question is: why do we need these two properties (Id and UserName) on the IUser interface in this case? What the difference between them? Which of them is supposed to be an unique ID?
ID's are typically numbers, although the default implementation of Identity uses Guid's. Name is username, typically a handle or shortening of a full name. Often times this is an email address, depends on how you set it up.
Id's are used as primary keys in your database. Names are not. The reason is that you might delete a user with a given username, and another use might come along and want to create an account with the same name. But, you still need a way to identify that these are two different users for auditing and historical reasons.
When creating a user, how exactly would the code know the userid to look it up? The username is the only thing it knows...
They're both unique. Createasync calls findbyname as you're not going to know an Id for a user that you're going to create as it doesn't exist yet.
FindByID Exists as it's quicker to do a lookup on that after you've created a user.

Which is the best? Roles based App or Table per Type?

I'm recently working on an application that requires 2 user types. Physicians and General Users. They share some attributes (for example Username, Password, FirstName, LastName, Gender, etc).
But Physicians also need some other attributes that General Users does not have it. Fore example Physicians may have Speciality and WorkingPlace. I found that I should use Table Per Type Inheritance (TPT) in Entity Framework. I created a abstract base class named People, also I created two subclass named (RegisteredUser and Phisycian) inherit from People abstract class.
I Also found that the default Membership Provider in ASP.NET is not suitable for my needs. So I developed a CustomMembershipProvider class that can now work with Table per Type inheritance in Entity Framework.
But I think that it can be very better that I use Roles instead of Table Per Type inheritance. So I want to change my application for using Roles. But the problem is that how can I handle different attributes for Phisycians and General Users? I need a solution that can handle multiple profile fields for multiple User roles. For example if a User is in Physician role, he should have Speciality and WorkingPlace attributes.
Can anyone help me?
How about using Simple Membership with Roles?
You can use Custom Attributes for the specific User Types (Physicians, GeneralUsers ) like so.
public class PhysicianProfile : ProfileBase
{
public string WorkingPlace {
get { return this["WorkingPlace"]; }
set { this["WorkingPlace"] = value; }
}
}

ASP.NET MVC Authorisation with CRUD roles

I need the ability to restrict what users can do in my application based on dynamic roles for CRUD.
For example the User/Index would need an authentication such as [ClaimsAuthorize("View", "User")] as oposed to [Authorise(Roles="Administrator")] so that I can check if the user has the security to view.
I have the user roles configured, but what the roles enable users to do is dynamic. An administrator can change the security levels with check boxes that will enable different security groups to do different things.
The main problem is doing this in Razor, I need something similar to #User.CanEditUsers, but I am not sure how I can go about doing this at all.
Any help would be greatly appreciated as I am having trouble finding the correct way to go about this.
Note that Authorizing users to see specific page elements differs from Authorizing for CRUD or other database operations, unless the elements point to operational Actions in Controller. Consider that you may have some elements that there's no need to be saw by a specific user, and don't have specific database operation. Till now we conclude that we need the following permissions :
Permission to See
Permission to Command
I believe that you can use Microsoft Role Provider for both parts. According to MSDN Documentation Considering that :
The Authorize attribute lets you indicate that authorization is
restricted to predefined roles or to individual users. This gives you
a high degree of control over who is authorized to view any page on
the site.
In The next step/question is how to do that?
I think 3 ways are available to meet our purpose:
Solution 1: Creating separate Views with specific page elements due to forwarding each user to related View. In this scenario we must
create separate controller actions too. we have to check user types
before each action like [Authorise(Roles="Administrator")]. We
forced to have static (Pre-defined) Roles and Accessibility. And in
one sentence Not a good solution because of redundancy and
instability.
Solution 2: Creating pages Dynamically simply by adding some if conditions for each access restricted element in One Page(for
example Edit Page). That is like employing #if
(User.IsInRole("Admin")) to authorize specific users and show
related page elements like buttons. In Controller side we can use
if conditions (not as FilterAttribute due to add dynamic
functionality based on generated/added new roles) and control valid
transactions against database. Although FilterAttributes add some great functionalists (like performance optimization). In one sentence A moderate solution.
Solution 3: Act like solution 2, just fix Controller problem by
creating our own custom FilterAttribute for authorization. That will
inherited from AuthorizeAttribute and overrides the OnAuthorize
method to do what you need only for Operations.
For Example :
public class TableAuthorizeAttribute : AuthorizeAttribute
{
public enum TableAction
{
Read,
Create,
Update,
Delete
}
public TableAction Action { get; set; }
public override void OnAuthorization(AuthorizationContext filterContext)
{
base.OnAuthorization(filterContext);
//do custom authorizization using Action and getting TableEntryID
//from filterContext.HttpContext.Request.QueryString or
//filterContext.HttpContext.Request.Form
}
}
And its usage will be like this :
[TableAuthorize(Action=TableAuthorizeAttribute.TableAction.Update)]
Here is complete example about above concept. Here is complete example for creating dynamic AuthorizeAttribute for authorizing new roles added to application.
Solution 3 in one sentence A perfect but Complex Solution.
Note that by using FilterAttribute before Actions we have limited our application to static/predefined roles. No need to use another Data Structure or generate tables in Database.
You need to separate the concept of roles from groups in your design.
A role gives fixed permissions to perform certain actions in your application. A group is a set of users. What your administrator is really doing is to assign groups of users to different roles.
Your authorization code should be able to rely on fixed roles, e.g. an "ViewUserInfo" role. Then implement the administration interface so that when the admin enables a user to view userinfo, you add that user to the "ViewUserInfo" role.
The same goes with groups: If an entire user group is granted the right to view user info you should add that group to the "ViewUserInfo" role. To introduce the concept of groups and be able to add groups to roles you can't rely on the standard SimpleRoleProvider, so you probably have to implement your own role provider as well as a group provider.
In the end some workaround might be easier, but this is, in my opinion a cleaner architecture.
From the horse's mouth: "Role management helps you manage authorization, which enables you to specify the resources that users in your application are allowed to access. Role management lets you treat groups of users as a unit by assigning users to roles such as manager, sales, member, and so on." (ref: http://msdn.microsoft.com/en-us/library/5k850zwb%28v=vs.100%29.aspx)
Users can be in multiple roles, and you can leverage action filters to get fine-grained control of access to the various resources in your site:
[Authorize(Roles="Contributor, Designer, Reviewer")]
I think the "dynamic" aspect you are after revolves around Administrators being able to add and remove users on-demand from the roles which provide access to those resources, which is pretty typical.
The idea of constantly changing the permissions your roles grant would be a bad design choice.

Custom fields in ASP.Net Login/Register?

I have to edit the Login/Registration that ASP provides to include a custom dropdown ("BranchID") menu that saves to the database so each user has its own Branch. I am using ASP Membership system, and of course it saves to the ASPNETMDF database it creates. Googling has net me some results but I am quite confused. I know there are "User Profiles", and I I can save this Profile data, but what I am not quite sure is if its a temporary measure or if it does record to the database.
I could make my own custom membership system, use the built it and adapt it or use the user profiles. What is the best course of action? I'd vastly prefer to adapt/edit the built in Membership system and add the data I require to it but I still don't haven't a clear answer to what I should do or what's best.
You have two choices:
Create a CustomMembershipProvider , and if you need to a CustomRoleProvider, you can do this by implementing .NET's MembershipProvider. Sample: http://www.codeproject.com/Articles/165159/Custom-Membership-Providers
Create a separate table that stores additional user information, i.e., "BranchID", and add a one-to-one relationship between your table and .NET's Membership
It's really up to you which one you choose.
MembershipProvider is pretty easy to extend. Assuming the branch is something they have to select to authenticate? You should be able to extend authenticate to do something like:
public class MyCustomMembershipProvider : MembershipProvider
{
/*
....
*/
public bool ValidateUser(string username, string password, string branch)
{
return (::ValidateUser(username, password) && MyCustomRoutine(username, branch));
}
}

Resources