2

MVC 3、ニンジェクト 2.2。

バインディングを一時的にオーバーライドする必要があるシナリオがあります。オーバーライドは、コントローラー内のアクションの期間中だけです。

私が必要とするのは次のようなものです:

[HttpGet, Authorize(Users="MySpecialAccount")]
public ActionResult Report(string userName) {
  var reportViewModel = new ReportViewModel();

  using(var block = Kernel.BeginBlock() {
    var principal = //load principal info based on userName;
    block.Rebind<IMyPrincipal>().ToConstant(principal);
    reportViewModel = GetViewModel(); //calls bunch of repos to hydrate view model that reference IMyPrincipal
  }

  return View(reportViewModel);
}

バックグラウンド:

アプリケーションは Windows 認証を使用します。カスタム プリンシパルをロードするカスタム プロバイダーがあります。このカスタム プリンシパルを repos/services/etc に挿入し、認証されたユーザーに基づいて適切なデータをロードできるようにします。それはすべて長い間うまく機能してきました。これで、1 つのアクションで偽装を使用するシナリオができました。その理由はおそらく範囲を超えていますが、基本的には、別のアカウントで HTML/Action をロードする別のプロセスを起動する HTMLToPDF ライターを使用しています。とにかく、私はこの1つのアクションで偽装しているため、リクエストを行ったのはユーザーではないため、すべてのリポジトリが正しい情報をロードできません。そのため、レポートを実行する必要がある「誰」のパラメーターを送信し、カスタム プリンシパルを一時的に再バインドする必要があります。

これが理にかなっていることを願っています。カスタム プリンシパルをロードする現在のコードのスニペットを次に示します。

In Global.asax:
protected void WindowsAuthentication_OnAuthenticate(Object source, WindowsAuthenticationEventArgs e)
    {

        if (e.Identity.IsAuthenticated)
        {
            //goes to db and loads additional info about logged on user. We use this info in repos/services to load correct data for logged on user.
            var principal = new PrincipalFactory().GetPrincipal(e.Identity); 

            e.User = principal;
        }
    }


//Ninject Binding    
Bind<IMyPrincipal>().ToProvider(new MyPrincipalProvider());

//Provider
public class MyPrincipalProvider : Provider<IMyPrincipal>
{
    protected override IMyPrincipal CreateInstance(IContext context)
    {
        var principal = HttpContext.Current.User as IMyPrincipal;

        return principal ?? new UnauthenticatedPrincipal(new GenericIdentity("Not Authenticated"));
    }
}

ご協力いただきありがとうございます!

4

1 に答える 1

2

頭に浮かぶ 1 つの可能性は、カスタムの authorize 属性を使用することです。

public class ImpersonateAuthorizeAttribute : AuthorizeAttribute
{
    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        var authorized = base.AuthorizeCore(httpContext);
        if (!authorized)
        {
            return false;
        }

        string username = httpContext.User.Identity.Name;

        // or if you wanted to load the username from the request:
        // string username = httpContext.Request["username"];

        IPrincipal principal = // load principal info based on username;

        // Swap the principal for this action
        httpContext.User = principal;

        return true;
    }
}

その後:

[HttpGet]
[ImpersonateAuthorize(Users="MySpecialAccount")]
public ActionResult Report(string userName) 
{
    // Here this.User will be the custom principal you loaded in 
    // the authorize attribute

    var reportViewModel = new ReportViewModel();

    return View(reportViewModel);
}

別のアプローチは、DI フレームワーク構成レベルでこれを行うことです。

public class MyPrincipalProvider : Provider<IPrincipal>
{
    protected override IPrincipal CreateInstance(IContext context)
    {
        var httpContext = HttpContext.Current;
        var rd = httpContext.Request.RequestContext.RouteData;
        var currentAction = rd.GetRequiredString("action");
        var currentController = rd.GetRequiredString("controller");
        if (string.Equals("report", currentAction, StringComparison.OrdinalIgnoreCase) &&
            string.Equals("users", currentController, StringComparison.OrdinalIgnoreCase))
        {
            IPrincipal principal = // load principal info based on username;
            return principal;
        }

        var principal = httpContext.User as IPrincipal;
        return principal ?? new UnauthenticatedPrincipal(new GenericIdentity("Not Authenticated"));
    }
}
于 2012-08-24T05:59:11.780 に答える