2012-10-03 32 views
4

我使用ASP.NET MVC 4與網頁API傳遞用戶名的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)這裏我需要通過較早(即從MVC 3升級前)我是用User.Identity.Username來獲取用戶名用戶名。

我應該如何處理這種情況。

如何傳遞用戶名?有什麼我可以做的。

此外,我不想在GetProductFromId(string username)方法內使用User.Identity.Username,因爲它將打敗使用web api的整個目的,也不會被測試。

請指導我幫我解決這個問題。由於

回答

13

另外,我不想使用User.Identity.Username的 GetProductFromId(用戶名字符串)方法中,因爲它會打敗使用Web API的整個 目的並不會檢驗的了。

這正是你應該使用什麼:

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

通知的[Authorize]屬性。根據您使用的授權方案,User.Identity將以不同方式填充。例如,如果您啓用了表單身份驗證,那麼用戶名顯然會來自客戶端在調用操作時需要傳遞的表單身份驗證Cookie。例如,如果您使用基本身份驗證而不是表單身份驗證,則還可以編寫自定義處理程序。我寫了一個example here

這並沒有打破任何單元測試的目的。這種方法是非常好的單元測試。 ApiControllerUser屬性是IPrincipal,它可以在單元測試中輕微地嘲弄。例如與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 
... 
+0

是,首先感謝的答案,我真的不知道你可以嘲笑用戶屬性,你能指出我在這個PLS上的一些鏈接。還有,如果我**希望**通過用戶名作爲參數,有沒有辦法/黑客來處理? – Yasser

+0

你想通過用戶名作爲參數嗎?這不會完全擊敗認證的目的陽離子?客戶可以通過他喜歡的任何用戶名。但是,當然如果你想這樣做,那麼簡單地把它作爲一個動作參數。然後,在調用該方法時,您可以將其作爲查詢字符串參數傳遞。但即使你想通過用戶名作爲參數,我建議你使用自定義處理程序(看看我寫的),並將其存儲到User.Identity.Name中。至於嘲笑用戶名屬性,給我1秒提供一個例子。 –

+0

是啊當然,我正在做的暴露一個API可以輸入用戶名和獲得與他相關的產品,可以使用1. web應用程序和任何人可以使用瀏覽器打這個網絡方法。 (是的,每個人都應該能夠獲得任何人的數據) – Yasser

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 
     } 
    } 
} 
+0

我的「Rant」https://granadacoder.wordpress。 COM/2010/12/01 /咆哮硬編碼,安全角色/ – granadaCoder