使用 JWT 令牌的 ASP.NET Core 网站到 WebApi 身份验证

Posted

技术标签:

【中文标题】使用 JWT 令牌的 ASP.NET Core 网站到 WebApi 身份验证【英文标题】:ASP.NET Core Website to WebApi authentication using JWT token 【发布时间】:2019-07-17 18:34:13 【问题描述】:

我正在开发一个 ASP.NET Core 2.2 网站,用户需要登录然后使用它。

我网站中的AccountController 调用另一个ASP.NET Core WebApi(带有[AllowAnonymous] 属性)从用户名和密码中获取JWT 令牌。

网站内除AccountController 之外的所有控制器都将具有[Authorize("Bearer")] 属性以检查用户是否已获得授权。

我的 WebApi 也会有其他需要 [Authorize("Bearer")] 的控制器,因此 JWT 令牌将在发出 http 请求时从网站传递。 WebApi项目中配置Startup.cs>ConfigureServices()方法文件见下:

services.AddAuthentication(options =>

    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
).AddJwtBearer(options =>

    options.SaveToken = true;
    options.TokenValidationParameters = new TokenValidationParameters
    
        ValidateIssuerSigningKey = true,
        ValidIssuer = "ZZZZ",
        ValidAudience = "ZZZZ",
        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey))
    ;
);
services.AddAuthorization(auth =>

    auth.AddPolicy("Bearer", new AuthorizationPolicyBuilder()
        .AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme)
        .RequireAuthenticatedUser().Build());
);

还有Configure() 方法:

app.UseAuthentication();

ASP.NET Core WebApi - 生成 JWT 令牌:

JWTToken jwt = new JWTToken();
jwt.Token = "";
jwt.Expires = DateTime.UtcNow.AddMinutes(90);

var claims = new[]

    new Claim(ClaimTypes.UserData, UserId)
;

var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(privateSecretKey));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

var token = new JwtSecurityToken(
    issuer: "ZZZ",
    audience: "ZZZ",
    claims: claims,
    expires: jwt.Expires,
    signingCredentials: creds);

var tokenStr = new JwtSecurityTokenHandler().WriteToken(token);

jwt.Token = tokenStr;
return jwt;

我已经完成了生成令牌并返回 JWT 令牌的 WebApi 方法。但是我该如何处理该令牌,以便身份验证/授权在我的 ASP.NET Core 网站中工作。

[HttpPost]
public async Task<IActionResult> Login(LoginModel model)

    var httpClient = _httpClientFactory.CreateClient(ConstantNames.WebApi);
    var response = await httpClient.PostAsJsonAsync($"ApiArea/authenticate", model);
    if (response.IsSuccessStatusCode)
    
        var jwtToken = await response.Content.ReadAsAsync<JWTToken>();

        /* --> WHAT DO I DO HERE? <-- */

    
    else
    
        ModelState.AddModelError("Password", "Invalid password");
        model.Password = "";
        return View(model);
    

    return RedirectToAction("Index", "Home");

为了让事情变得复杂,我的项目概述是这样的:

ASP.NET Core 网站 - 具有登录页面和其他控制器,其中包含对数据表和表单的 ajax 调用,必须获得授权 ASP.NET Core WebApi - 生成 JWT 令牌并具有用于其他必须授权的 api 调用的方法

我如何告诉网站如果用户未经授权,则转到我的/Account/Login 页面?

这个过程是否正确,如果不正确,我还需要添加身份并为网站做不同的事情吗?

【问题讨论】:

你可以只使用await HttpContext.SignInAsync(...) WebAPI 通常返回 401 Unauthorized 响应并且不会重定向到登录页面,重定向必须在客户端或 MVC 控制器中完成。 @CamiloTerevinto 谢谢会试一试,我在哪里存储 jwt 令牌本身以供进一步的 API 调用,有内置的方法吗? 一种常见的方法是将其放入 Cookie 中,但请确保将其设置为安全 谢谢,我一直在尝试await HttpContext.SignInAsync(...),但是当我使用它来创建主体并通过一些声明传递它时。用户未登录,并被重定向到登录页面。 【参考方案1】:

如果您的 ASP.NET Core 网站和 ASP.NET Web API 是两个不同的网站:

对于 WebAPI,客户端应始终通过添加 Authorization : Bearer access_token 标头来发送请求。或注册OnMessageReceivedhandler,如果您想通过 cookie/querystring 发送它 对于 ASP.NET Core 网站,浏览器应使用 cookie 或 JWT 作为凭据。

我不确定您的身份验证是什么样子的。

假设您选择对 ASP.NET Core 网站使用 cookie,请确保您已设置 LoginPath = "/Account/Login";

// the Startup::ConfigureServices of your ASP.NET Core Website
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddCookie(o => 
        o.LoginPath = "/Account/Login";
    );

然后按照Camilo Terevinto 的建议,您需要让用户登录:

    [HttpPost]
    public async Task<IActionResult> Login(LoginModel model)
    
        var httpClient = _httpClientFactory.CreateClient(ConstantNames.WebApi);
        var response = await httpClient.PostAsJsonAsync($"ApiArea/authenticate", model);
        if (response.IsSuccessStatusCode)
        
            var jwtToken = await response.Content.ReadAsAsync<JWTToken>();

            var username = ...
            var others = ...
            var claims = new List<Claim>
            
                new Claim(ClaimTypes.Name, username),
                // add other claims as you want ...
            ;
            var iden= new ClaimsIdentity( claims, CookieAuthenticationDefaults.AuthenticationScheme);
            var principal = new ClaimsPrincipal(iden);
            await HttpContext.SignInAsync( CookieAuthenticationDefaults.AuthenticationScheme, principal);
            return Redirect("/")

        
        else
        
            ModelState.AddModelError("Password", "Invalid password");
            model.Password = "";
            return View(model);
        

        return RedirectToAction("Index", "Home");
    

【讨论】:

以上是关于使用 JWT 令牌的 ASP.NET Core 网站到 WebApi 身份验证的主要内容,如果未能解决你的问题,请参考以下文章

使用 JWT 令牌的 ASP.NET Core 网站到 WebApi 身份验证

无法使用 ASP.NET Core 从 JWT 令牌获取声明

ASP.NET Core 和 JWT 令牌生命周期

向 ASP.NET Core 的 JWT 令牌添加自定义验证?

如何在 ASP.NET Core 中转储解析的 JWT 令牌?

ASP.NET Core JWT 令牌无法通过 HttpClient 工作