4

我正在使用带有 Web Api 的 ASP.NET MVC 4

我有以下 ApiController。

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

    public List<Product> GetProductsFromId(string username)
    {
        return _productService.GetProductsFromUsername(username);
    }
}

现在,如果您在这里看到第二个操作GetProductsFromId(string username),我需要传递我之前User.Identity.Username用来获取用户名的用户名(即在从 MVC 3 升级之前)。

在这种情况下我应该如何处理。

我如何传递用户名?有什么我可以做的。

此外,我不想User.Identity.Username在方法内部使用,GetProductFromId(string username)因为它会破坏使用 web api 的整个目的,并且也无法测试。

请指导我帮助我。谢谢

4

2 回答 2

13

此外,我不想在 GetProductFromId(string username) 方法中使用 User.Identity.Username,因为它会破坏使用 web api 的全部目的,并且也无法测试。

这正是您应该使用的:

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

注意[Authorize]属性。根据您使用的授权方案,User.Identity将填充不同的内容。例如,如果您启用了表单身份验证,那么用户名显然来自客户端在调用操作时需要传递的表单身份验证 cookie。例如,如果您使用基本身份验证而不是表单身份验证,您还可以编写自定义处理程序。我在这里写了一个例子

这不会破坏单元测试的任何目的。这种方法是完全可单元测试的。ApiControllerUser属性是一个可以在单元测试中简单地模拟的属性。例如起订量:IPrincipal

// 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
...
于 2012-10-03T08:59:14.147 回答
0

这是我正在做的事情的基本大纲。

我使用“用户名”来获取 IPrincipal。

我使用 MemoryCache/ObjectCache 来访问数据库,每 60 分钟一次。如果您需要“每次登录”而不是“每个用户”..(如果您的主体定义经常更改或者您需要为可能性编码,只需将缓存键更改为基于用户名和会话的内容。

请注意,我不能忍受在任何不是您孩子的足球俱乐部的应用程序中使用“IsInRole”。(我没有孩子,这是一个比喻)。

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
        }
    }
}
于 2015-07-31T11:20:35.897 回答