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

时间:2019-02-24 01:14:18

标签: c# asp.net-core jwt

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

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

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

我的WebApi也将具有其他需要[Authorize("Bearer")]的控制器,因此在发出http请求时将从网站传递JWT令牌。请参阅下面在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;

我已经完成了WebApi方法来生成令牌并返回JWT令牌。但是,我该使用该令牌做什么,以便身份验证/授权可以在我的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调用,必须授权数据表和Forms for Edit页面 ASP.NET Core WebApi -生成的JWT令牌,并具有用于其他必须被授权的api调用的方法

如何告知网站,如果用户未被授权,请转到我的/Account/Login页?

此过程是否正确?如果不是,我仍然需要添加身份并对网站进行其他更改吗?

1 个答案:

答案 0 :(得分:1)

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

  • 对于WebAPI,客户端应始终通过添加标题Authorization : Bearer {access_token}发送请求。或注册一个OnMessageReceived处理程序,如果您想通过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");
    }