how implement exiting authentication roles in the database into AspNet IdentityRole - asp.net

i've asp mvc application , database first , i have a table to hold my roles another for my users and junction table user_role.
i added the following class to my app
Microsoft.AspNet.Identity.Owin
Microsoft.AspNet.Identity.EntityFramework
Microsoft.Owin.Host.SystemWeb
can i use my existing tables to apply the roles to my controllers
[Authorize(Roles = "Admin")]]
public ActionResult MySecretAction() {}
or maybe
[Authorize(Roles = MyDBEntities.Roles.Find(1)]]
public ActionResult MySecretAction() {}
thank you

Can I use existing roles from db table?
Yes you can use existing roles from database.
You can use [Authorize(Roles = "Admin")], but not [Authorize(Roles = MyDBEntities.Roles.Find(1)] as it is not constant value, but dynamic.
But how can I add and remove roles to my existing tables when I assign a role to a user?
To add new role(s) you have to use RoleManager class with CreateAsync method along with other methods for managing roles used by your app.
When i add a role to a method , and the user is not authorized to use it , the application redirects him back to the login page ,where to change this?
To alter behavior during athorization you have to implement own Authorization attribute inherited from AuthorizeAttribute and override OnAuthorization method.
public class AuthorizeRoleAttribute : AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
// User is not authenticated(NOT logged in)
// we are letting ASP.NET to use standard procedure => redirect her/him to login page
if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
{
base.HandleUnauthorizedRequest(filterContext);
}
// User is authenticated(logged in)
// we are going to show her/him custom view with error
else
{
// Don't forget to create Unauthorized.cshtml view in Shared folder
filterContext.Result = new ViewResult
{
ViewName = "~/Views/Shared/Unauthorized.cshtml"
};
}
}
}
Then you have to use your custom AuthorizeRoleAttribute instead the default one.
[AuthorizeRole(Roles = "Admin")]]
public ActionResult MySecretAction() {}
Resources:
RoleManager class
Implementing RoleManager in ASP.NET MVC 5
ASP.NET MVC 5 Identity: Extending and Modifying Roles

I've created a costume authorization class , witch i can user to access the logged in user and my databases tables
using System;
using System.Web;
using System.Web.Mvc;
using Microsoft.AspNet.Identity;
using System.Linq;
using System.Collections.Generic;
using LoanApp.Models.DataBaseModel;
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
public class DynamicAuthorize : AuthorizeAttribute
{
// public string DefaultURL { get; set; }
protected override bool AuthorizeCore(HttpContextBase context)
{ return true;
}
}

Related

Net core custom user property

I'm using the default authorization in my .NET Core project. I want to check if an user is admin so in ApplicationUser.cs model I've added this:
public class ApplicationUser : IdentityUser
{
public bool admin { get; set; }
}
I migrated these changes into my SQL database and I can see the 'admin' property inside the AspNetUsers table. How do I check the 'admin' property of the currently logged in user?
You can access the current user instance through the UserManager<T> object, which can be injected into your controller as a constructor parameter. The method GetUserAsync takes a ClaimsPrincipal, which in this case is the User of the HttpContext.
private readonly UserManager<ApplicationUser> _userManager;
public HomeController(UserManager<ApplicationUser> userManager) {
_userManager = userManager;
var user = _userManager.GetUserAsync(HttpContext.User);
}
I agree with the above answer by Peter to just use the user variable and check for user.admin, however, I strongly suggest extending your project to use a simple Role-based Authorization to simplify things in the long run. You can achieve this with the following documentation: https://learn.microsoft.com/en-us/aspnet/core/security/authorization/roles

How can I get user and claim information using action filters?

