In an MVC app, administrator has a CRUD controller for managing users. Now, the functionality of the edit part needs to be extended and it involves adding a number role dependent tabs. They depend on the role of the viewed user, rather than on roles of the administrator who is viewing them. The easiest way for achieving this, would be getting all roles of that user as a array of strings (or similar), but how do I actually go about obtain those.
Is there a preferred method of getting all roles of a single user in SimpleMembership (based on his UserId) or do I just have to patch up a stored function in the database and pull those through it?
Writing the function is not a big deal, but this problem doesn't sound like something I should have to make workarounds for.
Use the Roles.GetRolesForUser() method https://msdn.microsoft.com/en-us/library/8h930x07(v=vs.110).aspx
string[] rolesArray = Roles.GetRolesForUser("username");
With the string being the User Name of the user as contained in the aspnetdb.
If you want to find by using a guid, you could try the following:
Guid userId; // ID of user - you can populate this somehow
MembershipUser memUser = Membership.GetUser(userId);
string[] roles = Roles.GetRolesForUser(memUser.UserName);
Here is the stored procedure I mentioned in the question:
CREATE FUNCTION GetUserRoles
(
#UserId int
)
RETURNS TABLE
AS
RETURN
(
SELECT
r.RoleName
FROM
dbo.webpages_UsersInRoles uir
JOIN dbo.webpages_Roles r ON (r.RoleId = uir.RoleId)
WHERE
uir.UserId = #UserId
)
GO
The only reason to go with this instead than the answer by user1666620, would be if you wanted to skip one unnecessary query to the DB. The preferred method to use this solution would be to add this function to your dbml (or it's EF equivalent). Obviously this first needs to be added in the database.
Related
I would like to add an option that user using web ui can define some views in our product.
We let super admins put in SQL query that would create that view.
Do you know if there are any tools for parsing SQL Query and check if it is valid SQL Query for only creating view?
I assume the input is secure, so your superusers are not going to try to inject stuff ;-)
Anyway the comment above is correct, at least you should check for semicolon and comments. Also that the string starts with "SELECT "
The easiest way - after this basic checks - would be to let them insert the SELECT-Query alone and test it on your connections. Then catch any exception and display it to the superuser.
In case of success, you could even display some of the result, in order give them the possibility to validate the query.
After that you prefix in your code the SELECT with "CREATE VIEW AS " in order to create the view on your database.
One possibility is to create a unique role that has select access on every table in the database but nothing else. Then have your C# run the query as that user in a try/catch block. This would even eliminate the possibility of SQL injection and/or provide a failsafe for well meaning but careless users.
The main disadvantage I see is that you would need to continually update permissions to ensure that the user is granted select access to new objects, but I think you can define those types of cascading permissions at the schema level... never tried it at the database level.
Force the query to begin with “CREATE VIEW”, e.g. by prefixing whatever is entered with that string.
Make sure that there is no semicolon inside the query. This will exclude some valid queries (that contain something like “WHERE a = ';'” or “/* comment; */”), but it is simple and you might get away with it.
I'm not even sure how to search for this question, so forgive me if I'm asking a duplicate question and would be grateful for any redirection needed.
I have data (Account Number, Password, Internal Y/N) that is being submitted to an Account Table from Navision. I want to use this data to automatically create a user in the UserProfile table (Username = Account Number, Password = Password) and assign that user to the Admin role if Internal = Y and DealerAdmin if Internal = N.
The data will continue to be maintained for Account numbers in Navision, but the DealerAdmin can add additional users from the website. Is this possible? If so, please provide any pointers to tutorials as to where to start? I presume it's a simple SQL statement. Where do I add this code in MVC so that it gets updated every time there's new data in the Account Table?
If you are using SQL why not use a trigger to create a new record in your User UserProfile when your conditions are met?
If this does not work for you can take a look at the post below and call your proc to move the data over if needed.
ASP.NET MVC 4 intercept all incoming requests
I have stored the user profile in another table, called Agent. The Agent table does not contain any navigation property since i couldn't find a way to store user id in the Agents table( in the examples from msdn, even they didn't do it).
An Agent has many packages, and now i have a create packages view. I wanted to store the logged in Agent's ID to get stored in the Packages. So in the package controller in the Post Create actionResult, i'm doing something like this:
var user = adb.Users.Where(p => p.Id == User.Identity.GetUserId()).Single();
var agent = db.Agents.Where(p => p.ID == user.Agent.ID).Single();
(I have 2 datacontext, one from the application user, and one i got from datafirst EF, i tried merging them, but i got errors.)
I am getting errors.
System.InvalidOperationException
The Enumerable.Single returns the only element of a sequence, and throws an exception if there is not exactly one element in the sequence. It throws InvalidOperationException , because the input sequence contains more than one element OR the input sequence is empty.
Instead of using Enumerable.Single, I would recommend using SingleOrDefault. This method returns null if there are no elements in the Enumerable rather than InvalidOperationException. You can then check for null value and take appropriate action if there is no entry in the Enumerable.
Ref https://msdn.microsoft.com/en-us/library/vstudio/bb342451(v=vs.100).aspx
I think the problem is in tables data (Users, Agents).
If you search by Id, I hope it's a key for tables, so I decided that you didn't add same records in one table, so we can remove variant that there are duplicates. If you use User.Identity.GetUserId() it's give background for decide that your user account already exist and the data in Users table is normal. InvalidOperationException in those places you can get if there are duplicates or data not exist. Variants with duplicates is left and I hope you use ID like key for table, so your problem is: You haven't any users in Agent table with ID which you get from user.Agent.ID. Two ways: wrong data in Agent or you get incorrect Id from user.Agent.ID(maybe problem in mapping). Try to create new User and new Agent for him and run your code. Are you sure that for all users should be an agent?
I'm working on an application that has to manage permissions, and I've come up with a design I wanted some feedback on. I'm not sure if this is exactly the right place to post it but I guess we'll see.
A user in my application can be assigned permissions. They can have permissions on an individual level, or from being part of a group. Thus I have the following tables (I think the names are relatively self-explanatory but can add further information if needed):
Users
Permissions
User_Permissions
Groups
User_Groups
User_Group_Permissions
The design of the permissions table is this:
id int (permission id, primary key)
name varchar(255) (name of the permission, such as "ADMINISTRATION")
description varchar(1000) (A short description of the permission)
default_value tinyint (The default value to assign to users (Yes/No/Never))
However, when I check the permission in code, I didn't want to use a "Magic String" so I created an enum for the permissions in my permissions table, and then use it like so:
public enum EPermission
{
ADMINISTRATION = 1,
LOGIN = 2
}
public bool HasPermission(EPermission permission)
{
int permission_id = (int)permission;
//look up the permission in the database based on permission_id
}
The ids in my permissions table match the number values I've assigned in my enums. The application has no way of changing these. The permissions in the permissions table are inserted with those ids as part of the installation and should not be changed.
Is this kind of coupling acceptable? I'm not expecting the data to change, but it's always possible that it could, and I'm just wondering if there might be a better way to do things before I get too deep into this.
Yes it is "acceptable" and a fairly common practice.
EDIT: If you wanted to really minimize the chance that your DB and the enum will become out of sync, you can reflect the enum to seed your table with data during deployment.
As you do not change the Permissions you can also get away from the permissions table and only use the enum. You can then store the value of the enum as an int in the User_Permissions and User_Group_Permissions tables.
When retrieving the data from the database you can deserialize the value to the enum. This reduces the possibility that the data in your database gets corrupted and does not match with your enum anymore.
I suspect that it will not help long run. what If a single user can have one or more permissions. Then you need to switch flag enum?
In SimpleMembership there isn't any column in the database for a user to be locked/unlocked.
I basically need my administrator to enable or disable any user in my application.
Is there any alternatives to that?
I find it easiest to use Roles to do this. Have a ActiveUser role and tag your controllers or actions with a Authorize attribute.
[Authorize(Roles = "ActiveUser")]
Then some simple admin to add or remove users from the role to unlock and lock their access to everything protected with that roles attribute.
Roles.AddUserToRole(user.Username, "ActiveUser");
Roles.RemoveUserFromRole(user.Username, "ActiveUser");
Probably not the "approved" way of doing things, but this is how I do it.
There is a field within the webpages_Membership table called IsConfirmed. Typically, this is for when you want a 2-stage registeration process: sign-up then activate via a link within an email. By nature though, this field has the same affect as IsApproved within the former aspnet_Membership table: if set to true, a user can login; if false they can't. So I just use plain old SQL to set to true or false:
// If using EntityFramework
// 1. Setup my params
var params = new List<SqlParameter>() {
new SqlParameter("#UserID", 1),
new SqlParameter("#Activate", true) // or false
};
SqlParameter[] paramArray = params.ToArray();
// 2. Update the database
myDbContext.Database.ExecuteSqlCommand("UPDATE webpages_Membership SET IsConfirmed = #Activate WHERE UserId = #UserID", paramArray);
I haven't tried simplemembership yet, but this sound great for some of the small projects I am working on. Here are some options:
Option 1: Add a custom field to the table like shown here - http://www.dwdmbi.com/2012/10/adding-custom-fields-to-vs2012-mvc4.html
Option 2 Create a new table with a foreign key back to User. Do an additional check on this value.
Either way your are going to something extra for the check. You can customize the 'Authorize' attribute to include your check (instructions here - Override Authorize Attribute in ASP.NET MVC).
try this approach. It uses IsApproved rather than the IsLockedOut. If your implementation does not already use IsAproved, this would be a good solution.
MembershipUser user = Membership.GetUser(username);
user.IsApproved = false;
Membership.UpdateUser(user);
This is not exactly locking the user. Technically this call is taking approved status from the user and leaving them unable to log-in.
I dont know the technology you are using but either you have to give column in the table with lock unlock as you specified or siply add one table in the database(Say tlbDisable) where you can delete the entries in original table and insert it in new table(tlbDisable).
When you again want to enable that user then simple delete the entry from tlbDisable and insert it into original user table.