I'm fairly new to ASP.NET Core, Angular HttpClient and Observables, so this question was legitimate a year ago, but no longer necessary.
I was not using the [Authorize] attribute properly - it should come before the [Http] verb attributes on all Action methods in the controller - where Authorization is needed for data access.
I was also not properly formatting my logic to perform the JWT token evaluation and Model State verification - so that my action methods would return Status Code 400 (BadRequest) for invalid model state and Status Code 401 (Not Authorized) for invalid JWT or for a session timeout based on the JWT generated at login.
Learning how to use the dbo.Session database was crucial. I had to include the JWT header in its http requests and to perform the JWT token validation and Authorization in the Session controller, too. Here is how I setup the client and server code for the dbo.Session table:
// Angular 9 Client-side model, repository and datasource combination
import { Injectable } from "@angular/core";
import { HttpClient, HttpHeaders } from "@angular/common/http";
import { Member } from "./member.model";
import { DatasourcesService } from "./datasources.service";
const sessionUrl = "/api/session";
// Note: this code is based on a "Cart" model
export class ContactInfo {
selections: MembersInfoSelection[] = [];
itemCount: number = 0;
constructor(private http: HttpClient, private authBearer: DatasourcesService) {
this.selections = [];
}
storeSessionData<T>(dataType: string, data: T) {
let myHeaders = new HttpHeaders();
if (this.authBearer.JWTauthcookie == null) {
myHeaders = myHeaders.set("Access-Key", "<secret>");
} else {
myHeaders = myHeaders.set("Authorization", "Bearer<" + this.authBearer.JWTauthcookie + ">");
}
myHeaders = myHeaders.set("Application-Names", ["ClientApp", "My-App"]);
return this.http.post(`${sessionUrl}/${dataType}`, data, {
headers: myHeaders
}).subscribe(response => { });
}
addMemberInfo(member: Member) {
let selection = this.selections
.find(mis => mis.memberid == member.memberID);
if (selection) {
selection.quantity++;
} else {
this.selections.push(new MembersInfoSelection(this, member.memberID,
member.last_Name, member.first_Name, member.midInit,
member.cell_Phone, member.email_Address));
}
this.update();
}
update(storeData: boolean = true) {
if (storeData) {
this.storeSessionData("contactinfo", this.selections.map(s => {
return {
memberid: s.memberid, lastname: s.lastname, firstname: s.firstname, midinit: s.midinit,
cellphone: s.cellphone, emailaddress: s.emailaddress, quantity: s.quantity
}
}));
}
}
}
// a separate class for data model
export class MembersInfoSelection {
constructor(public contactinfo: ContactInfo,
public memberid?: number,
public lastname?: string,
public firstname?: string,
public midinit?: string,
public cellphone?: string,
public emailaddress?: string,
public quantityValue?: number) { }
}
// Server-Side: AspNetCore 2.2 MVC Controller (C#)
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using ServerApp.Models;
using ServerApp.Infrastructure;
using Microsoft.AspNetCore.Authorization;
namespace ServerApp.Controllers
{
[Route("/api/session")]
[AllowAnonymous]
[ApiController]
public class SessionValuesController : Controller
{
private string bearerToken;
private readonly Jwt_GenerateToken valToken = new Jwt_GenerateToken();
[HttpGet("contactinfo")]
public IActionResult GetContactInfo()
{
return Ok(HttpContext.Session.GetString("contactinfo"));
}
[Authorize(Roles = "Admin,Super,User")]
[HttpPost("contactinfo")]
public object StoreContactInfo([FromBody] SessionInfo[] contacts)
{
object returnObject = new object();
// get the content/value of the Authorization header in the Http Request
bearerToken = Request.Headers["Authorization"];
var bearer = bearerToken.Substring(7, bearerToken.Length - 8);
if (valToken.ValidateCurrentToken(bearer) == true)
{
if (ModelState.IsValid)
{
var jsonData = JsonConvert.SerializeObject(contacts);
HttpContext.Session.SetString("contactinfo", jsonData);
return true;
}
return BadRequest();
}
return StatusCode(401);
}
}
}
Change your services.AddAuthentication();
to services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme);