在 MVC 5 的 cookie 中存储 JWT 令牌

Posted

技术标签:

【中文标题】在 MVC 5 的 cookie 中存储 JWT 令牌【英文标题】:storing JWT token in cookie in MVC 5 【发布时间】:2017-12-13 03:07:20 【问题描述】:

我想在我的 MVC 应用程序中进行 JWT 身份验证。我在 Web API 中创建了正确返回令牌的授权 Web 服务。之后我尝试将令牌存储在 cookie 中。

 [HttpPost]
    public async Task<ActionResult> Login(LoginDto loginDto)
    
        var token = await loginService.GetToken(loginDto);

        if (!string.IsNullOrEmpty(token))
        
            var cookie = new System.Web.HttpCookie("token", token)
            
                HttpOnly = true
            ;
            Response.Cookies.Add(cookie);
            return RedirectToAction("Index", "Product");
        
        return View("LoginFailed");
    

但现在我想将此标记添加到每个请求的标头中。所以我决定动作过滤器最适合实现这一目标。

public class CustomActionFilter : ActionFilterAttribute

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    
        var token = filterContext.HttpContext.Request.Cookies.Get("token");

        if (token != null)
            filterContext.HttpContext.Request.Headers.Add("Authorization", $"Bearer token");

        base.OnActionExecuting(filterContext);
    

启动

public class Startup

    public void Configuration(IAppBuilder app)
    
        AutofacConfig.Configure();
        AreaRegistration.RegisterAllAreas();
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);

        ConfigureOAuth(app);
    

    public void ConfigureOAuth(IAppBuilder app)
    
        var issuer = System.Configuration.ConfigurationManager.AppSettings["issuer"];
        var audience = System.Configuration.ConfigurationManager.AppSettings["appId"];
        var secret = TextEncodings.Base64Url.Decode(System.Configuration.ConfigurationManager.AppSettings["secret"]);

        app.UseJwtBearerAuthentication(
            new JwtBearerAuthenticationOptions
            
                AuthenticationMode = AuthenticationMode.Active,
                AllowedAudiences = new[]  audience ,
                IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[]
                
                    new SymmetricKeyIssuerSecurityTokenProvider(issuer, secret)
                ,

            );

    

然后我只是标记了授权属性的控制器。当我用 POSTMAN 调用它时它工作正常。

但是 MVC 中的操作过滤器总是在授权过滤器之后触发。所以我有问题:

    如何将 cookie 中的令牌添加到每个请求中?这是好习惯吗?如果不是我应该怎么做? csrf 攻击和其他攻击怎么样? AntiForgeryTokenAttr 会做这项工作吗?那么 ajax 调用呢?

附加信息

这就是登录服务的样子。它只是调用身份验证端点。

 public class LoginService : ILoginService

    public async Task<string> GetToken(LoginDto loginDto)
    
        var tokenIssuer = ConfigurationManager.AppSettings["issuer"];
        using (var httpClient = new HttpClient BaseAddress = new Uri($"tokenIssuer/oauth2/token"))
        
            using (var response = await httpClient.PostAsync(httpClient.BaseAddress, new FormUrlEncodedContent(
                new List<KeyValuePair<string, string>>
                
                    new KeyValuePair<string, string>("username", loginDto.Username),
                    new KeyValuePair<string, string>("password", loginDto.Password),
                    new KeyValuePair<string, string>("grant_type", "password"),
                    new KeyValuePair<string, string>("client_id", ConfigurationManager.AppSettings["appId"])
                )))
            
                var contents = await response.Content.ReadAsStringAsync();

                if (response.StatusCode == HttpStatusCode.OK)
                
                    var deserializedResponse =
                        new javascriptSerializer().Deserialize<Dictionary<string, string>>(contents);

                    var token = deserializedResponse["access_token"];

                    return token;
                
            
            return null;
        
    

【问题讨论】:

【参考方案1】:

我找到了解决方案。我只是自定义OAuthBearerAuthenticationProvider 提供程序,在这个类中我从cookie 中检索令牌,然后将其分配给context.Token

public class MvcJwtAuthProvider : OAuthBearerAuthenticationProvider

    public override Task RequestToken(OAuthRequestTokenContext context)
    
        var token = context.Request.Cookies.SingleOrDefault(x => x.Key == "token").Value;

        context.Token = token;
        return base.RequestToken(context);
    

然后在 startup.cs 中

public class Startup

    public void Configuration(IAppBuilder app)
    
        AutofacConfig.Configure();
        AreaRegistration.RegisterAllAreas();
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);

        ConfigureOAuth(app);
    

    public void ConfigureOAuth(IAppBuilder app)
    
        var issuer = System.Configuration.ConfigurationManager.AppSettings["issuer"];
        var audience = System.Configuration.ConfigurationManager.AppSettings["appId"];
        var secret = TextEncodings.Base64Url.Decode(System.Configuration.ConfigurationManager.AppSettings["secret"]);

        app.UseJwtBearerAuthentication(
            new JwtBearerAuthenticationOptions
            
                AuthenticationMode = AuthenticationMode.Active,
                AllowedAudiences = new[]  audience ,
                IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[]
                
                    new SymmetricKeyIssuerSecurityTokenProvider(issuer, secret)
                ,
                Provider = new MvcJwtAuthProvider() // override custom auth

            );

    

【讨论】:

在那个糟糕的 one-undoumented-MS-auth-API-over-the-other-mess 中,您的方法听起来很有希望。感谢分享!我只漏掉了谜题的一部分:你从哪里得到loginService.GetToken 或者它的样子? 我添加了另一个答案,因为在 cmets 部分可能很难显示此登录服务实现。

以上是关于在 MVC 5 的 cookie 中存储 JWT 令牌的主要内容,如果未能解决你的问题,请参考以下文章

在 cookie 中存储 JWT 令牌后,如何在 ASP.NET Core 3.1 中破坏该 cookie 并获取信息

鉴权必须了解的 5 个兄弟:cookie、session、token、jwt、单点登录

同时对 Asp.Net core 2.0 MVC 应用程序 (cookie) 和 REST API (JWT) 进行身份验证

如何使用护照身份验证更新包含 jwt 的 cookie

JWT LocalStorage 与 Cookie

将 JWT 令牌存储在 cookie 中