Right now I am doing this to get the information I need:
In my base controller:
public int roleId { get; private set; }
public int userId { get; private set; }
public void setUserAndRole()
{
ClaimsIdentity claimsIdentity;
var httpContext = HttpContext.Current;
claimsIdentity = httpContext.User.Identity as ClaimsIdentity;
roleId = Int32.Parse(claimsIdentity.FindFirst("RoleId").Value);
userId = Int32.Parse(User.Identity.GetUserId());
}
In my controller methods:
public async Task<IHttpActionResult> getTest(int examId, int userTestId, int retrieve)
{
setUserAndRole();
I wanted the roleId and userId to be available and populated in the constructor of my class but from what I understand the constructor fires before authorization information is available.
Can someone tell me how I could do this with an Action Filter? Ideally I would like the Action Filter to be at the controller level but if not then could it be done at the method level.
I am hoping for some good advice and suggestions. Thank you
Update to show System.Web.Http
#region Assembly System.Web.Http, Version=5.2.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
// C:\H\server\packages\Microsoft.AspNet.WebApi.Core.5.2.2\lib\net45\System.Web.Http.dll
#endregion
using System.Threading;
using System.Threading.Tasks;
using System.Web.Http.Controllers;
namespace System.Web.Http.Filters
{
//
// Summary:
// Represents the base class for all action-filter attributes.
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public abstract class ActionFilterAttribute : FilterAttribute, IActionFilter, IFilter
{
//
// Summary:
// Initializes a new instance of the System.Web.Http.Filters.ActionFilterAttribute
// class.
protected ActionFilterAttribute();
//
// Summary:
// Occurs after the action method is invoked.
//
// Parameters:
// actionExecutedContext:
// The action executed context.
public virtual void OnActionExecuted(HttpActionExecutedContext actionExecutedContext);
public virtual Task OnActionExecutedAsync(HttpActionExecutedContext actionExecutedContext, CancellationToken cancellationToken);
//
// Summary:
// Occurs before the action method is invoked.
//
// Parameters:
// actionContext:
// The action context.
public virtual void OnActionExecuting(HttpActionContext actionContext);
public virtual Task OnActionExecutingAsync(HttpActionContext actionContext, CancellationToken cancellationToken);
}
}
Based on your method signature (and later comments below) the code assumes that you are using Web API and not MVC although this could easily be changed for MVC as well.
I do want to specify that if you look purely at the requirements its how can I create a maintainable piece of code that is reused. In this case the code gets claims based information and injects it into your controllers. The fact that you are asking for a Filter is a technical requirement but I am also going to present a solution that does not use a Filter but an IoC instead which adds some flexibility (IMHO).
Some Tips
Try to always use interfaces when/where possible. It makes for easier unit testing, easier to alter the implementation, etc. I will not go into that all here but here is a link.
In WebAPI and also MVC do not use the System.Web.HttpContext.Current. It is very hard to unit test code that makes use of this. Mvc and Web API have a common abstraction called HttpContextBase, use this when possible. If there is no other way (I have not seen this yet) then use new HttpContextWrapper(System.Web.HttpContext.Current) and pass this instance in to what ever method/class you want to use (HttpContextWrapper derives from HttpContextBase).
Proposed Solutions
These are in no particular order. See end for a basic pro list of each solution.
Web API Filter - exactly what you are asking for. A Web API action filter to inject the claims based information into your Web Api methods.
IoC/DI - A very flexible approach to injecting dependencies into your Controllers and classes. I used AutoFac as the Di framework and illustrate how you can get the claims based info injected into your controller.
Authorization Filter - Essentially an extension on solution 1 but used in a manner in which you can secure access to your Web API interface. As it was not clear how you wanted to use this information I made the jump in this proposal that you wanted it to ensure the user had sufficient privileges.
Common Code
UserInfo.cs
This is common code used in both solutions that I will demo below. This is a common abstraction around the properties / claims based info you want access to. This way you do not have to extend methods if you want to add access to another property but just extend the interface / class.
using System;
using System.Security.Claims;
using System.Web;
using Microsoft.AspNet.Identity;
namespace MyNamespace
{
public interface IUserInfo
{
int RoleId { get; }
int UserId { get; }
bool IsAuthenticated { get; }
}
public class WebUserInfo : IUserInfo
{
public int RoleId { get; set; }
public int UserId { get; set; }
public bool IsAuthenticated { get; set; }
public WebUserInfo(HttpContextBase httpContext)
{
try
{
var claimsIdentity = httpContext.User.Identity as ClaimsIdentity;
IsAuthenticated = httpContext.User.Identity.IsAuthenticated;
if (claimsIdentity != null)
{
RoleId = Int32.Parse(claimsIdentity.FindFirst("RoleId").Value);
UserId = Int32.Parse(claimsIdentity.GetUserId());
}
}
catch (Exception ex)
{
IsAuthenticated = false;
UserId = -1;
RoleId = -1;
// log exception
}
}
}
}
Solution 1 - Web API Filter
This solution demos what you asked for, a reusable Web API filter that populates the claims based info.
WebApiClaimsUserFilter.cs
using System.Web;
using System.Web.Http.Controllers;
namespace MyNamespace
{
public class WebApiClaimsUserFilterAttribute : System.Web.Http.Filters.ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
// access to the HttpContextBase instance can be done using the Properties collection MS_HttpContext
var context = (HttpContextBase) actionContext.Request.Properties["MS_HttpContext"];
var user = new WebUserInfo(context);
actionContext.ActionArguments["claimsUser"] = user; // key name here must match the parameter name in the methods you want to populate with this instance
base.OnActionExecuting(actionContext);
}
}
}
Now you can use this filter by applying it to your Web API methods like an attribute or at the class level. If you want access everywhere you can also add it to the WebApiConfig.cs code like so (optional).
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Filters.Add(new WebApiClaimsUserFilterAttribute());
// rest of code here
}
}
WebApiTestController.cs
Here how to use it in a Web API method. Note that the matching is done based on the parameter name, this has to match the name assigned in the filter actionContext.ActionArguments["claimsUser"]. Your method will now be populated with the added instance from your filter.
using System.Web.Http;
using System.Threading.Tasks;
namespace MyNamespace
{
public class WebApiTestController : ApiController
{
[WebApiClaimsUserFilterAttribute] // not necessary if registered in webapiconfig.cs
public async Task<IHttpActionResult> Get(IUserInfo claimsUser)
{
var roleId = claimsUser.RoleId;
await Task.Delay(1).ConfigureAwait(true);
return Ok();
}
}
}
Solution 2 - IoC / DI
Here is a wiki on Inversion of Control and a wiki on Dependency Injection. These terms, IoC and DI, are usually used interchangeably. In a nutshell you define dependencies, register them with a DI or IoC framework, and these dependency instances are then injected in your running code for you.
There are many IoC frameworks out there, I used AutoFac but you can use whatever you want. Following this method you define your injectibles once and get access to them wherever you want. Just by referencing my new interface in the constructor it will be injected with the instance at run time.
DependencyInjectionConfig.cs
using System.Reflection;
using System.Web.Http;
using System.Web.Mvc;
using Autofac;
using Autofac.Integration.Mvc;
using Autofac.Integration.WebApi;
namespace MyNamespace
{
public static class DependencyInjectionConfig
{
/// <summary>
/// Executes all dependency injection using AutoFac
/// </summary>
/// <remarks>See AutoFac Documentation: https://github.com/autofac/Autofac/wiki
/// Compare speed of AutoFac with other IoC frameworks: http://nareblog.wordpress.com/tag/ioc-autofac-ninject-asp-asp-net-mvc-inversion-of-control
/// </remarks>
public static void RegisterDependencyInjection()
{
var builder = new ContainerBuilder();
var config = GlobalConfiguration.Configuration;
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.RegisterControllers(typeof(DependencyInjectionConfig).Assembly);
builder.RegisterModule(new AutofacWebTypesModule());
// here we specify that we want to inject a WebUserInfo wherever IUserInfo is encountered (ie. in a public constructor in the Controllers)
builder.RegisterType<WebUserInfo>()
.As<IUserInfo>()
.InstancePerRequest();
var container = builder.Build();
// For Web API
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
// 2 lines for MVC (not web api)
var resolver = new AutofacDependencyResolver(container);
DependencyResolver.SetResolver(resolver);
}
}
}
Now we just have to call this when our application starts, this can be done in the Global.asax.cs file.
using System;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.Http;
namespace MyNamespace
{
public class Global : HttpApplication
{
void Application_Start(object sender, EventArgs e)
{
DependencyInjectionConfig.RegisterDependencyInjection();
// rest of code
}
}
}
Now we can use it where ever we want.
WebApiTestController.cs
using System.Web.Http;
using System.Threading.Tasks;
namespace MyNamespace
{
public class WebApiTestController : ApiController
{
private IUserInfo _userInfo;
public WebApiTestController(IUserInfo userInfo)
{
_userInfo = userInfo; // injected from AutoFac
}
public async Task<IHttpActionResult> Get()
{
var roleId = _userInfo.RoleId;
await Task.Delay(1).ConfigureAwait(true);
return Ok();
}
}
}
Here are the dependencies you can get from NuGet for this example.
Install-Package Autofac
Install-Package Autofac.Mvc5
Install-Package Autofac.WebApi2
Solution 3 - Authorization Filter
One more solution I thought of. You never specified why you needed the user and role id. Maybe you want to check access level in the method before proceeding. If this is the case the best solution is to not only implement a Filter but to create an override of System.Web.Http.Filters.AuthorizationFilterAttribute. This allows you to execute an authorization check before your code even executes which is very handy if you have varying levels of access across your web api interface. The code I put together illustrates the point but you could extend it to add actual calls to a repository for checks.
WebApiAuthorizationClaimsUserFilterAttribute.cs
using System.Net;
using System.Net.Http;
using System.Web;
using System.Web.Http.Controllers;
namespace MyNamespace
{
public class WebApiAuthorizationClaimsUserFilterAttribute : System.Web.Http.Filters.AuthorizationFilterAttribute
{
// the authorized role id (again, just an example to illustrate this point. I am not advocating for hard coded identifiers in the code)
public int AuthorizedRoleId { get; set; }
public override void OnAuthorization(HttpActionContext actionContext)
{
var context = (HttpContextBase) actionContext.Request.Properties["MS_HttpContext"];
var user = new WebUserInfo(context);
// check if user is authenticated, if not return Unauthorized
if (!user.IsAuthenticated || user.UserId < 1)
actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized, "User not authenticated...");
else if(user.RoleId > 0 && user.RoleId != AuthorizedRoleId) // if user is authenticated but should not have access return Forbidden
actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Forbidden, "Not allowed to access...");
}
}
}
WebApiTestController.cs
using System.Web.Http;
using System.Threading.Tasks;
namespace MyNamespace
{
public class WebApiTestController : ApiController
{
[WebApiAuthorizationClaimsUserFilterAttribute(AuthorizedRoleId = 21)] // some role id
public async Task<IHttpActionResult> Get(IUserInfo claimsUser)
{
// code will only be reached if user is authorized based on the filter
await Task.Delay(1).ConfigureAwait(true);
return Ok();
}
}
}
Quick Comparison of Solutions
If you want flexibility go with AutoFac. You can reuse this for many of the moving parts of your solution/project. It makes for very maintainable and testable code. You can extend it very easily once its setup and running.
If you want something static and simple that is guaranteed not to change and you have minimal number of moving parts where an DI framework would be overkill then go with the Filter solution.
If you want to execute authorization checks in a single location then a custom AuthorizationFilterAttribute is the best way to go. You can add the code from the filter in solution #1 to this code if authorization passes, this way you still have access to the user information for other purposes in your code.
Edits
I added a 3rd solution to the list of possibilities.
Added a solution summary at the top of the answer.
Create a custom ActionFilter class (for OnActionExecuting):
using System.Security.Claims;
using System.Web;
using System.Web.Mvc;
using Microsoft.AspNet.Identity;
namespace YourNameSpace
{
public class CustomActionFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
ClaimsIdentity claimsIdentity = HttpContext.Current.User.Identity as ClaimsIdentity;
filterContext.ActionParameters["roleId"] = int.Parse(claimsIdentity.FindFirst("RoleId").Value);
filterContext.ActionParameters["userId"] = int.Parse(claimsIdentity.GetUserId());
}
}
}
Then decorate a choice of Base Controller, Controller or Action(s) (depending on the level you want to apply the custom filter), and specify roleId and userId as Action parameters:
[CustomActionFilter]
public async Task<IHttpActionResult> getTest(int roleId, int userId, int examId, int userTestId, int retrieve)
{
// roleId and userId available to use here
// Your code here
}
Hopefully that should do it.

