I am building an Application where alongside general public pages there will be a login page and 3 Dashboard Versions for each 3 role levels.
Table
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->string('firstname');
$table->string('surname');
$table->string('username');
$table->string('email')->unique();
$table->string('password', 60);
$table->string('role');
$table->rememberToken();
$table->datetime('created_at');
$table->datetime('updated_at');
});
With that i have another table Roles:
Schema::create('roles', function (Blueprint $table) {
$table->increments('id');
$table->string('role_type');
});
Relationship
Users::hasOne('roles');
Roles::hasMany('users');
Essentially on login function i want to check the users role_type and then redirect them based on the role.
I would like to know if this table structure and idea is correctly thought out.
Additionally when a user accesses a specific route i will have the route either display login if no user or 404/503 if user is logged in But does not match a specific role_type.
Thanks guys
On your users table instead of the role column you have, it should be these two lines:
$table->integer('role_id')->unsigned()->nullable();
$table->foreign('role_id')->references('id')->on('roles')->onDelete('set null');
The downside to this is it allows a null value for the 'role_id' column on users. The reason it needs this is to deal with what would happen if a Role that is assigned to a user is deleted.
But a better solution would be to use a many-to-many relationship, I personally would suggest using Entrust, since it has what you want built in, plus more options that you might want later.
Related
I can think of a couple of ways of achieving this (presuming for websites hosted on a Windows machine):
A) JavaScript side: Storing the authenticated user's accessibility role (e.g. Admin, Demo-User, ...etc) and basically rendering (or not rendering or disabling) relevant html elements/controls based on this role.
B) MVC side: Where the explanation in [A] is basically done on IIS and thus the views which are rendered via .CSHTML are manipulated based on the user's Role.
C) Combination of [A] & [B]: This is the most likely case.
Please, I would like the community's professional and experienced input on this matter.
I only use approach A, however in a different way.
As I use default simple membership in my apps, I just add some roles into the DB and add appropriate users to those roles.
Then, for filtering contents, I just do two jobs:
1) I filter controller request to appropriate roles by use of [Authorize] attrib:
[Authorize(Roles = "role1, role2, ...")]
2) I create a partial view to render the navigation bar/main menu. In that view, I first retrieve the roles of the current user:
var roles = Roles.GetRolesForUser(User.Identity.Name);
Then, according to his/her roles, I render menu items:
bool hasRole1 = roles.Contain("role1") | roles.Contain("admin");
// ...
#if (hasRole1)
{
<li>...</li>
}
I was trying to hide and show menu bar based on logged in user role. So i've written a code in razor view which is
#if ( Request.IsAuthenticated && HttpContext.Current.User.IsInRole( "Admin" ) ) {
<li>Projects link</li>
<li>Profile link</li>
}
and also this
#if (Roles.IsUserInRole( "Admin" ) ) {
<li>Projects link</li>
<li>Profile link</li>
}
I have tried both codes, it works but problem is Its not working for all admins. Its working for only one admin when totally 4 user have admin role.
And also same kind when i declaring another user role finance admin its working for a single user!
All other user its blocking the menu but the user roles is same for four users. I dont know how it getting only one user as admin when remaining three also same role.
Can any one explain where the method getting roles from data base and how it works?
The IsInRole method (and all other methods) are stored procedures in your database. In your database, you have the MemberShip tables. The Stored Procedures work on those tables. If you say that the code will work for one user that has the Admin role connected, the first thing I would check is if the other users where it won't work will really have that role. Check the table for all the user and role connections in your database.
Check your webpages_UsersInRoles table in your database, as this is what governs which roles are attached to which user profiles.
Perhaps there is also an issue with roles being assigned when a user is created. Check your register method on the account controller. You should have a line like this:
Roles.AddUserToRole(model.UserName, model.userRole);
If not then roles may not be assigned when a user is created.
When it comes to display a view regarding to authentication (view displayed depending to the visitor if he's a user or not). I face many choices. So I need your help to show me how i deal with such situation :
Using 2 views (one for the users and other for visitors), or just one view.
using 2 actions (one with authorize filter and the other without), or just one action.
And why the choices you suggest is better ?
You don't have to not use Authorize attribute. It's main function is to setup the User in the context, and then by default, it also checks that they are logged in. However, this last part can be overridden by using the AllowAnonymous attribute as well:
[Authorize]
[AllowAnonymous]
public ActionResult SomeView()
{
...
}
So, now your view will have a User to play with, and you can dynamically present different pieces of the view using that based on auth status:
#if (User.IsAuthenticated)
{
<p>Logged in</p>
}
else
{
<p>Anonymous</p>
}
EDIT (for clarification)
The Authorize attribute actually does two distinct things for you. First, it setups all the machinery for recognizing a user: reads the cookie or whatever, checks the authentication status, pulls in the user's info, if they are authenticated, etc. Second, it validates that the user is in fact logged in. Using AllowAnonymous skips this second part and allows anyone, logged in or not, to access the view, BUT and this is key, you still need the first part to know stuff like whether you have an authenticated user or not.
So, simply, using both the Authorize and AllowAnonymous attributes together means essentially, "see if the user is logged in, but don't require it to access this view". That allows anonymous users to still reach the page, but enables you to still deliver unique or different content to an actual logged in user.
Is there a way to retrieve all access rules from a specific Role?
As roles are just flagged at the top of an action or on top of the whole class I canĀ“t find a way to retrieve this information unless I read and parse the whole file and after that find a way to link this [authorization] tag to a group.
Thanks
No there is no builtin way. Its even impossible, because you might check for Roles in your code (actions/views) as well.
And how should the list of access rules be returned?
For example, how should an algorithm return / name this access rule in a view:
#if(User.IsInRole("SomeRole") {
<div>
Show some html only visible for users in SomeRole
</div>
}
You have to administer the list of your application defined access rules by yourself - i list will be very specific for your app.
Of cause, when you just use the Authorize attribute, you could generate a list of action methods accessible for a given role by reflecting over all controller classes.
I am building a Rails 3 app and I am working on a design for a sophisticated user permissions tool where a Company user determines specific roles for each PM.
Imagine this scenario - the Company wants to establish specific roles over three types of data.
Project table
Client table
Corporate Account (i.e. Company table)
I am thinking of adding a Role polymorphic table with these fields:
user_id (the user this role applies to, unless all_users == true)
item type (such as "Project", "Client", or "Company", unless all_items == true)
item id (as above)
role (such as "read", "edit", "destroy", or even "custom")
all_users (boolean: does this item's role apply to all users)
all_items (boolean: does this user's role apply to all items)
company_id (the company who 'owns' this role)
I feel that CanCan would be a nice lean way of accomplishing this, but here's my question. 1. Is the above table a good way to do this? 2. Could CanCan tie in with this to create an effective solution?
Your table seems like a sensible way to implement a very complicated authorization scheme, which seems to be what you're after.
As far as CanCan goes, yes it will tie in perfectly with this. All CanCan does is provide you with the ability to define authorization on actions, models, etc. according to certain criteria. These criteria could be anything (e.g. day of the month, etc.) but are usually tied to roles. So all you'll have to do is specify the authorization rights according to the information in your Role table and the specific model instance that is going to be evaluated.