I am developing an ASP.NET Core 2.2 Website where users need login and then use it.
The AccountController
in my Website calls another ASP.NET Core WebApi (with [AllowAnonymous]
attribute) to get the JWT token from username and password.
All controllers except for AccountController
within the Website will have [Authorize("Bearer")]
attribute to check if the user has been authorized.
My WebApi will have other controllers too which will require [Authorize("Bearer")]
, so the JWT token will be passed from the Website when making http requests. See below configured Startup.cs
> ConfigureServices()
method file in WebApi project:
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());
});
And the Configure()
method:
app.UseAuthentication();
ASP.NET Core WebApi - generate JWT token:
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;
I have completed the WebApi method to generate a token and return back a JWT token. But what do I do with that token so that the Authentication/Authorization works in my ASP.NET Core Website.
[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");
}
So to make matters complex, the overview of my project is as such:
ASP.NET Core Website - has login page and other controllers with ajax calls for datatables and Forms for Edit pages which must be authorized ASP.NET Core WebApi - generated JWT token and has methods for other api calls which must be authorized
How do I tell the Website that if user is not Authorized, then go to my /Account/Login
page?
Is this process correct, if not do I still need to add Identity and do this differently for Website?
JSON Web Tokens are an open, standard way for you to represent your user's identity securely during a two-party interaction. First, the user or client app sends a sign-in request. In this step, essentially, a username, password, or any other type of sign-in credentials the user provides will travel to the API.
JSON Web Tokens (commonly known as JWT) is an open standard to pass data between client and server, and enables you to transmit data back and forth between the server and the consumers in a secure manner. This article talks about how you can take advantage of JWTs to protect APIs.
If your ASP.NET Core Website and ASP.NET Web API are two different websites :
Authorization : Bearer {access_token}
. Or register an OnMessageReceived
handler if you would like send it via cookie/querystringI'm not sure how your authentication looks like.
Assuming you choose to use cookies for ASP.NET Core Website, make sure you've set the LoginPath = "/Account/Login";
// the Startup::ConfigureServices of your ASP.NET Core Website
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(o => {
o.LoginPath = "/Account/Login";
});
And then as suggested by Camilo Terevinto, you need to sign the user in :
[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");
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With