This is the difficult part. I decide that , for the moment, I do not need in the application any fancy authorization – just a simple url + secret ( a.k.a password).
I decided also to use JWT – it is a simple way to add authentication + authorization to the application.
Let’s see the login code
var data = await search.TILT_URLSimpleSearch_URLPart(SearchCriteria.Equal, url).ToArrayAsync(); ;
if (data == null)
return null;
if (data.Length != 1)
return null;
var item = data[0];
if (item.Secret != secret)
return null;
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(SecretKey);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new Claim[]
{
new Claim(TokenId ,item.ID.ToString() ),
new Claim(ClaimTypes.Role, "Editor")
}),
Expires = DateTime.UtcNow.AddMinutes(5),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
};
var token = tokenHandler.CreateToken(tokenDescriptor);
var ret = tokenHandler.WriteToken(token);
return ret;
Nothing fancy – just SecretKey must be set in the appsettings.json file – and be enough large – otherwise an error occurs
For adding the TILTs to the own url , a custom authentication should be made. The code is not so simple, so I show here:
builder.Services.AddAuthorization(options=>
options.AddPolicy("CustomBearer", policy =>
{
policy.AuthenticationSchemes.Add("CustomBearer");
policy.RequireAuthenticatedUser();
}));
builder.Services.AddAuthentication()
.AddJwtBearer("CustomBearer",options =>
{
options.RequireHttpsMetadata = false;
options.SaveToken = true;
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(key)),
ValidateIssuer = false,
ValidateAudience = false
};
options.Events = new JwtBearerEvents()
{
OnMessageReceived = ctx =>
{
if (!(ctx?.Request?.Headers?.ContainsKey("Authorization") ?? true))
{
ctx.NoResult();
return Task.CompletedTask;
};
var auth = ctx.Request.Headers["Authorization"].ToString();
if (string.IsNullOrEmpty(auth))
{
ctx.NoResult();
return Task.CompletedTask;
}
if (!auth.StartsWith("CustomBearer ", StringComparison.OrdinalIgnoreCase))
{
ctx.NoResult();
return Task.CompletedTask;
}
ctx.Token = auth.Substring("CustomBearer ".Length).Trim();
return Task.CompletedTask;
}
};
});
and the controller will be
[Authorize(Policy = "CustomBearer", Roles = "Editor")]
[HttpPost]
public async Task<ActionResult<TILT_Note_Table>> AddTILT([FromServices] I_InsertDataApplicationDBContext insert, TILT_Note_Table note)
{
//TB: 2022-04-30 to be moved into a class - skinny controllers
var c = this.User?.Claims.ToArray();
var idUrl = auth.MainUrlId(c);
if (idUrl == null)
{
return new UnauthorizedResult();
}
note.IDURL = idUrl.Value;
note.ID = 0;
note.ForDate = DateTime.UtcNow;
var noteOrig = new TILT_Note();
noteOrig.CopyFrom(note);
await insert.InsertTILT_Note(noteOrig);
note.CopyFrom(noteOrig);
return note;
}
The
//TB: 2022-04-30 to be moved into a class - skinny controllers
is a time bomb comment- it will generate an error when compiling on the date.
Also, I have added CORS
builder.Services.AddCors(options =>
{
options.AddPolicy(name: "AllowAll",
policy =>
{
policy.AllowAnyHeader().AllowAnyMethod().AllowCredentials().SetIsOriginAllowed(it => true);
});
});
//code
var app = builder.Build();
//code
app.UseCors("AllowAll");
in order for the front-end ,no matter where it is , to work.
I have put SetIsOriginAllowed(it => true) in the policy – works with credentials.
Tools Used
RSCG_TimeBombComment
QueryGenerator Visual Studio
BoilerplateFree – to generate interface from an existing class
System.IdentityModel.Tokens.Jwt – to generate the token and decrypt the token Visual Studio