1

If I adopted the last scenario in this thesis :

enter image description here

Then my main layers will be like that:

  • UI Service (MVC application)
  • Business Layer
  • Security Service (used as a wrapper class library for MS identity framework)
  • Aspects which use the previous security service to Authorize the business layer methods.

 public class EditEmployeeData : OnMethodBoundaryAspect
    {

        public override void OnEntry(MethodExecutionArgs args)
        {
            Employee emp = (Employee)args.Instance;
            ((System.Security.Claims.ClaimsIdentity)System.Web.HttpContext.Current.User.Identity).HasClaim("Employee", "EditName");
        }
    } 

I want to set the current user in runtime.


  • How to access the current user to authorize him on a specific functionality in business layer?
  • Should the authorization be more near to the UI to disable/hide functionality and to prevent calling not allowed action methods ?(In the preferred scenario there's not any interaction between the security layer and the UI !!)
Anyname Donotcare
  • 11,113
  • 66
  • 219
  • 392

3 Answers3

2

Update

Please see this answer about using claims...


In a controller, you can get the current user like this:

using Microsoft.AspNet.Identity.Owin;

public class MyController : Controller
{
    // this code will return 0 if user is not authenticated
    protected long GetUserId()
    {
       // note: I have changed the default UserId type from Guid to long
       return User.Identity.GetUserId<long>(); 

       /* 
        * use this if you are using Guid UserIds (which is the default)     
        * return User.Identity.GetUserId();
        */
    }

See this, if you want to know how to change type of UserId.

If you have access to HttpContext, you can get the user like this:

// note that I have changed UserId from Guid to long
HttpContext.Current.User.Identity.GetUserId<long>()

If you want to get ApplicationUser use this (more info here):

// this is how you get user manager from OwinContext    
var userManager = System.Web.HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>();
// Get ApplicationUser from UserManager 
ApplicationUser user = UserManager.FindById(User.Identity.GetUserId());

How to access the current user to authorize him on a specific functionality in business layer?

If you need to access current user in a service, you can pass it through or you can inject it. Using ninject, this is how you can inject UserId into a service:

kernel.Bind<MyService>().ToConstructor(ctorArg => new MyService(
            HttpContext.Current.User.Identity.GetUserId<long>()).InRequestScope(); 

And this is how MyService class looks like:

public class MyService
{
    private readonly long _userId;

    public MyService(long userId)
    {
       // this service always has access to current user (if logged in)
        _userId = userId;
    }
    // more code...

I am not sure what is the process of your authorization... ASP.NET Identity, already implements authorization task for you. This is implemented in ApplicationUserManager and ApplicationSignInManager which comes with ASP.NET MVC default template. You can use [Authorize] attribute on your action/class to prevent unauthorized access:

[Authorize] // <-- restricts all action methods of the class, unless marked [AllowAnonymous]
public class MyController : Controller
{
    [HttpPost]
    [Authorize] // <-- restricts this particular action method
    public ActionResult MyAction(long id)
    {
       // do some action which requires authorization
    }

Regarding DDD layers, have a look at this this link which explains services which belong to each layer.

Hooman Bahreini
  • 14,480
  • 11
  • 70
  • 137
1

How to access the current user to authorize him on a specific functionality in business layer?

To access user information on the business layer, you can type an interface named ICurrentUser

namespace AOPSample
{
    public interface ICurrentUser
    {
        User GetCurrentUser();
    }

    public class User
    {
        public int Id { get; set; }
        public string Username { get; set; }
        public string Role { get; set; }
    }
}

The CurrentUser class must be able to read the information of the user from a common location. HttpContext is available for this.

Let's write a helper class for this.

using System.Web;

namespace AOPSample
{
    public class ContextHelper
    {
        public T Get<T>()
        {
            T local = default(T);
            string key = typeof(T).GUID.ToString();
            if (HttpContext.Current.Items.Contains(key))
            {
                local = (T)HttpContext.Current.Items[key];
            }
            return local;
        }

        public T Get<T>(string key)
        {
            T local = default(T);
            if (HttpContext.Current.Items.Contains(key))
            {
                local = (T)HttpContext.Current.Items[key];
            }
            return local;
        }

        public void Set<T>(T value)
        {
            string str = typeof(T).GUID.ToString();
            HttpContext.Current.Items[str] = value;
        }

        public void Set<T>(T value, string key)
        {
            HttpContext.Current.Items[key] = value;
        }
    }
}

Our CurrentUser class will return user information using your helper class

namespace AOPSample
{
    public class CurrentUser : ICurrentUser
    {
        public User GetCurrentUser()
        {
            return new ContextHelper().Get<User>();
        }
    }
}

now user information write to HttpContext with ContextHelper class and for this use correct location interceptor class

public class EditEmployeeData : OnMethodBoundaryAspect
    {

        public override void OnEntry(MethodExecutionArgs args)
        {
            Employee emp = (Employee)args.Instance;
            ((System.Security.Claims.ClaimsIdentity)System.Web.HttpContext.Current.User.Identity).HasClaim("Employee", "EditName");

            new ContextHelper().Set<User>(new User
            {

            });
        }
    } 

You can access user information from the domain layer with ICurrentUser. HttpContext is unique for every request and response

Should the authorization be more near to the UI to disable/hide functionality and to prevent calling not allowed action methods ?(In the preferred scenario there's not any interaction between the security layer and the UI !!)

It's your choice

In my opinion, you can take user privileges and log them with cache and use them for client side actions, but according to the technology you use for server side, you can store user information for each request in a similar way. For example; The correct location to store the OperationContext for wcf.

tdayi
  • 142
  • 5
0

If you use ASP.NET Identity, you can try the following approach in order to get current User:

ApplicationUser user = System.Web.HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>().FindById(System.Web.HttpContext.Current.User.Identity.GetUserId());

//If you use int instead of string for primary key, use this:
ApplicationUser user = System.Web.HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>().FindById(Convert.ToInt32(System.Web.HttpContext.Current.User.Identity.GetUserId()));

Hope this helps...

Murat Yıldız
  • 11,299
  • 6
  • 63
  • 63