简体   繁体   English

JWT 使用 HttpOnly cookie 的授权

[英]JWT Authorization using HttpOnly cookie

I am making a web application using ASP.NET Core using CookieAuthentication as my MVC authentication and JWT for Web-APIs.我正在使用 ASP.NET 核心制作 web 应用程序,使用CookieAuthentication作为我的 MVC 身份验证,JWT 用于 Web-API。

I have configured the cookie authentication and created the JWT token successfully.我已经配置了 cookie 身份验证并成功创建了 JWT 令牌。 However I have trouble authorizing my API methods that contain the [Authorization(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] attribute.但是,我无法授权包含[Authorization(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]属性的 API 方法。

Startup.cs启动.cs

services
    .AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddCookie(options =>
    {
        options.Cookie.Name = "CookieAuthentication";
        options.Cookie.HttpOnly = true;
        options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
        options.ExpireTimeSpan = TimeSpan.FromDays(14);
        options.LoginPath = "/Account/Login";
        options.LogoutPath = "/Account/Logout";
        options.AccessDeniedPath = "/Account/Unauthorized";
    });

services
    .AddAuthentication()
    .AddJwtBearer(options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            ValidIssuer = Configuration["Jwt:JwtIssuer"],
            ValidAudience = Configuration["Jwt:JwtAudience"],
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:JwtSecretKey"]))
        };
    });

AccountController.cs AccountController.cs

[HttpPost]
[Route("Login")]
[AllowAnonymous]
public async Task<IActionResult> Login([FromForm]LoginViewModel model)
{
    await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);

    if (model.Username == "test" && model.Password == "test")
    {
        var name = "Name";
        var role = "Admin";
        var email = "test123@gmail.com";

        var claims = new List<Claim>()
        {
            new Claim(ClaimTypes.Name, name),
            new Claim(ClaimTypes.Email, email),
            new Claim(ClaimTypes.Role, role)
        };

        var credientials = new SigningCredentials(
            new SymmetricSecurityKey(
                Encoding.UTF8.GetBytes(_config["Jwt:JwtSecretKey"])),
                SecurityAlgorithms.HmacSha256);

        var securityToken = new JwtSecurityToken(   
            issuer: _config["Jwt:JwtIssuer"],
            audience: _config["Jwt:JwtIssuer"],
            claims: claims,
            expires: DateTime.Now.AddMinutes(1),
            signingCredentials: credientials
        );

        HttpContext.Response.Cookies.Append(
            "JwtCookie",
            "Bearer " + new JwtSecurityTokenHandler().WriteToken(securityToken),
            new CookieOptions
            {
                Expires = DateTime.Now.AddMinutes(1),
                HttpOnly = true,
                Secure = true,
                SameSite = SameSiteMode.Strict
            });

            var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);

            var authenticationProperties = new AuthenticationProperties()
            {
                ExpiresUtc = DateTimeOffset.UtcNow.AddMinutes(1),
                IsPersistent = true
            };

            await HttpContext.SignInAsync(
                CookieAuthenticationDefaults.AuthenticationScheme,
                new ClaimsPrincipal(claimsIdentity),
                authenticationProperties);

            #endregion

            return Redirect($"{role}/Index");

Private.cshtml私有.cshtml

@{
    ViewData["Title"] = "Private";
}

<h2>Private Area</h2>

<input type="button" onclick="addUser()" value="Login" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script>
    function addUser()
    {
        $.ajax
            ({
                type: 'POST',
                url: '/api/Test/AddUser'
            }).done(function (data)
            {
                console.log("done");
            }).fail(function (data, textStatus, xhr)
            {
                console.log("fail");
            })
    }
</script>

/api/Test/AddUser method /api/Test/AddUser 方法

[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[HttpPost]
[Route("AddUser")]
public IActionResult AddUser()
{
    var u = new User
    {
        SamAccountName = "Test",
        Role = ""
    };
    _context.Add(u);
    try
    {
        _context.SaveChanges();
    }
    catch (Exception e)
    {
        return BadRequest($"Cannot save: {e}");
    }

    return Ok();
}

The question I have is:我的问题是:

  1. I am getting 401 error when I try to call the api/Test/AddUser method.当我尝试调用api/Test/AddUser方法时出现 401 错误。 Is there a way I can send the cookie containing the JWT token through the authorization header automatically, similar to how CookieAuthentication does it?有没有一种方法可以通过授权 header 自动发送包含 JWT 令牌的 cookie,类似于CookieAuthentication的方式? I know this is because of my not having an Authorization header.我知道这是因为我没有授权 header。 However because I stored my JWT token inside the HttpOnly cookie, I cannot find a way to pass the token into the authorization header.但是,因为我将 JWT 令牌存储在 HttpOnly cookie 中,所以我找不到将令牌传递到授权 header 的方法。 I could add Authorization { "Bearer " + token }.我可以添加授权{“承载”+令牌}。 I would have to use sessionStorage or use a normal cookie but that would pop up some security concerns.我将不得不使用 sessionStorage 或使用普通的 cookie,但这会引发一些安全问题。 I have seen many tutorials but have never seen how the javascript passes its authorization header, most show passing through authorization header in Postman.我看过很多教程,但从未见过 javascript 如何通过授权 header,大多数显示通过授权 header 在 Z34C061E1976CEDF27.

  2. If the above could be done, is there a way the expiration date could be synced up with the CookieAuthentication cookie?如果上述可以完成,是否有办法将到期日期与CookieAuthentication cookie 同步? Since a JWT token expiration date cannot be extended like cookie, how would I ensure that the user is able to access the APIs and MVC if they are using two different types of authentication?由于 JWT 令牌到期日期不能像 cookie 一样延长,如果用户使用两种不同类型的身份验证,我将如何确保他们能够访问 API 和 MVC?

  3. The project only uses HTTPS and I implemented anti forgery tokens inside the forms I submit.该项目仅使用 HTTPS 并且我在我提交的 forms 中实现了防伪令牌。 Is there any attacks I should protect against?有什么我应该防范的攻击吗?

A little bit late, but I think you'll find the answer to your problem with this answer有点晚了,但我想你会用这个答案找到你的问题的答案

How can I validate a JWT passed via cookies? 如何验证通过 cookies 传递的 JWT?

The basic idea is to create a middleware to intercept the request, check if it contains the token in the cookie, extract the token, and configure the authorization header of the request.基本思路是创建一个中间件拦截请求,检查cookie中是否包含token,提取token,配置请求的授权header。 After this, your request should have the authorization header with the token, and the Authorize data annotation should kick in在此之后,您的请求应该具有带有令牌的授权 header,并且授权数据注释应该启动

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM