Passing username to Web Api methods in ASP.NET MVC 4

I am using ASP.NET MVC 4 with Web Api

I have the following ApiController.

public class ProductsController : ApiController { public List<Product> GetProducts() { return _productService.GetAllProducts(); } public List<Product> GetProductsFromId(string username) { return _productService.GetProductsFromUsername(username); } } 

Now, if you see the second GetProductsFromId(string username) action here, I need to pass in the username that previously (for example, before upgrading from MVC 3) I used User.Identity.Username to get the username.

How should I handle this in such a scenario.

How to transfer username? I can do something.

Also, I do not want to use User.Identity.Username inside the GetProductFromId(string username) method, since it will defeat the whole purpose of using the web api and will also not be verified.

Please help me with this. Thanks

+4
source share
2 answers

Also, I do not want to use User.Identity.Username inside GetProductFromId (username), since it will defeat the whole purpose of using the web api and will not be verified as well.

What you should use:

 [Authorize] public List<Product> GetProductsFromId() { string username = User.Identity.Name; return _productService.GetProductsFromUsername(username); } 

Note the [Authorize] attribute. Depending on the authorization scheme, you use User.Identity , it will be filled in different ways. For example, if you enabled forms-based authentication, then the username will obviously be obtained from the forms authentication cookie that the client must pass when the action is invoked. You can also write your own handler, for example, if you use basic authentication instead of forms authentication. I wrote here here .

This does not violate any purpose of unit testing. This method is ideal for testing. The User ApiController property is IPrincipal , which could be trivially ridiculed in a unit test. For example, using Moq:

 // arrange var sut = new ProductsController(); var user = new Mock<IPrincipal>(); var identity = new Mock<IIdentity>(); user.Setup(x => x.Identity).Returns(identity.Object); identity.Setup(x => x.Name).Returns("john"); Thread.CurrentPrincipal = user.Object; // act var actual = sut.GetProductsFromId(); // assert ... 
+13
source

Here is a basic plan of what I'm doing.

I use "username" to get the IPrincipal.

I use MemoryCache / ObjectCache so that I only hit the database every 60 minutes. If you need this β€œfor logging in” rather than β€œper user" .. (if your basic definition often changes or you need to code an opportunity, just change the cache key to what is the username and based on the session.

Note that I cannot use β€œIsInRole” in any application that is not your football club. (I have no children, this is a metaphor).

 namespace MyProduct.MyApplication.WebServices.Controllers { /// <summary> /// Performs operations with "Item" list /// </summary> public class MyItemController : BaseApiController { [Authorize] public IEnumerable<Item> Get() { string username = User.Identity.Name; IPrincipalCache cache = new PrincipalCache(); /* use injection - Unity, this hard coding for demo purposes */ MyCustomPrincipal princ = cache.GetMyCustomPrincipal(username); if ( ! princ.HasRight("USER_CAN_GET_ITEMS")) /* Note my MyCustomPrincipal has this method...out of the "box" you'll have "IsInRole('MyRoleName') */ { return null; } return itemsService.GetItems(); } } using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Caching; using System.Web; using MyProduct.MyApplication.Infrastructure.Security; namespace MyProduct.MyApplication.WebServices.Security.Caching { public interface IPrincipalCache { MyCustomPrincipal GetMyCustomPrincipal(string userName); } public class PrincipalCache : IPrincipalCache { public MyCustomPrincipal GetMyCustomPrincipal(string userName) { string cacheKey = "MyCustomPrincipalCacheKey" + userName; MyCustomPrincipal cachedOrFreshPrincipal = GetFromCache<MyCustomPrincipal>(cacheKey, () => { return new MyCustomPrincipal(); /* Go to the method/datalayer/ and hydrate a MyCustomPrincipal */ }); return cachedOrFreshPrincipal; } private TEntity GetFromCache<TEntity>(string key, Func<TEntity> valueFactory) where TEntity : class { ObjectCache cache = MemoryCache.Default; var newValue = new Lazy<TEntity>(valueFactory); CacheItemPolicy policy = new CacheItemPolicy { AbsoluteExpiration = DateTimeOffset.Now.AddMinutes(60) }; /* Most people will do stuff for less than one hour I guess */ //The line below returns existing item or adds the new value if it doesn't exist var value = cache.AddOrGetExisting(key, newValue, policy) as Lazy<TEntity>; return (value ?? newValue).Value; // Lazy<T> handles the locking itself } } } 
0
source

Source: https://habr.com/ru/post/1437534/


All Articles