ASP.NET Identity 2.0 UserManager.FindByIdAsyc not returning Roles

I am building a website using ASP.NET MVC v5.2, Entity Framework v6.0 (Code First) and Identity 2.0.
I have the following code in my UserAdmin controller:
// GET: /UserAdmin/Details/5
public async Task<ActionResult> Details(string id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var user = await UserManager.FindByIdAsync(id);
return View(user);
}
My problem is that while I can populate a user's roles with the UserManager, it is not picking up the roles associated with that user when using the FindByIdAsync method.
Here is data from the IdentityUserRole table which shows for the highlighted user assigned to two roles:
Here is the debug info showing the same user as above but the Roles count is zero:
Why are the roles for this user not being returned?
Edit #1
I am not using the default implementations for UserManager.
My ApplicationUser extends IdentityUser to allow me to add custom properties. My ApplicationDbContext extends IdentityDbContext.
Here's where I set up my primary keys for Identity using Fluent API:
modelBuilder.Entity<IdentityUserLogin>().HasKey<string>(l => l.UserId);
modelBuilder.Entity<IdentityRole>().HasKey<string>(r => r.Id);
modelBuilder.Entity<IdentityUserRole>().HasKey(r => new { r.RoleId, r.UserId });
As you are extending the IdentityDbContext and IdentityUser, you don't need to define your relationships for Logins, Roles and UserRoles as they are already defined in the base classes. You need to remove the lines like modelBuilder.Entity<IdentityUserRole>().HasKey(r => new { r.RoleId, r.UserId }); as they are taken care of.
As for not using the default UserManager There is a possibility here I see based on the code you have provided.
The default implementation for UserManager takes an IUserStore<TUser> as a parameter in it's constructor. If you are using (or deriving from) the UserStore<TUser> implementation in the Microsoft.AspNet.Identity.EntityFramework Library, the things like Roles, Claims and Logins are being included in the queries being made to the database. If you are creating your own class implementing IUserStore<TUser> then you will need to include the related data yourself. an example is shown below.
public class ApplicationUser : IdentityUser
{
//Add your Custom Properties here..
}
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
//Add your Custom Properties here..
}
public class ApplicationUserStore : IUserStore<ApplicationUser>
{
private readonly ApplicationDbContext _context;
public ApplicationUserStore(ApplicationDbContext context)
{
_context = context;
}
public async Task<ApplicationUser> FindByIdAsync(string userName)
{
return await _context.Users.Include(x => x.Roles).FirstOrDefaultAsync(n => n.UserName == userName);
}
}

