2017-01-28

如何在 ASP.NET MVC 的 BaseController 或是 Controller 建構式中存取 ASP.NET Identity User 資料

從 ASP.NET MVC 5 開始預設使用 ASP.NET Identity ,全新的會員身份系統(membership system),雖然已經實際在幾個專案使用,但因為對 ASP.NET Identity 沒有很清楚的理解跟認識,每次使用時都會遇到類似,甚至相同的問題。 最近的專案又遇到了相同(慚愧~~),趕快紀錄一下,避免每次遇到都要查好久


文章大綱

  1. 錯誤訊息
  2. 新增 BaseController
  3. 建立 ASP.NET Identity 資料服務
  4. 其他 Controller 實際使用
  5. Web API 下的作法

1. 錯誤訊息

Object reference not set to an instance of an object.

1error

2. 新增 BaseController

  1. 加上 [Authorize] attibute

    [Authorize]
    public class BaseController : Controller
    
  2. 新增 User property

    IUser _UserData;
    public IUser UserData
        {
            get { return _UserData; }
            set { _UserData = value; }
        }
    
  3. 建立 BaseController 建構式

    • 取得執行緒目前原則
    • 檢查目前原則是否有效登入
    • 依執行原則中的名稱反查 User 資料
    public BaseController()
        {
            var userFromAuthCookie = System.Threading.Thread.CurrentPrincipal;
    
            if (userFromAuthCookie != null && userFromAuthCookie.Identity.IsAuthenticated) // && !String.IsNullOrEmpty(userFromAuthCookie.Identity.Name))
            {
                string userNameFromAuthCookie = userFromAuthCookie.Identity.Name;
                _UserData = UserRepository.GetUser(userNameFromAuthCookie);
            }
        }
    
  • 完整程式碼
    [Authorize]
    public class BaseController : Controller
    {
        IUser _UserData;
    
        public IUser UserData
        {
            get { return _UserData; }
        }
    
        public BaseController()
        {
            var userFromAuthCookie = System.Threading.Thread.CurrentPrincipal;
    
            if (userFromAuthCookie != null && userFromAuthCookie.Identity.IsAuthenticated)
            {
                string userNameFromAuthCookie = userFromAuthCookie.Identity.Name;
                _UserData = UserRepository.GetUser(userNameFromAuthCookie);
            }
        }
    
    
    }
    

3. 建立 ASP.NET Identity 資料服務

```
public static class UserRepository
{
    public  static IUser GetUser(string username)
    {
        var UserManager = HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>();
        return UserManager.FindByName(username);
    }
}
```

4. 其他 Controller 實際使用

  1. 繼承 BaseController public class HomeController : BaseController

  2. 自訂 property private string userID;

  3. 建構式存取 BaseController property

    public HomeController()
        {
            userID = UserData.Id;
        }
    

5. Web API 下的作法

相關做法請參考 Identity 2.0 User Identity is null in MVC 5 controller initializer

  1. 加入自訂 Authorize attibute

    public class MyAuthorizeAttribute : AuthorizeAttribute 
    {
        public override async Task OnAuthorizationAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
        {
            if (actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Any()) return;
    
            base.OnAuthorization(actionContext);
    
            Guid userId;
    
            if (actionContext.RequestContext.Principal.Identity.IsAuthenticated
                && Guid.TryParse(actionContext.RequestContext.Principal.Identity.GetUserId(), out userId))
            {
                actionContext.Request.Properties.Add("userId", actionContext.RequestContext.Principal.Identity.GetUserId());
            }
        }
    }
    
  2. 將自訂的 Authorize attibute 加入 Startup.cs 中

    public void Configuration(IAppBuilder app)
    {
        ConfigureOAuth(app);
    
        HttpConfiguration config = new HttpConfiguration();
        WebApiConfig.Register(config);
        config.Filters.Add(new MyAuthorizeAttribute());
    }
    
  3. 使用 Guid userId = (Guid) ActionContext.Request.Properties["userId"];

參考資料

  1. Defining a User with User.Identity.Name in controller constructor
  2. ASP MVC5 - Identity. How to get current ApplicationUser
  3. Identity 2.0 User Identity is null in MVC 5 controller initializer

沒有留言:

張貼留言