如何使 class 对象在 Asp .Net Web API 请求的整个生命周期内可用?

How to make a class object available during the entire life of the request in Asp .Net Web API?

这是我的代码。我已经为有效令牌 return 用户对象编写了登录名来验证令牌。但无法找到使其跨控制器可用的方法。

我不想使用身份。

public class CustomAuthorize : AuthorizeAttribute
{
    private const string AUTH_TOKEN = "AuthToken";

    public override Task OnAuthorizationAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
    {
        AllowAnonymousAttribute allowAnonymousAttribute = actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().FirstOrDefault();

        if (allowAnonymousAttribute != null)
        {
            return Task.FromResult<object>(null);
        }

        if (actionContext.Request.Headers.Contains(AUTH_TOKEN))
        {
            var authToken = actionContext.Request.Headers.GetValues(AUTH_TOKEN).First();
            var user = Utility.GetUserByToken(authToken);

            if (user != null)
            {
                //
                // how to make this `user` object available across the controllers
                //

                return Task.FromResult<object>(null);
            }
            else
            {
                actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized, new CustomError() { Code = 100, Message = "Invalid Access Token" });
                return Task.FromResult<object>(null);
            }
        }
        else
        {
            actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized, new CustomError() { Code = 100, Message = "Invalid Access Token" });
            return Task.FromResult<object>(null);
        }
    }
}

请帮忙...

一种方法是扩展 ApiController,这是您的控制器用作基础的东西 class。

定义自定义控制器

public class CustomController : ApiController
{
    projected User _user;

}

对于所有其他控制器,使用它作为基础 class 并且 _user 对象应该可以从所有控制器访问。

你的问题有点不清楚 - 我假设你指的是这一行:

var user = Utility.GetUserByToken(authToken);

如果是这样,那么我可能有解决办法。所以根本问题是你不能简单地将这个变量保存在你当前在当前控制器中的位置,你需要了解你正在工作的上下文 - 每次不同的用户发出请求时,都会在当前控制器中创建不同的用户模型.要在用户发出请求时访问我的应用程序中的用户模型,我执行以下操作:

首先你需要挂接到ASP.NET的请求接收进程。这可以在 Global.asax.cs 文件中完成,但我更喜欢保持它干净并创建一个 PartialGlobal class 并将 Global.asax.cs 标记为部分。

来自

public class MvcApplication : System.Web.HttpApplication

public partial class MvcApplication : System.Web.HttpApplication

然后创建 PartialGlobal Class:

 public partial class MvcApplication
{
    protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
    {
        var request = HttpContext.Current.Request;
        var authHeader = request.Headers["Authorization"];

        //For API users
        if (authHeader != null)
        {
            var authHeaderVal = AuthenticationHeaderValue.Parse(authHeader);
            if (authHeaderVal.Scheme.Equals("Basic", StringComparison.OrdinalIgnoreCase))
            {
                if (!string.IsNullOrEmpty(authHeaderVal.Parameter))
                {
                    AuthenticateUser(authHeaderVal.Parameter);
                }
            }
        }
        //For Regular Website Users
        else
        {
            HttpCookie authCookie = request.Cookies[FormsAuthentication.FormsCookieName];
            if (authCookie != null)
            {
                //Extract the forms authentication cookie
                FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
                // If caching userData field then extract
                var userModel = UsersBLL.DeserializeObject(authTicket.UserData);
                var principal = new UserPrincipal(userModel);
                SetPrincipal(principal);
            }
        }
    }

    private static bool AuthenticateUser(string credentials)
    {
        var model = UsersBLL.DecryptToken(credentials);
        if (!model.RefUser.HasValue)
        {
            return false;
        }

        SetPrincipal(new UserPrincipal(model));

        return true;
    }

    private static void SetPrincipal(UserPrincipal principal)
    {
        Thread.CurrentPrincipal = principal;
        if (HttpContext.Current != null)
        {
            HttpContext.Current.User = principal;
        }
    }
}    

UserPrincipal Class:

public class UserPrincipal : IPrincipal
{
    public IIdentity Identity { get; private set; }
    //Just a class with details like name,age etc.
    public UserModel Model { get; set; }

    public UserPrincipal(UserModel model)
    {
        this.Model = model;
        this.Identity = new GenericIdentity(model.Email);
    }        
}

注意 PartialGLobal class 中的行:var model = UsersBLL.DecryptToken(credentials);。在这里,我只是使用我创建的方法来 de-crypt 我的令牌字符串,这样它就可以被反序列化,你可能不会 have/need 这个。

关键部分是 PartialGlobal class:

的最后一步
private static void SetPrincipal(UserPrincipal principal)
{
     Thread.CurrentPrincipal = principal;
     if (HttpContext.Current != null)
     {
         HttpContext.Current.User = principal;
     }
}

如果您知道您的用户的上下文,您只需调用以下命令即可在任何地方访问它:

var principal = (UserPrincipal)HttpContext.Current.User;