Securing ajax calls in a ASP.NET MVC application

I have an ASP.NET MVC based application that allows different levels of access depending on the user. The way it currently works is when a user accesses a page, a check is done against the database to determine the rights that user has. The view is then selected based on the level of access that user has. Some users see more data and have more functionality available to them than do others. Each page also makes a variety of ajax calls to display and update the data displayed on the page.
My question is what is the best way to ensure that a particular ajax call originated from the view and was not crafted manually to return or update data the user does not have access to? I would prefer not to have to go to the database to re-check every time an ajax call is made since that was already done when the user initially loaded the page.
Check out the Authorize Attribute, you can put it on an entire controller or just specific methods within your controller.
Examples:
[Authorize(Roles = "Administrator")]
public class AdminController : Controller
{
//your code here
}
or
public class AdminController : Controller
{
//Available to everyone
public ActionResult Index()
{
return View();
}
//Just available to users in the Administrator role.
[Authorize(Roles = "Administrator")]
public ActionResult AdminOnlyIndex()
{
return View();
}
}
Alternately, you can write a custom Authorize attribute to provide your own logic.
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
IPrincipal user = httpContext.User;
var validRoles = Roles.Split(',');//Roles will be a parameter when you use the Attribute
List<String> userRoles = GetRolesFromDb(user);//This will be a call to your database to get the roles the user is in.
return validRoles.Intersect(userRoles).Any();
}
}
To use:
[CustomAuthorizeAttribute(Roles = "Admin,Superuser")]
public class AdminController : Controller {
}
If iyou are using a post use
[Authorize]
[ValidateAntiForgeryToken]
If iyou are using a get use
[Authorize]
You can also use this custom attribute
public class HttpAjaxRequestAttribute : ActionMethodSelectorAttribute
{
public override bool IsValidForRequest(ControllerContext controllerContext, System.Reflection.MethodInfo methodInfo)
{
if (!controllerContext.HttpContext.Request.IsAjaxRequest())
{
throw new Exception("This action " + methodInfo.Name + " can only be called via an Ajax request");
}
return true;
}
}
Then decorate your action as below
[Authorize]
[HttpAjaxRequest]
public ActionResult FillCity(int State)
{
//code here
}
Remember to "Mark/Tick" if this solve your problem.
It depends on what type of session mechanisam you are using . Are you using default membership provider ? If not than you can pass user's id and sessionid make sure that user session is valid and user has required permission to make that call .
Along with the Authorize attribute, you can also allow only Ajax requests using custom attributes as shown here.
Thanks

restrict user access to controller based on property in object (asp.net mvc)

What is the best way to control user access to a controller. I have local User object with a property(boolean - "IsSubscribed"). Users can only access the controller if the value is true.
Notes:
I use forms authentication, but NO .net membership/profile etc.
mvc version 2
You could write a custom Authroize attribute:
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
var isAuthorized = base.AuthorizeCore(httpContext);
if (isAuthorized)
{
// Perform your custom authorization and return true/false
}
return isAuthorized;
}
}
and then decorate your controller/actions with this attribute.

Resources