【问题标题】:Where do I store the Web API access token?我在哪里存储 Web API 访问令牌?
【发布时间】:2015-02-03 06:09:04
【问题描述】:

我有一个非常薄的前端 ASP.NET MVC 5 应用程序,它与 WebApi 2 后端通信。这些是单独的应用程序。

我已从 WebApi 获得身份验证令牌。我必须在用户登录时获取它。我将它存储在会话状态中,但这显然是错误的地方。我遇到用户仍然登录但身份验证令牌不再处于会话中的情况。

我需要将它与我的身份验证 cookie 一起存储,并且它需要具有相同的生命周期。为什么没有开箱即用的方法呢?我敢肯定,这是成千上万的程序员面临的情况。

这是我将其存储到 Session 中的代码:

/// <summary>
/// Configure the application sign-in manager which is used in this application.
/// </summary>
public class ApplicationSignInManager : SignInManager<ApplicationUser, string>
{
    public override async Task<SignInStatus> PasswordSignInAsync(string userName, string password, bool isPersistent, bool shouldLockout)
    {
        var status = await base.PasswordSignInAsync(userName, password, isPersistent, shouldLockout);

        if (status == SignInStatus.Success)
            await PasswordSaveTokenAsync(userName, password);

        return status;
    }

    /// <summary>
    /// Get the token from the Web API with the given user name (<paramref name="userName"/>) and password 
    ///     (<paramref name="password"/>) and save it to the session state.
    /// </summary>
    /// <param name="userName">User name.</param>
    /// <param name="password">Password.</param>
    private async Task PasswordSaveTokenAsync(string userName, string password)
    {
        var baseAddress = Config.WebApiAddress;

        var client = new HttpClient { BaseAddress = baseAddress };
        var response = await client.PostAsync("Token", new StringContent(String.Format("grant_type=password&username={0}&password={1}", userName, password), Encoding.UTF8));

        response.EnsureSuccessStatusCode();

        var tokenResponse = await response.Content.ReadAsStringAsync();
        var json = JObject.Parse(tokenResponse);

        var token = json["access_token"].ToString();

        Session.AccessToken = token;
    }
}

【问题讨论】:

    标签: asp.net-mvc asp.net-web-api


    【解决方案1】:

    这是我想出的解决方案。

    在 Global.asax 中:

    public class MvcApplication : System.Web.HttpApplication
    {
        // Other members removed for brevity.
    
        protected void Session_Start()
        {
            var cookie = Request.Cookies["AccessToken"];
    
            if (cookie != null && cookie.Value != null)
                Session["AccessToken"] = cookie.Value;
        }
    }
    

    在 ApplicationSignInManager.cs 中:

    public class ApplicationSignInManager : SignInManager<ApplicationUser, string>
    {
        // Comments and other members removed for brevity.
    
        public override async Task<SignInStatus> PasswordSignInAsync(string userName, string password, bool isPersistent, bool shouldLockout)
        {
            var status = await base.PasswordSignInAsync(userName, password, isPersistent, shouldLockout);
    
            if (status == SignInStatus.Success)
                await PasswordSaveTokenAsync(userName, password);
    
            return status;
        }
    
        private async Task PasswordSaveTokenAsync(string userName, string password)
        {
            var baseAddress = Config.WebApiAddress;
    
            var client = new HttpClient { BaseAddress = baseAddress };
            var response = await client.PostAsync("Token", new StringContent(String.Format("grant_type=password&username={0}&password={1}", userName, password), Encoding.UTF8));
    
            response.EnsureSuccessStatusCode();
    
            var tokenResponse = await response.Content.ReadAsStringAsync();
            var json = JObject.Parse(tokenResponse);
    
            var token = json["access_token"].ToString();
            var expires = DateTime.Parse(json[".expires"].ToString());
    
            HttpContext.Current.Response.Cookies.Add(new HttpCookie("AccessToken")
            {
                Value = token,
                HttpOnly = true,
                Expires = expires,
            });
    
            HttpContext.Current.Session["AccessToken"] = token;
        }
    }
    

    【讨论】:

      【解决方案2】:

      您也可以将其放入 cookie 中。

      请务必将 cookie 标记为仅限 http

      【讨论】:

      • 但是什么时候?我无法访问我上面的方法 PasswordSaveTokenAsync() 的 cookie。我吗?我想在保存身份验证 cookie 时保存一个 cookie。那里没有我能找到的钩子。
      • 从头开始。如何制作仅 HTTP 的 cookie?
      • 没关系。让我知道我的解决方案中是否有任何错误的形式。谢谢。
      • 你能拿到HttpContext.Current吗?
      • 这里有一些关于制作 cookie 的信息 http only.. msdn.microsoft.com/en-us/library/…