Web API 在 MVC 中存储承载令牌的位置
Posted
技术标签:
【中文标题】Web API 在 MVC 中存储承载令牌的位置【英文标题】:Where to store Bearer Token in MVC from Web API 【发布时间】:2017-01-20 19:35:21 【问题描述】:场景
我有一个 ASP.NET Web API,它使用 OAuth 密码流提供不记名令牌来访问其资源。
我现在正在制作一个需要使用此 API 的 MVC 应用程序。
计划是让 MVC 控制器代表客户端浏览器调用 API。
来自浏览器的 ajax 请求将到达 MVC 控制器,然后进行 API 调用。然后将结果作为 JSON 反馈给客户端,并在 java-script 中处理。
客户端不应直接与 API 通信。
进行身份验证。
一旦通过成功调用 Web api 令牌端点在 MVC 应用程序中收到承载令牌,我需要找到处理承载令牌的最佳方式。
我需要在对 api 的任何后续调用中使用此不记名令牌。
我的计划是将其存储在System.Web.HttpContext.Current.Session["BearerToken"]
然后我可以创建一个自定义AuthorizationAttribute
,它将检查当前 HttpContext 中是否存在 BearerToken,如果不存在,客户端将需要重新访问令牌端点。
这看起来可行吗?
我正在征求人们对此的意见,因为我不相信这是我项目的最佳解决方案。
【问题讨论】:
不记名令牌将进入您的请求标头。我相信您正在通过 AJAX 调用访问 Web API。因此,您必须使用从 Web API 收到的令牌适当地创建 AJAX 请求。我在这里做了类似的事情,但没有 AJAX-***.com/questions/38661090/… 我正在使用 MVC 应用程序中的 HttpClient 对象进行 wep api 调用 【参考方案1】:我设法想出了一些我认为会很好用的东西。
我正在使用 Owin 中间件进行 Cookie 身份验证。
在 MVC 应用程序中,我有一个 Owin 启动文件,其中配置了 Cookie 身份验证:-
public class Startup
public void Configuration(IAppBuilder app)
// For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=316888
app.UseCookieAuthentication(new CookieAuthenticationOptions()
AuthenticationType = "ApplicationCookie",
LoginPath = new PathString("/Account/Login"),
);
然后我创建了一个 AccountController,其中包含两个用于登录和注销的操作方法:-
登录。
public ActionResult Login(LoginModel model,string returnUrl)
var getTokenUrl = string.Format(ApiEndPoints.AuthorisationTokenEndpoint.Post.Token, ConfigurationManager.AppSettings["ApiBaseUri"]);
using (HttpClient httpClient = new HttpClient())
HttpContent content = new FormUrlEncodedContent(new[]
new KeyValuePair<string, string>("grant_type", "password"),
new KeyValuePair<string, string>("username", model.EmailAddress),
new KeyValuePair<string, string>("password", model.Password)
);
HttpResponseMessage result = httpClient.PostAsync(getTokenUrl, content).Result;
string resultContent = result.Content.ReadAsStringAsync().Result;
var token = JsonConvert.DeserializeObject<Token>(resultContent);
AuthenticationProperties options = new AuthenticationProperties();
options.AllowRefresh = true;
options.IsPersistent = true;
options.ExpiresUtc = DateTime.UtcNow.AddSeconds(int.Parse(token.expires_in));
var claims = new[]
new Claim(ClaimTypes.Name, model.EmailAddress),
new Claim("AcessToken", string.Format("Bearer 0", token.access_token)),
;
var identity = new ClaimsIdentity(claims, "ApplicationCookie");
Request.GetOwinContext().Authentication.SignIn(options, identity);
return RedirectToAction("Index", "Home");
退出
public ActionResult LogOut()
Request.GetOwinContext().Authentication.SignOut("ApplicationCookie");
return RedirectToAction("Login");
保护资源
[Authorize]
public class HomeController : Controller
private readonly IUserSession _userSession;
public HomeController(IUserSession userSession)
_userSession = userSession;
// GET: Home
public ActionResult Index()
ViewBag.EmailAddress = _userSession.Username;
ViewBag.AccessToken = _userSession.BearerToken;
return View();
public interface IUserSession
string Username get;
string BearerToken get;
public class UserSession : IUserSession
public string Username
get return ((ClaimsPrincipal)HttpContext.Current.User).FindFirst(ClaimTypes.Name).Value;
public string BearerToken
get return ((ClaimsPrincipal)HttpContext.Current.User).FindFirst("AcessToken").Value;
【讨论】:
我的 HomeController/Index 上的 userSession 对象为 NULL 如果您没有在应用程序中使用依赖注入,则 userSession 将为空。 @Derek,是的,你是对的,你能帮我解决这个问题吗? 那是一个完全不同的话题。研究 Autofac 库。它易于实施! 处理登录的好方法,我仍然想知道你是如何管理“过期的Access_token”的?我的理解是即使令牌过期,cookie 身份验证也会让您保持登录状态。下一次 API 调用,您将获得一个全新的令牌。你需要更换它。你会怎么处理?另外,如果 Access_token 将用户登录或注销设置为 MVC 应用程序范围怎么办?【参考方案2】:既然您提到您正在使用 HttpClient()。我使用 HttpClient()-
做了类似的事情获取令牌-
static Dictionary<string, string> GetTokenDetails(string userName, string password)
Dictionary<string, string> tokenDetails = null;
try
using (var client = new HttpClient())
var login = new Dictionary<string, string>
"grant_type", "password",
"username", userName,
"password", password,
;
var resp = client.PostAsync("http://localhost:61086/token", new FormUrlEncodedContent(login));
resp.Wait(TimeSpan.FromSeconds(10));
if (resp.IsCompleted)
if (resp.Result.Content.ReadAsStringAsync().Result.Contains("access_token"))
tokenDetails = JsonConvert.DeserializeObject<Dictionary<string, string>>(resp.Result.Content.ReadAsStringAsync().Result);
catch (Exception ex)
return tokenDetails;
使用令牌发布数据
static string PostData(string token, List<KeyValuePair<string, string>> lsPostContent)
string response = String.Empty;
try
using (var client = new HttpClient())
FormUrlEncodedContent cont = new FormUrlEncodedContent(lsPostContent);
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
var resp = client.PostAsync("https://localhost:61086/api/<your API controller>/", cont);
resp.Wait(TimeSpan.FromSeconds(10));
if (resp.IsCompleted)
if (resp.Result.StatusCode == HttpStatusCode.Unauthorized)
Console.WriteLine("Authorization failed. Token expired or invalid.");
else
response = resp.Result.Content.ReadAsStringAsync().Result;
Console.WriteLine(response);
catch (Exception ex)
return response;
即使您将 Bearer 令牌存储在 HttpContext 中,您也需要注意在 Web API 中设置的令牌到期时间。仅在会话中验证令牌的存在无济于事,因为旧令牌将在过期时间后失效。
【讨论】:
以上是关于Web API 在 MVC 中存储承载令牌的位置的主要内容,如果未能解决你的问题,请参考以下文章
了解 ASP.NET(MVC、Web API)中的令牌生成/验证
在 .net 核心 web api 中存储 JWT 令牌的位置?
Web Api 2 Preflight CORS 请求承载令牌