From 77816605d1106cf6c2176aad059e3abc115ce1e0 Mon Sep 17 00:00:00 2001 From: Reginald Cherenfant Jasmin Date: Wed, 20 Sep 2023 00:32:30 -0400 Subject: [PATCH] implementation of Authentication using JWT. Security applied on all microservices endpoints. --- .../Controllers/AnswersController.cs | 16 +- .../DamageAssesment.Api.Answers/Program.cs | 58 +++- .../Controllers/AttachmentsController.cs | 9 +- .../Program.cs | 57 +++- .../Controllers/DocumentsController.cs | 21 +- .../DASA_Documents/Active/Document_1.txt | 1 - .../DamageAssesment.Api.DocuLinks.csproj | 1 + .../DamageAssesment.Api.Documents/Program.cs | 59 +++- .../Properties/launchSettings.json | 2 +- .../appsettings.json | 4 + .../Controllers/EmployeesController.cs | 10 +- .../DamageAssesment.Api.Employees/Program.cs | 56 +++- .../appsettings.json | 7 +- .../Controllers/LocationsController.cs | 11 +- .../Controllers/RegionsController.cs | 11 +- .../DamageAssesment.Api.Locations/Program.cs | 60 +++- .../Controllers/QuestionsController.cs | 19 +- .../Models/Question.cs | 2 +- .../DamageAssesment.Api.Questions/Program.cs | 58 +++- .../Controllers/SurveyResponsesController.cs | 37 ++- ...j => DamageAssesment.Api.Responses.csproj} | 0 .../Interfaces/IAnswerServiceProvider.cs | 6 +- .../Interfaces/IAttachmentServiceProvider.cs | 4 +- .../Interfaces/IEmployeeServiceProvider.cs | 4 +- .../Interfaces/IHttpUtil.cs | 2 +- .../Interfaces/ILocationServiceProvider.cs | 2 +- .../Interfaces/IQuestionServiceProvider.cs | 6 +- .../Interfaces/IRegionServiceProvider.cs | 2 +- .../Interfaces/ISurveyServiceProvider.cs | 4 +- .../Interfaces/ISurveysResponse.cs | 16 +- .../Models/Employee.cs | 2 +- .../Program.cs | 56 +++- .../Providers/SurveyResponsesProvider.cs | 114 ++++--- .../Services/AnswerServiceProvider.cs | 13 +- .../Services/AttachmentServiceProvider.cs | 8 +- .../Services/EmployeeServiceProvider.cs | 8 +- .../Services/HttpUtil.cs | 7 +- .../Services/LocationServiceProvider.cs | 4 +- .../Services/QuestionServiceProvider.cs | 12 +- .../Services/RegionServiceProvider.cs | 4 +- .../Services/SurveyServiceProvider.cs | 8 +- .../appsettings.json | 3 + .../Controllers/SurveysController.cs | 9 +- .../DamageAssesment.Api.Surveys/Program.cs | 37 ++- .../Controllers/UsersAccessController.cs | 127 ++++++++ .../DamageAssesment.Api.UsersAccess.csproj | 20 ++ .../Db/Role.cs | 21 ++ .../Db/Token.cs | 17 + .../Db/User.cs | 31 ++ .../Db/UsersAccessDbContext.cs | 32 ++ .../Interfaces/IEmployeeServiceProvider.cs | 10 + .../Interfaces/IHttpUtil.cs | 7 + .../Interfaces/IRoleProvider.cs | 12 + .../Interfaces/ITokenServiceProvider.cs | 11 + .../Interfaces/IUsersAccessProvider.cs | 17 + .../Models/Employee.cs | 14 + .../Models/JwtSettings.cs | 9 + .../Models/Role.cs | 8 + .../Models/Token.cs | 10 + .../Models/TokenResponse.cs | 8 + .../Models/User.cs | 13 + .../Models/UserCredentials.cs | 5 + .../Profiles/UsersAccessProfile.cs | 14 + .../Program.cs | 146 +++++++++ .../Properties/launchSettings.json | 31 ++ .../Providers/UserAccessProvider.cs | 305 ++++++++++++++++++ .../Services/EmployeeServiceProvider.cs | 50 +++ .../Services/HttpUtil.cs | 42 +++ .../Services/ServiceProviderBase.cs | 25 ++ .../Services/TokenServiceProvider.cs | 59 ++++ .../appsettings.Development.json | 8 + .../appsettings.json | 36 +++ ...DamageAssesment.Api.Responses.Test.csproj} | 2 +- .../SurveyResponsesServiceTest.cs | 32 +- DamageAssesmentApi/DamageAssesment.sln | 11 +- 75 files changed, 1744 insertions(+), 219 deletions(-) delete mode 100644 DamageAssesmentApi/DamageAssesment.Api.Documents/DASA_Documents/Active/Document_1.txt rename DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/{DamageAssesment.Api.SurveyResponses.csproj => DamageAssesment.Api.Responses.csproj} (100%) create mode 100644 DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Controllers/UsersAccessController.cs create mode 100644 DamageAssesmentApi/DamageAssesment.Api.UsersAccess/DamageAssesment.Api.UsersAccess.csproj create mode 100644 DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Db/Role.cs create mode 100644 DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Db/Token.cs create mode 100644 DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Db/User.cs create mode 100644 DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Db/UsersAccessDbContext.cs create mode 100644 DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Interfaces/IEmployeeServiceProvider.cs create mode 100644 DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Interfaces/IHttpUtil.cs create mode 100644 DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Interfaces/IRoleProvider.cs create mode 100644 DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Interfaces/ITokenServiceProvider.cs create mode 100644 DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Interfaces/IUsersAccessProvider.cs create mode 100644 DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Models/Employee.cs create mode 100644 DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Models/JwtSettings.cs create mode 100644 DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Models/Role.cs create mode 100644 DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Models/Token.cs create mode 100644 DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Models/TokenResponse.cs create mode 100644 DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Models/User.cs create mode 100644 DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Models/UserCredentials.cs create mode 100644 DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Profiles/UsersAccessProfile.cs create mode 100644 DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Program.cs create mode 100644 DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Properties/launchSettings.json create mode 100644 DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Providers/UserAccessProvider.cs create mode 100644 DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Services/EmployeeServiceProvider.cs create mode 100644 DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Services/HttpUtil.cs create mode 100644 DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Services/ServiceProviderBase.cs create mode 100644 DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Services/TokenServiceProvider.cs create mode 100644 DamageAssesmentApi/DamageAssesment.Api.UsersAccess/appsettings.Development.json create mode 100644 DamageAssesmentApi/DamageAssesment.Api.UsersAccess/appsettings.json rename DamageAssesmentApi/DamageAssesment.SurveyResponses.Test/{DamageAssesment.Api.SurveyResponses.Test.csproj => DamageAssesment.Api.Responses.Test.csproj} (95%) diff --git a/DamageAssesmentApi/DamageAssesment.Api.Answers/Controllers/AnswersController.cs b/DamageAssesmentApi/DamageAssesment.Api.Answers/Controllers/AnswersController.cs index a86cbf1..f794283 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Answers/Controllers/AnswersController.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Answers/Controllers/AnswersController.cs @@ -1,7 +1,6 @@ using DamageAssesment.Api.Answers.Interfaces; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -using Microsoft.EntityFrameworkCore; -using Microsoft.OpenApi.Any; namespace DamageAssesment.Api.Answers.Controllers { @@ -16,7 +15,7 @@ namespace DamageAssesment.Api.Answers.Controllers /// /// Get all answers /// - + [Authorize(Roles = "admin")] [HttpGet("Answers")] public async Task GetAnswersAsync() { @@ -32,7 +31,7 @@ namespace DamageAssesment.Api.Answers.Controllers /// Get an answer based on answerId. /// - + [Authorize(Roles = "admin")] [HttpGet("Answers/{Id}")] public async Task GetAnswerByIdAsync(int Id) { @@ -48,6 +47,7 @@ namespace DamageAssesment.Api.Answers.Controllers /// /// Get all answers based on responseId. /// + [Authorize(Roles = "admin")] [HttpGet("Answers/ByResponse/{responseid}")] public async Task GetAnswersByResponseId(int responseid) { @@ -61,7 +61,7 @@ namespace DamageAssesment.Api.Answers.Controllers /// /// Get all answers based on questionId. /// - + [Authorize(Roles = "admin")] [HttpGet("Answers/ByQuestion/{questionid}")] public async Task AnswersByQuestionId(int questionid) { @@ -75,7 +75,7 @@ namespace DamageAssesment.Api.Answers.Controllers /// /// Update an existing answer. /// - + [Authorize(Roles = "admin")] [HttpPut("Answers")] public async Task UpdateAnswer(Models.Answer answer) { @@ -96,7 +96,7 @@ namespace DamageAssesment.Api.Answers.Controllers /// /// Save a new answer. /// - + [Authorize(Roles = "admin")] [HttpPost("Answers")] public async Task CreateAnswer(Models.Answer answer) { @@ -114,7 +114,7 @@ namespace DamageAssesment.Api.Answers.Controllers /// /// Delete an existing answer. /// - + [Authorize(Roles = "admin")] [HttpDelete("Answers/{id}")] public async Task DeleteAnswer(int id) { diff --git a/DamageAssesmentApi/DamageAssesment.Api.Answers/Program.cs b/DamageAssesmentApi/DamageAssesment.Api.Answers/Program.cs index 7229cf9..95475fe 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Answers/Program.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Answers/Program.cs @@ -1,23 +1,73 @@ using DamageAssesment.Api.Answers.Db; using DamageAssesment.Api.Answers.Interfaces; using DamageAssesment.Api.Answers.Providers; +using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.EntityFrameworkCore; +using Microsoft.IdentityModel.Tokens; +using Microsoft.OpenApi.Models; using System.Reflection; +using System.Text; var builder = WebApplication.CreateBuilder(args); - +var authkey = builder.Configuration.GetValue("JwtSettings:securitykey"); +builder.Services.AddAuthentication(item => +{ + item.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; + item.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; +}).AddJwtBearer(item => +{ + item.RequireHttpsMetadata = true; + item.SaveToken = true; + item.TokenValidationParameters = new TokenValidationParameters() + { + ValidateIssuerSigningKey = true, + IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(authkey)), + ValidateIssuer = false, + ValidateAudience = false, + ClockSkew = TimeSpan.Zero + }; +}); // Add services to the container. builder.Services.AddControllers(); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); //builder.Services.AddSwaggerGen(); -builder.Services.AddSwaggerGen(c => +builder.Services.AddSwaggerGen(options => { // Include XML comments from your assembly var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); - c.IncludeXmlComments(xmlPath); + options.IncludeXmlComments(xmlPath); + + OpenApiSecurityScheme securityDefinition = new OpenApiSecurityScheme() + { + Name = "Bearer", + BearerFormat = "JWT", + Scheme = "bearer", + Description = "Specify the authorization token.", + In = ParameterLocation.Header, + Type = SecuritySchemeType.Http, + }; + + options.AddSecurityDefinition("jwt_auth", securityDefinition); + + // Make sure swagger UI requires a Bearer token specified + OpenApiSecurityScheme securityScheme = new OpenApiSecurityScheme() + { + Reference = new OpenApiReference() + { + Id = "jwt_auth", + Type = ReferenceType.SecurityScheme + } + }; + + OpenApiSecurityRequirement securityRequirements = new OpenApiSecurityRequirement() + { + {securityScheme, new string[] { }}, + }; + + options.AddSecurityRequirement(securityRequirements); }); builder.Services.AddScoped(); builder.Services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); //4/30 @@ -35,7 +85,7 @@ if (app.Environment.IsDevelopment()) app.UseSwagger(); app.UseSwaggerUI(); } - +app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); diff --git a/DamageAssesmentApi/DamageAssesment.Api.Attachments/Controllers/AttachmentsController.cs b/DamageAssesmentApi/DamageAssesment.Api.Attachments/Controllers/AttachmentsController.cs index 0fcec65..4245281 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Attachments/Controllers/AttachmentsController.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Attachments/Controllers/AttachmentsController.cs @@ -1,6 +1,7 @@ using Azure; using DamageAssesment.Api.Attachments.Interfaces; using DamageAssesment.Api.Attachments.Models; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using System.Net.Http.Headers; @@ -21,7 +22,7 @@ namespace DamageAssesment.Api.Attachments.Controllers /// /// Get all attachments. /// - + [Authorize(Roles = "admin")] [HttpGet("Attachments")] public async Task GetAttachmentsAsync() { @@ -37,6 +38,7 @@ namespace DamageAssesment.Api.Attachments.Controllers /// /// Get all attachments by attachmentId. /// + [Authorize(Roles = "admin")] [HttpGet("Attachments/{id}")] public async Task GetAttachmentbyIdAsync(int id) { @@ -80,7 +82,7 @@ namespace DamageAssesment.Api.Attachments.Controllers /// /// Save new Attachment(s) /// - + [Authorize(Roles = "admin")] [HttpPost("Attachments"), DisableRequestSizeLimit] public async Task UploadAttachmentAsync(AttachmentInfo attachmentInfo) { @@ -107,7 +109,7 @@ namespace DamageAssesment.Api.Attachments.Controllers /// /// Modify an new attachment. /// - + [Authorize(Roles = "admin")] [HttpPut("Attachments"), DisableRequestSizeLimit] public async Task UpdateAttachmentAsync(AttachmentInfo attachmentInfo) { @@ -138,6 +140,7 @@ namespace DamageAssesment.Api.Attachments.Controllers /// /// Delete an existing attachment. /// + [Authorize(Roles = "admin")] [HttpDelete("Attachments/{id}")] public async Task DeleteAttachment(int id) { diff --git a/DamageAssesmentApi/DamageAssesment.Api.Attachments/Program.cs b/DamageAssesmentApi/DamageAssesment.Api.Attachments/Program.cs index 61ce1c5..9368b21 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Attachments/Program.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Attachments/Program.cs @@ -1,25 +1,75 @@ using DamageAssesment.Api.Attachments.Db; using DamageAssesment.Api.Attachments.Interfaces; using DamageAssesment.Api.Attachments.Providers; +using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Http.Features; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.FileProviders; +using Microsoft.IdentityModel.Tokens; +using Microsoft.OpenApi.Models; using System.Reflection; +using System.Text; var builder = WebApplication.CreateBuilder(args); - +var authkey = builder.Configuration.GetValue("JwtSettings:securitykey"); +builder.Services.AddAuthentication(item => +{ + item.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; + item.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; +}).AddJwtBearer(item => +{ + item.RequireHttpsMetadata = true; + item.SaveToken = true; + item.TokenValidationParameters = new TokenValidationParameters() + { + ValidateIssuerSigningKey = true, + IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(authkey)), + ValidateIssuer = false, + ValidateAudience = false, + ClockSkew = TimeSpan.Zero + }; +}); // Add services to the container. builder.Services.AddControllers(); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); //builder.Services.AddSwaggerGen(); -builder.Services.AddSwaggerGen(c => +builder.Services.AddSwaggerGen(options => { // Include XML comments from your assembly var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); - c.IncludeXmlComments(xmlPath); + options.IncludeXmlComments(xmlPath); + + OpenApiSecurityScheme securityDefinition = new OpenApiSecurityScheme() + { + Name = "Bearer", + BearerFormat = "JWT", + Scheme = "bearer", + Description = "Specify the authorization token.", + In = ParameterLocation.Header, + Type = SecuritySchemeType.Http, + }; + + options.AddSecurityDefinition("jwt_auth", securityDefinition); + + // Make sure swagger UI requires a Bearer token specified + OpenApiSecurityScheme securityScheme = new OpenApiSecurityScheme() + { + Reference = new OpenApiReference() + { + Id = "jwt_auth", + Type = ReferenceType.SecurityScheme + } + }; + + OpenApiSecurityRequirement securityRequirements = new OpenApiSecurityRequirement() + { + {securityScheme, new string[] { }}, + }; + + options.AddSecurityRequirement(securityRequirements); }); builder.Services.AddScoped(); builder.Services.AddScoped(); @@ -45,6 +95,7 @@ if (app.Environment.IsDevelopment()) app.UseSwaggerUI(); } +app.UseAuthentication(); app.UseAuthorization(); app.UseHttpsRedirection(); diff --git a/DamageAssesmentApi/DamageAssesment.Api.Documents/Controllers/DocumentsController.cs b/DamageAssesmentApi/DamageAssesment.Api.Documents/Controllers/DocumentsController.cs index dcf43b9..baeb7b3 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Documents/Controllers/DocumentsController.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Documents/Controllers/DocumentsController.cs @@ -2,6 +2,7 @@ using DamageAssesment.Api.Documents.Interfaces; using DamageAssesment.Api.Documents.Models; using DamageAssesment.Api.Documents.Providers; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; @@ -24,6 +25,7 @@ namespace DamageAssesment.Api.Documents.Controllers /// Get all document link type. /// [HttpGet] + [Authorize(Roles = "admin")] [Route("doculinks/types")] public async Task GetLinkTypesAsync() { @@ -37,6 +39,7 @@ namespace DamageAssesment.Api.Documents.Controllers /// /// Get a document link type by id. /// + [Authorize(Roles = "admin")] [HttpGet] [Route("doculinks/types/{id}")] public async Task GetLinkTypeAsync(int id) @@ -51,6 +54,7 @@ namespace DamageAssesment.Api.Documents.Controllers /// /// Update a existing document link type. /// + [Authorize(Roles = "admin")] [HttpPut] [Route("doculinks/types")] public async Task UpdateLinkType(Models.LinkType linkType) @@ -72,6 +76,7 @@ namespace DamageAssesment.Api.Documents.Controllers /// /// Create a new document link type. /// + [Authorize(Roles = "admin")] [HttpPost] [Route("doculinks/types")] public async Task CreateLinkType(Models.LinkType linkType) @@ -90,6 +95,7 @@ namespace DamageAssesment.Api.Documents.Controllers /// /// Delete a existing document link type by id. /// + [Authorize(Roles = "admin")] [HttpDelete] [Route("doculinks/types/{id}")] public async Task DeleteLinkType(int id) @@ -101,11 +107,12 @@ namespace DamageAssesment.Api.Documents.Controllers } return NotFound(); } - /// - /// Get all documents. - /// - /// - [Route("doculinks")] + /// + /// Get all documents. + /// + + [Authorize(Roles = "admin")] + [Route("doculinks")] [Route("doculinks/{linktype:alpha}")] [Route("doculinks/{linktype:alpha}/{language:alpha}")] [HttpGet] @@ -138,6 +145,7 @@ namespace DamageAssesment.Api.Documents.Controllers /// /// Get a document by id. /// + [Authorize(Roles = "admin")] [HttpGet] [Route("doculinks/{id}")] [Route("doculinks/{id}/{linktype:alpha}")] @@ -154,6 +162,7 @@ namespace DamageAssesment.Api.Documents.Controllers /// /// Upload new document. /// + [Authorize(Roles = "admin")] [HttpPut] [Route("doculinks/{id}")] public async Task UpdateDocument(int id,DocumentInfo documentInfo) @@ -178,6 +187,7 @@ namespace DamageAssesment.Api.Documents.Controllers /// /// update existing document. /// + [Authorize(Roles = "admin")] [HttpPost] [Route("doculinks")] public async Task CreateDocument(DocumentInfo documentInfo) @@ -205,6 +215,7 @@ namespace DamageAssesment.Api.Documents.Controllers /// /// Delete document by id. /// + [Authorize(Roles = "admin")] [HttpDelete] [Route("doculinks/{id}")] public async Task DeleteDocument(int id) diff --git a/DamageAssesmentApi/DamageAssesment.Api.Documents/DASA_Documents/Active/Document_1.txt b/DamageAssesmentApi/DamageAssesment.Api.Documents/DASA_Documents/Active/Document_1.txt deleted file mode 100644 index eed7e79..0000000 --- a/DamageAssesmentApi/DamageAssesment.Api.Documents/DASA_Documents/Active/Document_1.txt +++ /dev/null @@ -1 +0,0 @@ -sample \ No newline at end of file diff --git a/DamageAssesmentApi/DamageAssesment.Api.Documents/DamageAssesment.Api.DocuLinks.csproj b/DamageAssesmentApi/DamageAssesment.Api.Documents/DamageAssesment.Api.DocuLinks.csproj index dab0e6c..f7da769 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Documents/DamageAssesment.Api.DocuLinks.csproj +++ b/DamageAssesmentApi/DamageAssesment.Api.Documents/DamageAssesment.Api.DocuLinks.csproj @@ -10,6 +10,7 @@ + diff --git a/DamageAssesmentApi/DamageAssesment.Api.Documents/Program.cs b/DamageAssesmentApi/DamageAssesment.Api.Documents/Program.cs index c9db54e..8134622 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Documents/Program.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Documents/Program.cs @@ -2,23 +2,73 @@ using DamageAssesment.Api.Documents.Db; using DamageAssesment.Api.Documents.Interfaces; using DamageAssesment.Api.Documents.Providers; using Microsoft.EntityFrameworkCore; +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.IdentityModel.Tokens; using System.Reflection; +using System.Text; +using Microsoft.OpenApi.Models; var builder = WebApplication.CreateBuilder(args); // Add services to the container. - +var authkey = builder.Configuration.GetValue("JwtSettings:securitykey"); +builder.Services.AddAuthentication(item => +{ + item.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; + item.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; +}).AddJwtBearer(item => +{ + item.RequireHttpsMetadata = true; + item.SaveToken = true; + item.TokenValidationParameters = new TokenValidationParameters() + { + ValidateIssuerSigningKey = true, + IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(authkey)), + ValidateIssuer = false, + ValidateAudience = false, + ClockSkew = TimeSpan.Zero + }; +}); builder.Services.AddControllers(); -builder.Services.AddSwaggerGen(c => +builder.Services.AddSwaggerGen(options => { // Include XML comments from your assembly var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); - c.IncludeXmlComments(xmlPath); + options.IncludeXmlComments(xmlPath); + + OpenApiSecurityScheme securityDefinition = new OpenApiSecurityScheme() + { + Name = "Bearer", + BearerFormat = "JWT", + Scheme = "bearer", + Description = "Specify the authorization token.", + In = ParameterLocation.Header, + Type = SecuritySchemeType.Http, + }; + + options.AddSecurityDefinition("jwt_auth", securityDefinition); + + // Make sure swagger UI requires a Bearer token specified + OpenApiSecurityScheme securityScheme = new OpenApiSecurityScheme() + { + Reference = new OpenApiReference() + { + Id = "jwt_auth", + Type = ReferenceType.SecurityScheme + } + }; + + OpenApiSecurityRequirement securityRequirements = new OpenApiSecurityRequirement() + { + {securityScheme, new string[] { }}, + }; + + options.AddSecurityRequirement(securityRequirements); }); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); -builder.Services.AddSwaggerGen(); +//builder.Services.AddSwaggerGen(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); @@ -36,6 +86,7 @@ if (app.Environment.IsDevelopment()) app.UseSwaggerUI(); } +app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); diff --git a/DamageAssesmentApi/DamageAssesment.Api.Documents/Properties/launchSettings.json b/DamageAssesmentApi/DamageAssesment.Api.Documents/Properties/launchSettings.json index e4e08ae..fcc4c27 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Documents/Properties/launchSettings.json +++ b/DamageAssesmentApi/DamageAssesment.Api.Documents/Properties/launchSettings.json @@ -14,7 +14,7 @@ "dotnetRunMessages": true, "launchBrowser": true, "launchUrl": "swagger", - "applicationUrl": "http://localhost:5133", + "applicationUrl": "http://localhost:5136", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } diff --git a/DamageAssesmentApi/DamageAssesment.Api.Documents/appsettings.json b/DamageAssesmentApi/DamageAssesment.Api.Documents/appsettings.json index e38d9fb..9d665b2 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Documents/appsettings.json +++ b/DamageAssesmentApi/DamageAssesment.Api.Documents/appsettings.json @@ -6,8 +6,12 @@ } }, "AllowedHosts": "*", + "JwtSettings": { + "securitykey": "bWlhbWkgZGFkZSBzY2hvb2xzIHNlY3JldCBrZXk=" + }, "Fileupload": { "folderpath": "DASA_Documents/Active", "Deletepath": "DASA_Documents/Deleted" } } + diff --git a/DamageAssesmentApi/DamageAssesment.Api.Employees/Controllers/EmployeesController.cs b/DamageAssesmentApi/DamageAssesment.Api.Employees/Controllers/EmployeesController.cs index f5e0d88..019df03 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Employees/Controllers/EmployeesController.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Employees/Controllers/EmployeesController.cs @@ -1,4 +1,5 @@ using DamageAssesment.Api.Employees.Interfaces; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; @@ -18,7 +19,7 @@ namespace DamageAssesment.Api.Employees.Controllers /// /// GET request for retrieving employees. /// - + [Authorize(Roles = "admin")] [HttpGet("Employees")] public async Task GetEmployeesAsync() { @@ -35,7 +36,7 @@ namespace DamageAssesment.Api.Employees.Controllers /// /// GET request for retrieving an employee by ID. /// - + [Authorize(Roles = "admin")] [HttpGet("Employees/{id}")] public async Task GetEmployeeByIdAsync(int id) { @@ -48,11 +49,12 @@ namespace DamageAssesment.Api.Employees.Controllers return NotFound(); } - + /// /// PUT request for updating an existing employee. /// /// The updated employee object. + [Authorize(Roles = "admin")] [HttpPut("Employees/{id}")] public async Task UpdateEmployee(int id, Models.Employee Employee) { @@ -75,6 +77,7 @@ namespace DamageAssesment.Api.Employees.Controllers /// POST request for creating a new employee. /// /// The employee information for creating a new employee. + [Authorize(Roles = "admin")] [HttpPost("Employees")] public async Task CreateEmployee(Models.Employee Employee) { @@ -93,6 +96,7 @@ namespace DamageAssesment.Api.Employees.Controllers /// DELETE request for deleting an existing employee. /// /// The ID of the employee to be deleted. + [Authorize(Roles = "admin")] [HttpDelete("Employees/{id}")] public async Task DeleteEmployee(int id) { diff --git a/DamageAssesmentApi/DamageAssesment.Api.Employees/Program.cs b/DamageAssesmentApi/DamageAssesment.Api.Employees/Program.cs index 1e88127..a4cf2df 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Employees/Program.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Employees/Program.cs @@ -1,23 +1,74 @@ using DamageAssesment.Api.Employees.Db; using DamageAssesment.Api.Employees.Interfaces; using DamageAssesment.Api.Employees.Providers; +using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.EntityFrameworkCore; +using Microsoft.IdentityModel.Tokens; +using Microsoft.OpenApi.Models; using System.Reflection; +using System.Text; var builder = WebApplication.CreateBuilder(args); // Add services to the container. +var authkey = builder.Configuration.GetValue("JwtSettings:securitykey"); +builder.Services.AddAuthentication(item => +{ + item.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; + item.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; +}).AddJwtBearer(item => +{ + item.RequireHttpsMetadata = true; + item.SaveToken = true; + item.TokenValidationParameters = new TokenValidationParameters() + { + ValidateIssuerSigningKey = true, + IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(authkey)), + ValidateIssuer = false, + ValidateAudience = false, + ClockSkew = TimeSpan.Zero + }; +}); builder.Services.AddControllers(); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); //builder.Services.AddSwaggerGen(); -builder.Services.AddSwaggerGen(c => +builder.Services.AddSwaggerGen(options => { // Include XML comments from your assembly var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); - c.IncludeXmlComments(xmlPath); + options.IncludeXmlComments(xmlPath); + + OpenApiSecurityScheme securityDefinition = new OpenApiSecurityScheme() + { + Name = "Bearer", + BearerFormat = "JWT", + Scheme = "bearer", + Description = "Specify the authorization token.", + In = ParameterLocation.Header, + Type = SecuritySchemeType.Http, + }; + + options.AddSecurityDefinition("jwt_auth", securityDefinition); + + // Make sure swagger UI requires a Bearer token specified + OpenApiSecurityScheme securityScheme = new OpenApiSecurityScheme() + { + Reference = new OpenApiReference() + { + Id = "jwt_auth", + Type = ReferenceType.SecurityScheme + } + }; + + OpenApiSecurityRequirement securityRequirements = new OpenApiSecurityRequirement() + { + {securityScheme, new string[] { }}, + }; + + options.AddSecurityRequirement(securityRequirements); }); builder.Services.AddScoped(); @@ -43,6 +94,7 @@ if (app.Environment.IsDevelopment()) } } +app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); diff --git a/DamageAssesmentApi/DamageAssesment.Api.Employees/appsettings.json b/DamageAssesmentApi/DamageAssesment.Api.Employees/appsettings.json index 1a1f3fe..ff5949d 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Employees/appsettings.json +++ b/DamageAssesmentApi/DamageAssesment.Api.Employees/appsettings.json @@ -8,10 +8,5 @@ "Microsoft.AspNetCore": "Warning" } }, - "AllowedHosts": "*", - "settings": { - "endpoint1": "xxx", - "endpoint2": "xxx", - "endpoint3": "xxx" - } + "AllowedHosts": "*" } diff --git a/DamageAssesmentApi/DamageAssesment.Api.Locations/Controllers/LocationsController.cs b/DamageAssesmentApi/DamageAssesment.Api.Locations/Controllers/LocationsController.cs index d9bbea3..da06bee 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Locations/Controllers/LocationsController.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Locations/Controllers/LocationsController.cs @@ -1,4 +1,5 @@ using DamageAssesment.Api.Locations.Interfaces; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; @@ -15,7 +16,7 @@ namespace DamageAssesment.Api.Locations.Controllers /// /// Get all locations. /// - + [Authorize(Roles = "admin")] [HttpGet("Locations")] public async Task GetLocationsAsync() { @@ -31,7 +32,7 @@ namespace DamageAssesment.Api.Locations.Controllers /// /// Get all locations based on locationdId. /// - + [Authorize(Roles = "admin")] [HttpGet("Locations/{id}")] public async Task GetLocationByIdAsync(int id) { @@ -47,7 +48,7 @@ namespace DamageAssesment.Api.Locations.Controllers /// /// Update a Location. /// - + [Authorize(Roles = "admin")] [HttpPut("Locations/{id}")] public async Task UpdateLocation(int id, Models.Location Location) { @@ -65,7 +66,7 @@ namespace DamageAssesment.Api.Locations.Controllers /// /// Save a new location. /// - + [Authorize(Roles = "admin")] [HttpPost("Locations")] public async Task CreateLocation(Models.Location Location) { @@ -83,7 +84,7 @@ namespace DamageAssesment.Api.Locations.Controllers /// /// Delete an existing location. /// - + [Authorize(Roles = "admin")] [HttpDelete("Locations/{id}")] public async Task DeleteLocation(int id) { diff --git a/DamageAssesmentApi/DamageAssesment.Api.Locations/Controllers/RegionsController.cs b/DamageAssesmentApi/DamageAssesment.Api.Locations/Controllers/RegionsController.cs index 172043c..d7fe03c 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Locations/Controllers/RegionsController.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Locations/Controllers/RegionsController.cs @@ -1,4 +1,5 @@ using DamageAssesment.Api.Locations.Interfaces; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; namespace DamageAssesment.Api.Locations.Controllers @@ -15,7 +16,7 @@ namespace DamageAssesment.Api.Locations.Controllers /// /// Get all regions.2 /// - + [Authorize(Roles = "admin")] [HttpGet("regions")] public async Task GetRegionsAsync() { @@ -29,7 +30,7 @@ namespace DamageAssesment.Api.Locations.Controllers /// /// GET request for retrieving a region by its ID. /// - + [Authorize(Roles = "admin")] [HttpGet("regions/{id}")] public async Task GetRegionAsync(int id) { @@ -43,7 +44,7 @@ namespace DamageAssesment.Api.Locations.Controllers /// /// POST request for creating a new region. /// - + [Authorize(Roles = "admin")] [HttpPost("regions")] public async Task PostRegionAsync(Models.Region region) { @@ -57,7 +58,7 @@ namespace DamageAssesment.Api.Locations.Controllers /// /// PUT request for updating an existing region. /// - + [Authorize(Roles = "admin")] [HttpPut("regions/{id}")] public async Task PutRegionAsync(int id, Models.Region region) { @@ -75,7 +76,7 @@ namespace DamageAssesment.Api.Locations.Controllers /// DELETE request for deleting a region based on ID. /// - + [Authorize(Roles = "admin")] [HttpDelete("regions/{id}")] public async Task DeleteRegionAsync(int id) { diff --git a/DamageAssesmentApi/DamageAssesment.Api.Locations/Program.cs b/DamageAssesmentApi/DamageAssesment.Api.Locations/Program.cs index 200e39b..6563a8b 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Locations/Program.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Locations/Program.cs @@ -1,23 +1,73 @@ using DamageAssesment.Api.Locations.Db; using DamageAssesment.Api.Locations.Interfaces; using DamageAssesment.Api.Locations.Providers; +using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.EntityFrameworkCore; +using Microsoft.IdentityModel.Tokens; +using Microsoft.OpenApi.Models; using System.Reflection; +using System.Text; var builder = WebApplication.CreateBuilder(args); // Add services to the container. - +var authkey = builder.Configuration.GetValue("JwtSettings:securitykey"); +builder.Services.AddAuthentication(item => +{ + item.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; + item.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; +}).AddJwtBearer(item => +{ + item.RequireHttpsMetadata = true; + item.SaveToken = true; + item.TokenValidationParameters = new TokenValidationParameters() + { + ValidateIssuerSigningKey = true, + IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(authkey)), + ValidateIssuer = false, + ValidateAudience = false, + ClockSkew = TimeSpan.Zero + }; +}); builder.Services.AddControllers(); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); //builder.Services.AddSwaggerGen(); -builder.Services.AddSwaggerGen(c => +builder.Services.AddSwaggerGen(options => { // Include XML comments from your assembly var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); - c.IncludeXmlComments(xmlPath); + options.IncludeXmlComments(xmlPath); + + OpenApiSecurityScheme securityDefinition = new OpenApiSecurityScheme() + { + Name = "Bearer", + BearerFormat = "JWT", + Scheme = "bearer", + Description = "Specify the authorization token.", + In = ParameterLocation.Header, + Type = SecuritySchemeType.Http, + }; + + options.AddSecurityDefinition("jwt_auth", securityDefinition); + + // Make sure swagger UI requires a Bearer token specified + OpenApiSecurityScheme securityScheme = new OpenApiSecurityScheme() + { + Reference = new OpenApiReference() + { + Id = "jwt_auth", + Type = ReferenceType.SecurityScheme + } + }; + + OpenApiSecurityRequirement securityRequirements = new OpenApiSecurityRequirement() + { + {securityScheme, new string[] { }}, + }; + + options.AddSecurityRequirement(securityRequirements); }); builder.Services.AddScoped(); builder.Services.AddScoped(); @@ -26,7 +76,10 @@ builder.Services.AddDbContext(option => { option.UseInMemoryDatabase("Locations"); }); + + var app = builder.Build(); +// Add services to the container. // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) @@ -44,6 +97,7 @@ if (app.Environment.IsDevelopment()) } } +app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); diff --git a/DamageAssesmentApi/DamageAssesment.Api.Questions/Controllers/QuestionsController.cs b/DamageAssesmentApi/DamageAssesment.Api.Questions/Controllers/QuestionsController.cs index 17024eb..3799b40 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Questions/Controllers/QuestionsController.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Questions/Controllers/QuestionsController.cs @@ -1,4 +1,5 @@ using DamageAssesment.Api.Questions.Interfaces; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; namespace DamageAssesment.Api.Questions.Controllers @@ -10,16 +11,14 @@ namespace DamageAssesment.Api.Questions.Controllers public QuestionsController(IQuestionsProvider questionsProvider) { - this.questionsProvider = questionsProvider; - } - /// /// GET request for retrieving questions. /// - // get all questions + //get all questions + [Authorize(Roles = "admin,survey,user,report")] [Route("Questions")] [Route("Questions/{language:alpha}")] [HttpGet] @@ -37,6 +36,7 @@ namespace DamageAssesment.Api.Questions.Controllers /// /// GET request for retrieving a question by ID. /// + [Authorize(Roles = "admin,survey,user,report")] [Route("Questions/{id}/{language:alpha}")] [Route("Questions/{id:int}")] [HttpGet] @@ -55,6 +55,7 @@ namespace DamageAssesment.Api.Questions.Controllers /// GET request for retrieving survey questions based on a survey ID. /// Uri: {Optional language}/GetSurveyQuestions/{surveyId} :Default returns question in all languages /// + [Authorize(Roles = "admin,survey,user,report")] [Route("Questions/BySurvey/{surveyId:int}")] [Route("Questions/BySurvey/{surveyId:int}/{language:alpha}")] [HttpGet] @@ -71,6 +72,7 @@ namespace DamageAssesment.Api.Questions.Controllers /// PUT request for updating a question (multilingual). /// + [Authorize(Roles = "admin")] [HttpPut("Questions")] public async Task UpdateQuestion(Models.Question question) { @@ -92,6 +94,7 @@ namespace DamageAssesment.Api.Questions.Controllers /// POST request for creating a new question (multilingual). /// + [Authorize(Roles = "admin")] [HttpPost("Questions")] public async Task CreateQuestion(Models.Question question) { @@ -110,6 +113,7 @@ namespace DamageAssesment.Api.Questions.Controllers /// DELETE request for deleting a question based on ID. /// + [Authorize(Roles = "admin")] [HttpDelete("Questions/{id}")] public async Task DeleteQuestion(int id) { @@ -125,6 +129,7 @@ namespace DamageAssesment.Api.Questions.Controllers /// GET request for retrieving question categories. /// + [Authorize(Roles = "admin,user,report")] [HttpGet("Questions/Categories")] [HttpGet("Questions/Categories/{language:alpha}")] public async Task GetQuestionCategoriesAsync(string? language) @@ -139,7 +144,7 @@ namespace DamageAssesment.Api.Questions.Controllers /// /// GET request for retrieving a question category by ID. /// - + [Authorize(Roles = "admin,report")] [HttpGet("Questions/Categories/{id:int}")] [HttpGet("Questions/Categories/{id:int}/{language:alpha}")] public async Task GetQuestionCategoryAsync(int id,string? language) @@ -156,7 +161,7 @@ namespace DamageAssesment.Api.Questions.Controllers /// /// PUT request for updating a question category. /// - + [Authorize(Roles = "admin,survey,report")] [HttpPut("Questions/Categories")] public async Task UpdateQuestionCategory(Models.QuestionCategory questionCategory) { @@ -178,6 +183,7 @@ namespace DamageAssesment.Api.Questions.Controllers /// POST request for creating a new question category. /// + [Authorize(Roles = "admin")] [HttpPost("Questions/Categories")] public async Task CreateQuestionCategory(Models.QuestionCategory questionCategory) { @@ -196,6 +202,7 @@ namespace DamageAssesment.Api.Questions.Controllers /// DELETE request for deleting a question category based on ID. /// + [Authorize(Roles = "admin")] [HttpDelete("Questions/Categories/{id}")] public async Task DeleteQuestionCategory(int id) { diff --git a/DamageAssesmentApi/DamageAssesment.Api.Questions/Models/Question.cs b/DamageAssesmentApi/DamageAssesment.Api.Questions/Models/Question.cs index b6c1668..f7fe7fb 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Questions/Models/Question.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Questions/Models/Question.cs @@ -12,7 +12,7 @@ public bool IsRequired { get; set; } public bool Comment { get; set; } public bool Key { get; set; } - public int? SurveyId { get; set; } + public int SurveyId { get; set; } public int CategoryId { get; set; } } } diff --git a/DamageAssesmentApi/DamageAssesment.Api.Questions/Program.cs b/DamageAssesmentApi/DamageAssesment.Api.Questions/Program.cs index 073cb10..ac0eed7 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Questions/Program.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Questions/Program.cs @@ -1,11 +1,33 @@ using DamageAssesment.Api.Questions.Db; using DamageAssesment.Api.Questions.Interfaces; using DamageAssesment.Api.Questions.Providers; +using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.EntityFrameworkCore; +using Microsoft.IdentityModel.Tokens; +using Microsoft.OpenApi.Models; using System.Reflection; +using System.Text; var builder = WebApplication.CreateBuilder(args); - +// Add services to the container. +var authkey = builder.Configuration.GetValue("JwtSettings:securitykey"); +builder.Services.AddAuthentication(item => +{ + item.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; + item.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; +}).AddJwtBearer(item => +{ + item.RequireHttpsMetadata = true; + item.SaveToken = true; + item.TokenValidationParameters = new TokenValidationParameters() + { + ValidateIssuerSigningKey = true, + IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(authkey)), + ValidateIssuer = false, + ValidateAudience = false, + ClockSkew = TimeSpan.Zero + }; +}); // Add services to the container. builder.Services.AddControllers(); @@ -17,13 +39,41 @@ builder.Services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); builder.Services.AddEndpointsApiExplorer(); //builder.Services.AddSwaggerGen(); -builder.Services.AddSwaggerGen(c => +builder.Services.AddSwaggerGen(options => { // Include XML comments from your assembly var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); - c.IncludeXmlComments(xmlPath); + options.IncludeXmlComments(xmlPath); + + OpenApiSecurityScheme securityDefinition = new OpenApiSecurityScheme() + { + Name = "Bearer", + BearerFormat = "JWT", + Scheme = "bearer", + Description = "Specify the authorization token.", + In = ParameterLocation.Header, + Type = SecuritySchemeType.Http, + }; + + options.AddSecurityDefinition("jwt_auth", securityDefinition); + + // Make sure swagger UI requires a Bearer token specified + OpenApiSecurityScheme securityScheme = new OpenApiSecurityScheme() + { + Reference = new OpenApiReference() + { + Id = "jwt_auth", + Type = ReferenceType.SecurityScheme + } + }; + OpenApiSecurityRequirement securityRequirements = new OpenApiSecurityRequirement() + { + {securityScheme, new string[] { }}, + }; + options.AddSecurityRequirement(securityRequirements); }); + builder.Services.AddDbContext(option => { option.UseInMemoryDatabase("Questions"); @@ -43,7 +93,7 @@ if (app.Environment.IsDevelopment()) questionProvider.SeedData(); } } - +app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Controllers/SurveyResponsesController.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Controllers/SurveyResponsesController.cs index e5f3917..3e9246f 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Controllers/SurveyResponsesController.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Controllers/SurveyResponsesController.cs @@ -3,6 +3,7 @@ using DamageAssesment.Api.SurveyResponses.Models; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; +using System.IdentityModel.Tokens.Jwt; namespace DamageAssesment.Api.SurveyResponses.Controllers { @@ -10,10 +11,20 @@ namespace DamageAssesment.Api.SurveyResponses.Controllers public class SurveyResponsesController : ControllerBase { private readonly ISurveysResponse surveyResponseProvider; - - public SurveyResponsesController(ISurveysResponse surveyResponseProvider) + private string token; + private readonly IHttpContextAccessor httpContextAccessor; + public SurveyResponsesController(ISurveysResponse surveyResponseProvider, IHttpContextAccessor httpContextAccessor) { this.surveyResponseProvider = surveyResponseProvider; + this.httpContextAccessor = httpContextAccessor; + token = httpContextAccessor.HttpContext.Request.Headers.Authorization; + if (token != null) + { + token = token.Replace("Bearer ", string.Empty); + } else + { + token = ""; + } } /// /// GET request for retrieving survey responses. @@ -22,7 +33,7 @@ namespace DamageAssesment.Api.SurveyResponses.Controllers [HttpGet("Responses")] public async Task GetSurveyResponsesAsync() { - var result = await this.surveyResponseProvider.GetSurveyResponsesAsync(); + var result = await this.surveyResponseProvider.GetSurveyResponsesAsync(token); if (result.IsSuccess) { return Ok(result.surveyResponses); @@ -36,11 +47,11 @@ namespace DamageAssesment.Api.SurveyResponses.Controllers /// /// GET request for retrieving survey responses by survey ID. /// - + [HttpGet("Responses/BySurvey/{surveyid}")] public async Task GetSurveyResponsesAsync(int surveyid) { - var result = await this.surveyResponseProvider.GetSurveyResponsesBySurveyAsync(surveyid); + var result = await this.surveyResponseProvider.GetSurveyResponsesBySurveyAsync(surveyid, token); if (result.IsSuccess) { return Ok(result.SurveyResponses); @@ -56,7 +67,7 @@ namespace DamageAssesment.Api.SurveyResponses.Controllers [HttpGet("Responses/{surveyid}/{locationid}")] public async Task GetSurveyResponsesBySurveyAndLocationAsync(int surveyid, int locationid) { - var result = await this.surveyResponseProvider.GetSurveyResponsesBySurveyAndLocationAsync(surveyid, locationid); + var result = await this.surveyResponseProvider.GetSurveyResponsesBySurveyAndLocationAsync(surveyid, locationid, token); if (result.IsSuccess) { return Ok(result.SurveyResponses); @@ -73,8 +84,8 @@ namespace DamageAssesment.Api.SurveyResponses.Controllers [HttpGet("Responses/ByAnswer/{surveyid}/{questionid}/{answer}")] public async Task GetSurveyResponsesByAnswerAsyncAsync(int surveyid, int questionid, string answer) - { - var result = await surveyResponseProvider.GetResponsesByAnswerAsync(surveyid, questionid, answer); + { + var result = await surveyResponseProvider.GetResponsesByAnswerAsync(surveyid, questionid, answer, token); if (result.IsSuccess) { return Ok(result.SurveyResponses); @@ -90,7 +101,7 @@ namespace DamageAssesment.Api.SurveyResponses.Controllers [HttpGet("Responses/ByRegion/{surveyid}")] public async Task GetAnswersByRegionAsync(int surveyid) { - var result = await this.surveyResponseProvider.GetAnswersByRegionAsync(surveyid); + var result = await this.surveyResponseProvider.GetAnswersByRegionAsync(surveyid, token); if (result.IsSuccess) { return Ok(result.Answers); @@ -105,7 +116,7 @@ namespace DamageAssesment.Api.SurveyResponses.Controllers [HttpGet("Responses/ByMaintenanceCenter/{surveyid}")] public async Task GetAnswersByMaintenaceCentersync(int surveyid) { - var result = await this.surveyResponseProvider.GetSurveyResponsesByMaintenanceCenterAsync(surveyid); + var result = await this.surveyResponseProvider.GetSurveyResponsesByMaintenanceCenterAsync(surveyid, token); if (result.IsSuccess) { return Ok(result.SurveyResponses); @@ -120,7 +131,7 @@ namespace DamageAssesment.Api.SurveyResponses.Controllers [HttpGet("Responses/{id}")] public async Task GetSurveyResponseByIdAsync(int id) { - var result = await this.surveyResponseProvider.GetSurveyResponseByIdAsync(id); + var result = await this.surveyResponseProvider.GetSurveyResponseByIdAsync(id, token); if (result.IsSuccess) { return Ok(result.SurveyResponse); @@ -165,7 +176,7 @@ namespace DamageAssesment.Api.SurveyResponses.Controllers /// /// DELETE request for deleting an existing survey response. /// - + [HttpDelete("Responses/{id}")] public async Task DeleteSurveyResponseAsync(int id) { @@ -184,7 +195,7 @@ namespace DamageAssesment.Api.SurveyResponses.Controllers [HttpPost("Responses/Answers")] public async Task PostSurveyAnswersAsync(Request request) { - var result = await this.surveyResponseProvider.PostSurveyAnswersAsync(request); + var result = await this.surveyResponseProvider.PostSurveyAnswersAsync(request, token); if (result.IsSuccess) return Ok(result.SurveyResponse); diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/DamageAssesment.Api.SurveyResponses.csproj b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/DamageAssesment.Api.Responses.csproj similarity index 100% rename from DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/DamageAssesment.Api.SurveyResponses.csproj rename to DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/DamageAssesment.Api.Responses.csproj diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/IAnswerServiceProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/IAnswerServiceProvider.cs index e947659..2517daa 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/IAnswerServiceProvider.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/IAnswerServiceProvider.cs @@ -4,9 +4,9 @@ namespace DamageAssesment.Api.SurveyResponses.Interfaces { public interface IAnswerServiceProvider { - Task> getAnswersAsync(); - Task> GetAnswersByResponseIdAsync(int responseId); + Task> getAnswersAsync(string token); + Task> GetAnswersByResponseIdAsync(int responseId, string token); - Task PostAnswersAsync(Models.Answer answer); + Task PostAnswersAsync(Models.Answer answer, string token); } } diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/IAttachmentServiceProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/IAttachmentServiceProvider.cs index a20c91c..f22c3d0 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/IAttachmentServiceProvider.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/IAttachmentServiceProvider.cs @@ -4,7 +4,7 @@ namespace DamageAssesment.Api.SurveyResponses.Interfaces { public interface IAttachmentServiceProvider { - Task> getAttachmentsAsync(); - Task> PostAttachmentsAsync(Models.AttachmentInfo attachmentInfo); + Task> getAttachmentsAsync(string token); + Task> PostAttachmentsAsync(Models.AttachmentInfo attachmentInfo, string token); } } diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/IEmployeeServiceProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/IEmployeeServiceProvider.cs index 62031d5..9b1d2e1 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/IEmployeeServiceProvider.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/IEmployeeServiceProvider.cs @@ -4,7 +4,7 @@ namespace DamageAssesment.Api.SurveyResponses.Interfaces { public interface IEmployeeServiceProvider { - Task> getEmployeesAsync(); - Task getEmployeeAsync(int employeeId); + Task> getEmployeesAsync(string token); + Task getEmployeeAsync(int employeeId, string token); } } diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/IHttpUtil.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/IHttpUtil.cs index e3f1e66..f262fa5 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/IHttpUtil.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/IHttpUtil.cs @@ -4,6 +4,6 @@ namespace DamageAssesment.Api.SurveyResponses.Interfaces { public interface IHttpUtil { - Task SendAsync(HttpMethod method, string url, string JsonInput); + Task SendAsync(HttpMethod method, string url, string JsonInput, string token); } } diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/ILocationServiceProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/ILocationServiceProvider.cs index 75db3f1..aae34b0 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/ILocationServiceProvider.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/ILocationServiceProvider.cs @@ -4,6 +4,6 @@ namespace DamageAssesment.Api.SurveyResponses.Interfaces { public interface ILocationServiceProvider { - Task> getLocationsAsync(); + Task> getLocationsAsync(string token); } } diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/IQuestionServiceProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/IQuestionServiceProvider.cs index ab5f5ba..4530034 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/IQuestionServiceProvider.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/IQuestionServiceProvider.cs @@ -4,8 +4,8 @@ namespace DamageAssesment.Api.SurveyResponses.Interfaces { public interface IQuestionServiceProvider { - Task> getQuestionsAsync(); - Task> getSurveyQuestionsAsync(int surveyId); - Task getQuestionsAsync(int questionId); + Task> getQuestionsAsync(string token); + Task> getSurveyQuestionsAsync(int surveyId, string token); + Task getQuestionsAsync(int questionId, string token); } } diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/IRegionServiceProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/IRegionServiceProvider.cs index 8aeb1f8..1d26e11 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/IRegionServiceProvider.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/IRegionServiceProvider.cs @@ -4,6 +4,6 @@ namespace DamageAssesment.Api.SurveyResponses.Interfaces { public interface IRegionServiceProvider { - Task> getRegionsAsync(); + Task> getRegionsAsync(string token); } } diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/ISurveyServiceProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/ISurveyServiceProvider.cs index 97d6461..7609d1d 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/ISurveyServiceProvider.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/ISurveyServiceProvider.cs @@ -4,7 +4,7 @@ namespace DamageAssesment.Api.SurveyResponses.Interfaces { public interface ISurveyServiceProvider { - Task> getSurveysAsync(); - Task getSurveyAsync(int surveyId); + Task> getSurveysAsync(string token); + Task getSurveyAsync(int surveyId,string token); } } diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/ISurveysResponse.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/ISurveysResponse.cs index 536353c..de31140 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/ISurveysResponse.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/ISurveysResponse.cs @@ -5,19 +5,19 @@ namespace DamageAssesment.Api.SurveyResponses.Interfaces { public interface ISurveysResponse { - Task<(bool IsSuccess, dynamic Answers, string ErrorMessage)> GetAnswersByRegionAsync(int surveyId); + Task<(bool IsSuccess, dynamic Answers, string ErrorMessage)> GetAnswersByRegionAsync(int surveyId, string token); Task<(bool IsSuccess, Models.SurveyResponse SurveyResponse, string ErrorMessage)> PostSurveyResponseAsync(Models.SurveyResponse surveyResponse); // Task<(bool IsSuccess,dynamic surveyResponses, string ErrorMessage)> GetSurveyResponseAsync(int responseId); - Task<(bool IsSuccess, dynamic surveyResponses, string ErrorMessage)> GetSurveyResponsesAsync(); + Task<(bool IsSuccess, dynamic surveyResponses, string ErrorMessage)> GetSurveyResponsesAsync(string token); Task<(bool IsSuccess, Models.SurveyResponse SurveyResponse, string ErrorMessage)> PutSurveyResponseAsync(int Id, Models.SurveyResponse surveyResponse); Task<(bool IsSuccess, Models.SurveyResponse SurveyResponse, string ErrorMessage)> DeleteSurveyResponseAsync(int Id); - Task<(bool IsSuccess, dynamic SurveyResponse, string ErrorMessage)> GetSurveyResponseByIdAsync(int responseId); - Task<(bool IsSuccess, dynamic SurveyResponses, string ErrorMessage)> GetSurveyResponsesBySurveyAsync(int surveyId); - Task<(bool IsSuccess, dynamic SurveyResponses, string ErrorMessage)> GetSurveyResponsesBySurveyAndLocationAsync(int surveyId, int locationId); - Task<(bool IsSuccess, dynamic SurveyResponses, string ErrorMessage)> GetSurveyResponsesByMaintenanceCenterAsync(int surveyId); - Task<(bool IsSuccess, dynamic SurveyResponses, string ErrorMessage)> GetResponsesByAnswerAsync(int surveyId, int questionId, string answer); + Task<(bool IsSuccess, dynamic SurveyResponse, string ErrorMessage)> GetSurveyResponseByIdAsync(int responseId, string token); + Task<(bool IsSuccess, dynamic SurveyResponses, string ErrorMessage)> GetSurveyResponsesBySurveyAsync(int surveyId, string token); + Task<(bool IsSuccess, dynamic SurveyResponses, string ErrorMessage)> GetSurveyResponsesBySurveyAndLocationAsync(int surveyId, int locationId, string token); + Task<(bool IsSuccess, dynamic SurveyResponses, string ErrorMessage)> GetSurveyResponsesByMaintenanceCenterAsync(int surveyId, string token); + Task<(bool IsSuccess, dynamic SurveyResponses, string ErrorMessage)> GetResponsesByAnswerAsync(int surveyId, int questionId, string answer, string token); - Task<(bool IsSuccess, Models.SurveyResponse SurveyResponse, string ErrorMessage)> PostSurveyAnswersAsync(Request request); + Task<(bool IsSuccess, Models.SurveyResponse SurveyResponse, string ErrorMessage)> PostSurveyAnswersAsync(Request request, string token); } } diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Models/Employee.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Models/Employee.cs index 9a06020..ab21448 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Models/Employee.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Models/Employee.cs @@ -11,6 +11,6 @@ namespace DamageAssesment.Api.SurveyResponses.Models public string OfficePhoneNumber { get; set; } public string Email { get; set; } public bool IsActive { get; set; } - public string? PreferredLanguage { get; set; } + public string PreferredLanguage { get; set; } } } diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Program.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Program.cs index 8d27911..550d49c 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Program.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Program.cs @@ -5,6 +5,10 @@ using DamageAssesment.Api.SurveyResponses.Providers; using Microsoft.EntityFrameworkCore; using Polly; using System.Reflection; +using Microsoft.OpenApi.Models; +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.IdentityModel.Tokens; +using System.Text; var builder = WebApplication.CreateBuilder(args); const int maxApiCallRetries = 3; @@ -14,6 +18,24 @@ const int intervalForCircuitBraker = 5; //5 seconds // Add services to the container. +var authkey = builder.Configuration.GetValue("JwtSettings:securitykey"); +builder.Services.AddAuthentication(item => +{ + item.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; + item.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; +}).AddJwtBearer(item => +{ + item.RequireHttpsMetadata = true; + item.SaveToken = true; + item.TokenValidationParameters = new TokenValidationParameters() + { + ValidateIssuerSigningKey = true, + IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(authkey)), + ValidateIssuer = false, + ValidateAudience = false, + ClockSkew = TimeSpan.Zero + }; +}); builder.Services.AddControllers(); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle @@ -26,6 +48,7 @@ builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); +builder.Services.AddHttpContextAccessor(); builder.Services.AddHttpClient(). AddTransientHttpErrorPolicy(policy => policy.WaitAndRetryAsync(maxApiCallRetries, _ => TimeSpan.FromSeconds(intervalToRetry))). @@ -35,12 +58,40 @@ builder.Services.AddHttpClient(). builder.Services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); builder.Services.AddEndpointsApiExplorer(); //builder.Services.AddSwaggerGen(); -builder.Services.AddSwaggerGen(c => + +builder.Services.AddSwaggerGen(options => { // Include XML comments from your assembly var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); - c.IncludeXmlComments(xmlPath); + options.IncludeXmlComments(xmlPath); + + OpenApiSecurityScheme securityDefinition = new OpenApiSecurityScheme() + { + Name = "Bearer", + BearerFormat = "JWT", + Scheme = "bearer", + Description = "Specify the authorization token.", + In = ParameterLocation.Header, + Type = SecuritySchemeType.Http, + }; + + options.AddSecurityDefinition("jwt_auth", securityDefinition); + + // Make sure swagger UI requires a Bearer token specified + OpenApiSecurityScheme securityScheme = new OpenApiSecurityScheme() + { + Reference = new OpenApiReference() + { + Id = "jwt_auth", + Type = ReferenceType.SecurityScheme + } + }; + OpenApiSecurityRequirement securityRequirements = new OpenApiSecurityRequirement() + { + {securityScheme, new string[] { }}, + }; + options.AddSecurityRequirement(securityRequirements); }); builder.Services.AddDbContext(option => { @@ -55,6 +106,7 @@ if (app.Environment.IsDevelopment()) app.UseSwaggerUI(); } +app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Providers/SurveyResponsesProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Providers/SurveyResponsesProvider.cs index 1f82d8c..d3641b1 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Providers/SurveyResponsesProvider.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Providers/SurveyResponsesProvider.cs @@ -48,7 +48,7 @@ namespace DamageAssesment.Api.SurveyResponses.Providers } } - public async Task<(bool IsSuccess, dynamic Answers, string ErrorMessage)> GetAnswersByRegionAsync(int surveyId) + public async Task<(bool IsSuccess, dynamic Answers, string ErrorMessage)> GetAnswersByRegionAsync(int surveyId,string token) { try { @@ -57,7 +57,7 @@ namespace DamageAssesment.Api.SurveyResponses.Providers if (listSurveyResponse.Any()) { - var answers = await getAnswersByRegionAndSurveyIdAsync(listSurveyResponse); + var answers = await getAnswersByRegionAndSurveyIdAsync(listSurveyResponse,token); return (true, answers, "Request Successful."); } else @@ -72,7 +72,7 @@ namespace DamageAssesment.Api.SurveyResponses.Providers } } - public async Task<(bool IsSuccess, dynamic SurveyResponse, string ErrorMessage)> GetSurveyResponseByIdAsync(int responseId) + public async Task<(bool IsSuccess, dynamic SurveyResponse, string ErrorMessage)> GetSurveyResponseByIdAsync(int responseId, string token) { try { @@ -81,7 +81,7 @@ namespace DamageAssesment.Api.SurveyResponses.Providers if (surveyResponse != null) { - var answers = await getSurveyResponseByResponseIdAsync(surveyResponse); + var answers = await getSurveyResponseByResponseIdAsync(surveyResponse, token); if (answers != null) return (true, answers, "Request Successful."); @@ -105,16 +105,16 @@ namespace DamageAssesment.Api.SurveyResponses.Providers - public async Task<(bool IsSuccess, dynamic SurveyResponses, string ErrorMessage)> GetSurveyResponsesBySurveyAsync(int surveyId) + public async Task<(bool IsSuccess, dynamic SurveyResponses, string ErrorMessage)> GetSurveyResponsesBySurveyAsync(int surveyId, string token) { try { logger?.LogInformation("Querying to get Survey object from microservice"); - var survey = await surveyServiceProvider.getSurveyAsync(surveyId); + var survey = await surveyServiceProvider.getSurveyAsync(surveyId,token); if (survey != null) { - var answers = await getSurveyResponsesBySurveyIdAsync(surveyId); + var answers = await getSurveyResponsesBySurveyIdAsync(surveyId, token); if (answers != null) return (true, answers, "Request Successful."); @@ -136,16 +136,16 @@ namespace DamageAssesment.Api.SurveyResponses.Providers } } - public async Task<(bool IsSuccess, dynamic SurveyResponses, string ErrorMessage)> GetSurveyResponsesBySurveyAndLocationAsync(int surveyId, int locationId) + public async Task<(bool IsSuccess, dynamic SurveyResponses, string ErrorMessage)> GetSurveyResponsesBySurveyAndLocationAsync(int surveyId, int locationId, string token) { try { logger?.LogInformation("Querying to get Survey object from microservice"); - var survey = await surveyServiceProvider.getSurveyAsync(surveyId); + var survey = await surveyServiceProvider.getSurveyAsync(surveyId, token); if (survey != null) { - var answers = await getSurveyResponsesBySurveyIdLocationIdAsync(surveyId, locationId); + var answers = await getSurveyResponsesBySurveyIdLocationIdAsync(surveyId, locationId, token); if (answers != null) return (true, answers, "Request Successful."); @@ -167,16 +167,16 @@ namespace DamageAssesment.Api.SurveyResponses.Providers } } - public async Task<(bool IsSuccess, dynamic SurveyResponses, string ErrorMessage)> GetSurveyResponsesByMaintenanceCenterAsync(int surveyId) + public async Task<(bool IsSuccess, dynamic SurveyResponses, string ErrorMessage)> GetSurveyResponsesByMaintenanceCenterAsync(int surveyId, string token) { try { logger?.LogInformation("Querying to get Survey object from microservice"); - var survey = await surveyServiceProvider.getSurveyAsync(surveyId); + var survey = await surveyServiceProvider.getSurveyAsync(surveyId, token); if (survey != null) { - var answers = await getResultsByMaintenanceCenterAsync(surveyId); + var answers = await getResultsByMaintenanceCenterAsync(surveyId,token); if (answers != null) return (true, answers, "Request Successful."); @@ -198,19 +198,19 @@ namespace DamageAssesment.Api.SurveyResponses.Providers } } - public async Task<(bool IsSuccess, dynamic SurveyResponses, string ErrorMessage)> GetResponsesByAnswerAsync(int surveyId, int questionId, string answer) + public async Task<(bool IsSuccess, dynamic SurveyResponses, string ErrorMessage)> GetResponsesByAnswerAsync(int surveyId, int questionId, string answer, string token) { try { logger?.LogInformation("Querying to get Survey object from microservice"); - var survey = await surveyServiceProvider.getSurveyAsync(surveyId); - var question = await questionServiceProvider.getQuestionsAsync(questionId); + var survey = await surveyServiceProvider.getSurveyAsync(surveyId, token); + var question = await questionServiceProvider.getQuestionsAsync(questionId,token); bool IsCorrectAnswer = answer.ToLower().Equals("yes") || answer.ToLower().Equals("no") ? true : false; if (survey != null && question != null && IsCorrectAnswer) { - var answers = await getSurveyResponsesByAnswerAsync(survey, question, answer); + var answers = await getSurveyResponsesByAnswerAsync(survey, question, answer, token); if (answers != null) return (true, answers, "Request Successful."); @@ -233,11 +233,11 @@ namespace DamageAssesment.Api.SurveyResponses.Providers } - public async Task<(bool IsSuccess, dynamic surveyResponses, string ErrorMessage)> GetSurveyResponsesAsync() + public async Task<(bool IsSuccess, dynamic surveyResponses, string ErrorMessage)> GetSurveyResponsesAsync(string token) { try { - var answers = await getAllSurveyResponsesAsync(); + var answers = await getAllSurveyResponsesAsync(token); if (answers != null) return (true, answers, "Request Successful."); @@ -341,11 +341,11 @@ namespace DamageAssesment.Api.SurveyResponses.Providers } //Method to get Answers by region with surveyId as input parameter - private async Task getAnswersByRegionAndSurveyIdAsync(IQueryable surveyResponses) + private async Task getAnswersByRegionAndSurveyIdAsync(IQueryable surveyResponses, string token) { try { - var answersList = await answerServiceProvider.getAnswersAsync(); + var answersList = await answerServiceProvider.getAnswersAsync(token); if (answersList == null || !answersList.Any()) return null; @@ -368,8 +368,8 @@ namespace DamageAssesment.Api.SurveyResponses.Providers if (surveyAnswers == null || !surveyAnswers.Any()) return null; - var regions = await regionServiceProvider.getRegionsAsync(); - var locations = await locationServiceProvider.getLocationsAsync(); + var regions = await regionServiceProvider.getRegionsAsync(token); + var locations = await locationServiceProvider.getLocationsAsync(token); if (regions == null || !regions.Any() || locations == null || !locations.Any()) return null; @@ -427,15 +427,15 @@ namespace DamageAssesment.Api.SurveyResponses.Providers } //Method to get Survey Response by ResponseId - private async Task getSurveyResponseByResponseIdAsync(Db.SurveyResponse surveyResponse) + private async Task getSurveyResponseByResponseIdAsync(Db.SurveyResponse surveyResponse, string token) { try { - var employee = await employeeServiceProvider.getEmployeeAsync(surveyResponse.EmployeeId); - var answers = await answerServiceProvider.GetAnswersByResponseIdAsync(surveyResponse.Id); - var allQuestions = await questionServiceProvider.getQuestionsAsync(); + var employee = await employeeServiceProvider.getEmployeeAsync(surveyResponse.EmployeeId, token); + var answers = await answerServiceProvider.GetAnswersByResponseIdAsync(surveyResponse.Id, token); + var allQuestions = await questionServiceProvider.getQuestionsAsync(token); var questions = allQuestions.Where(s => s.SurveyId == surveyResponse.SurveyId); - var attachments = await attachmentServiceProvider.getAttachmentsAsync(); + var attachments = await attachmentServiceProvider.getAttachmentsAsync(token); var result = new { @@ -470,20 +470,19 @@ namespace DamageAssesment.Api.SurveyResponses.Providers //Method to get Survey Responses by surveyId - private async Task getSurveyResponsesBySurveyIdAsync(int surveyId) + private async Task getSurveyResponsesBySurveyIdAsync(int surveyId, string token) { try { var surveyResonses = await surveyResponseDbContext.SurveyResponses.Where(x => x.SurveyId == surveyId).ToListAsync(); - - var employees = await employeeServiceProvider.getEmployeesAsync(); - var answers = await answerServiceProvider.getAnswersAsync(); - var questions = await questionServiceProvider.getQuestionsAsync(); + var employees = await employeeServiceProvider.getEmployeesAsync(token); + var answers = await answerServiceProvider.getAnswersAsync(token); + var questions = await questionServiceProvider.getQuestionsAsync(token); var surveyQuestions = from q in questions where q.SurveyId == surveyId select q; //var surveyQuestions = await questionServiceProvider.getSurveyQuestionsAsync(surveyId); - var attachments = await attachmentServiceProvider.getAttachmentsAsync(); + var attachments = await attachmentServiceProvider.getAttachmentsAsync(token); var result = from r in surveyResonses select new { @@ -520,16 +519,15 @@ namespace DamageAssesment.Api.SurveyResponses.Providers //Method to get All Survey Responses - private async Task getAllSurveyResponsesAsync() + private async Task getAllSurveyResponsesAsync(string token) { try { var surveyResonses = await surveyResponseDbContext.SurveyResponses.ToListAsync(); - - var employees = await employeeServiceProvider.getEmployeesAsync(); - var answers = await answerServiceProvider.getAnswersAsync(); - var questions = await questionServiceProvider.getQuestionsAsync(); - var attachments = await attachmentServiceProvider.getAttachmentsAsync(); + var employees = await employeeServiceProvider.getEmployeesAsync(token); + var answers = await answerServiceProvider.getAnswersAsync(token); + var questions = await questionServiceProvider.getQuestionsAsync(token); + var attachments = await attachmentServiceProvider.getAttachmentsAsync(token); var result = from r in surveyResonses select new @@ -566,13 +564,13 @@ namespace DamageAssesment.Api.SurveyResponses.Providers //Method to get Answers By Maintenance Center by surveyId - private async Task getResultsByMaintenanceCenterAsync(int surveyId) + private async Task getResultsByMaintenanceCenterAsync(int surveyId, string token) { try { var surveyResponses = await surveyResponseDbContext.SurveyResponses.Where(x => x.SurveyId == surveyId).ToListAsync(); - var answers = await answerServiceProvider.getAnswersAsync(); - var locations = await locationServiceProvider.getLocationsAsync(); + var answers = await answerServiceProvider.getAnswersAsync(token); + var locations = await locationServiceProvider.getLocationsAsync(token); var maintenanceCenters = locations.DistinctBy(m => m.MaintenanceCenter); //get all the answers for the particular survey @@ -626,17 +624,16 @@ namespace DamageAssesment.Api.SurveyResponses.Providers } //Method to get Survey Responses by surveyId and LocationId - private async Task getSurveyResponsesBySurveyIdLocationIdAsync(int surveyId, int locationId) + private async Task getSurveyResponsesBySurveyIdLocationIdAsync(int surveyId, int locationId, string token) { try { var surveyResonses = await surveyResponseDbContext.SurveyResponses.Where(x => x.SurveyId == surveyId && x.LocationId.Equals(locationId)).ToListAsync(); - - var employees = await employeeServiceProvider.getEmployeesAsync(); - var answers = await answerServiceProvider.getAnswersAsync(); - var questions = await questionServiceProvider.getQuestionsAsync(); + var employees = await employeeServiceProvider.getEmployeesAsync(token); + var answers = await answerServiceProvider.getAnswersAsync(token); + var questions = await questionServiceProvider.getQuestionsAsync(token); var surveyQuestions = from q in questions where q.SurveyId == surveyId select q; - var attachments = await attachmentServiceProvider.getAttachmentsAsync(); + var attachments = await attachmentServiceProvider.getAttachmentsAsync(token); var result = from r in surveyResonses select new @@ -674,14 +671,14 @@ namespace DamageAssesment.Api.SurveyResponses.Providers //Method to get Survey Responses by surveyId questionId and answer - private async Task getSurveyResponsesByAnswerAsync(Survey survey, Question question, string answer) + private async Task getSurveyResponsesByAnswerAsync(Survey survey, Question question, string answer, string token) { try { var surveyResponses = await surveyResponseDbContext.SurveyResponses.Where(x => x.SurveyId == survey.Id).ToListAsync(); - var answers = await answerServiceProvider.getAnswersAsync(); - var employees = await employeeServiceProvider.getEmployeesAsync(); - var attachments = await attachmentServiceProvider.getAttachmentsAsync(); + var answers = await answerServiceProvider.getAnswersAsync(token); + var employees = await employeeServiceProvider.getEmployeesAsync(token); + var attachments = await attachmentServiceProvider.getAttachmentsAsync(token); var result = from r in surveyResponses select new @@ -720,16 +717,16 @@ namespace DamageAssesment.Api.SurveyResponses.Providers } - async Task ProcessAnswers(AnswerRequest answerRequest, int surveyResponseId) + async Task ProcessAnswers(AnswerRequest answerRequest, int surveyResponseId,string token) { if (answerRequest != null) { - var answer = await answerServiceProvider.PostAnswersAsync(new Models.Answer { QuestionId = answerRequest.QuestionId, AnswerText = answerRequest.AnswerText, Comment = answerRequest.Comment, SurveyResponseId = surveyResponseId }); + var answer = await answerServiceProvider.PostAnswersAsync(new Models.Answer { QuestionId = answerRequest.QuestionId, AnswerText = answerRequest.AnswerText, Comment = answerRequest.Comment, SurveyResponseId = surveyResponseId }, token); if (answer != null) { List listAnswerInfo = new List(); listAnswerInfo.Add(new AnswerInfo { AnswerId = answer.Id, postedFiles = answerRequest.PostedFiles }); - var attachments = attachmentServiceProvider.PostAttachmentsAsync(new AttachmentInfo { ResponseId = surveyResponseId, Answers = listAnswerInfo }); + var attachments = attachmentServiceProvider.PostAttachmentsAsync(new AttachmentInfo { ResponseId = surveyResponseId, Answers = listAnswerInfo }, token); string message = $"Answer for question {answerRequest.QuestionId} saved to the database"; logger?.LogInformation(message); @@ -750,8 +747,7 @@ namespace DamageAssesment.Api.SurveyResponses.Providers } } - - public async Task<(bool IsSuccess, Models.SurveyResponse SurveyResponse, string ErrorMessage)> PostSurveyAnswersAsync(Models.Request request) + public async Task<(bool IsSuccess, Models.SurveyResponse SurveyResponse, string ErrorMessage)> PostSurveyAnswersAsync(Models.Request request, string token) { try { @@ -761,7 +757,7 @@ namespace DamageAssesment.Api.SurveyResponses.Providers if (response.IsSuccess) { var surveyResponse = response.SurveyResponse; - var tasks = request.Answers.Select(x => ProcessAnswers(x, surveyResponse.Id)); + var tasks = request.Answers.Select(x => ProcessAnswers(x, surveyResponse.Id,token)); await Task.WhenAll(tasks); return (true, surveyResponse, null); } diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Services/AnswerServiceProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Services/AnswerServiceProvider.cs index 695ad3e..5ee1a39 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Services/AnswerServiceProvider.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Services/AnswerServiceProvider.cs @@ -1,5 +1,6 @@ using DamageAssesment.Api.SurveyResponses.Interfaces; using DamageAssesment.Api.SurveyResponses.Models; +using Microsoft.Extensions.Primitives; using Newtonsoft.Json; @@ -10,11 +11,11 @@ namespace DamageAssesment.Api.SurveyResponses.Services public AnswerServiceProvider(IConfiguration configuration, IHttpUtil httpUtil, ILogger logger) : base(configuration, httpUtil, logger, configuration.GetValue("RessourceSettings:Answer"), configuration.GetValue("EndPointSettings:AnswerUrlBase")) { } - public async Task> getAnswersAsync() + public async Task> getAnswersAsync(string token) { try { - var responseJsonString = await httpUtil.SendAsync(HttpMethod.Get, url, null); + var responseJsonString = await httpUtil.SendAsync(HttpMethod.Get, url, null, token); var answers = JsonConvert.DeserializeObject>(responseJsonString); if (answers == null || !answers.Any()) @@ -28,12 +29,12 @@ namespace DamageAssesment.Api.SurveyResponses.Services } } - public async Task> GetAnswersByResponseIdAsync(int responseId) + public async Task> GetAnswersByResponseIdAsync(int responseId, string token) { try { url = urlBase + string.Format(configuration.GetValue("RessourceSettings:AnswerByResponse"), responseId); - var responseJsonString = await httpUtil.SendAsync(HttpMethod.Get, url, null); + var responseJsonString = await httpUtil.SendAsync(HttpMethod.Get, url, null,token); var answers = JsonConvert.DeserializeObject>(responseJsonString); if (answers == null || !answers.Any()) @@ -47,12 +48,12 @@ namespace DamageAssesment.Api.SurveyResponses.Services } } - public async Task PostAnswersAsync(Answer answer) + public async Task PostAnswersAsync(Answer answer, string token ) { try { var requestJsonString = JsonConvert.SerializeObject(answer); - var responseJsonString = await httpUtil.SendAsync(HttpMethod.Post, url, requestJsonString); + var responseJsonString = await httpUtil.SendAsync(HttpMethod.Post, url, requestJsonString, token); var answers = JsonConvert.DeserializeObject(responseJsonString); if (answers == null) diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Services/AttachmentServiceProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Services/AttachmentServiceProvider.cs index 120e60f..25601fe 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Services/AttachmentServiceProvider.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Services/AttachmentServiceProvider.cs @@ -10,11 +10,11 @@ namespace DamageAssesment.Api.SurveyResponses.Services { } - public async Task> getAttachmentsAsync() + public async Task> getAttachmentsAsync(string token) { try { - var responseJsonString = await httpUtil.SendAsync(HttpMethod.Get, url, null); + var responseJsonString = await httpUtil.SendAsync(HttpMethod.Get, url, null,token); var attachments = JsonConvert.DeserializeObject>(responseJsonString); if (attachments == null || !attachments.Any()) @@ -28,12 +28,12 @@ namespace DamageAssesment.Api.SurveyResponses.Services } } - public async Task> PostAttachmentsAsync(AttachmentInfo attachmentInfo) + public async Task> PostAttachmentsAsync(AttachmentInfo attachmentInfo, string token) { try { var requestJsonString = JsonConvert.SerializeObject(attachmentInfo); - var responseJsonString = await httpUtil.SendAsync(HttpMethod.Post, url, requestJsonString); + var responseJsonString = await httpUtil.SendAsync(HttpMethod.Post, url, requestJsonString, token); var attachments = JsonConvert.DeserializeObject>(responseJsonString); if (attachments == null) diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Services/EmployeeServiceProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Services/EmployeeServiceProvider.cs index 8dd1352..0a598a6 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Services/EmployeeServiceProvider.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Services/EmployeeServiceProvider.cs @@ -11,11 +11,11 @@ namespace DamageAssesment.Api.SurveyResponses.Services { } - public async Task> getEmployeesAsync() + public async Task> getEmployeesAsync(string token) { try { - var responseJsonString = await httpUtil.SendAsync(HttpMethod.Get, url, null); + var responseJsonString = await httpUtil.SendAsync(HttpMethod.Get, url, null,token); var employees = JsonConvert.DeserializeObject>(responseJsonString); if (employees == null || !employees.Any()) @@ -29,12 +29,12 @@ namespace DamageAssesment.Api.SurveyResponses.Services } } - public async Task getEmployeeAsync(int employeeId) + public async Task getEmployeeAsync(int employeeId, string token) { try { url = urlBase + string.Format(configuration.GetValue("RessourceSettings:EmployeeById"), employeeId); - var responseJsonString = await httpUtil.SendAsync(HttpMethod.Get, url, null); + var responseJsonString = await httpUtil.SendAsync(HttpMethod.Get, url, null, token); var employee = JsonConvert.DeserializeObject(responseJsonString); if (employee == null) diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Services/HttpUtil.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Services/HttpUtil.cs index 8b4755d..09e3582 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Services/HttpUtil.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Services/HttpUtil.cs @@ -1,4 +1,5 @@ using DamageAssesment.Api.SurveyResponses.Interfaces; +using DamageAssesment.Api.SurveyResponses.Models; using System.Net.Http.Headers; using System.Text; @@ -14,20 +15,18 @@ namespace DamageAssesment.Api.SurveyResponses.Services this.httpClient = httpClient; this.logger = logger; } - public async Task SendAsync(HttpMethod method, string url, string JsonInput) + public async Task SendAsync(HttpMethod method, string url, string JsonInput, string token) { try { var request = new HttpRequestMessage(method, url); request.Headers.Accept.Clear(); request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); - - //request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token); + request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token); if (method == HttpMethod.Post) { request.Content = new StringContent(JsonInput, Encoding.UTF8, "application/json"); } - var response = await httpClient.SendAsync(request, CancellationToken.None); response.EnsureSuccessStatusCode(); var responseString = await response.Content.ReadAsStringAsync(); diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Services/LocationServiceProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Services/LocationServiceProvider.cs index 2e3fa32..62ebf09 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Services/LocationServiceProvider.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Services/LocationServiceProvider.cs @@ -10,11 +10,11 @@ namespace DamageAssesment.Api.SurveyResponses.Services { } - public async Task> getLocationsAsync() + public async Task> getLocationsAsync(string token) { try { - var responseJsonString = await httpUtil.SendAsync(HttpMethod.Get, url, null); + var responseJsonString = await httpUtil.SendAsync(HttpMethod.Get, url, null, token); var locations = JsonConvert.DeserializeObject>(responseJsonString); if (locations == null || !locations.Any()) diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Services/QuestionServiceProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Services/QuestionServiceProvider.cs index 138011f..9f163c2 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Services/QuestionServiceProvider.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Services/QuestionServiceProvider.cs @@ -10,11 +10,11 @@ namespace DamageAssesment.Api.SurveyResponses.Services { } - public async Task> getQuestionsAsync() + public async Task> getQuestionsAsync(string token) { try { - var responseJsonString = await httpUtil.SendAsync(HttpMethod.Get, url, null); + var responseJsonString = await httpUtil.SendAsync(HttpMethod.Get, url, null,token); var questions = JsonConvert.DeserializeObject>(responseJsonString); if (questions == null || !questions.Any()) @@ -28,12 +28,12 @@ namespace DamageAssesment.Api.SurveyResponses.Services } } - public async Task> getSurveyQuestionsAsync(int surveyId) + public async Task> getSurveyQuestionsAsync(int surveyId, string token) { try { url = urlBase + string.Format(configuration.GetValue("RessourceSettings:SurveyQuestion"), surveyId); - var responseJsonString = await httpUtil.SendAsync(HttpMethod.Get, url, null); + var responseJsonString = await httpUtil.SendAsync(HttpMethod.Get, url, null, token); var questions = JsonConvert.DeserializeObject>(responseJsonString); if (questions == null || !questions.Any()) @@ -48,12 +48,12 @@ namespace DamageAssesment.Api.SurveyResponses.Services } - public async Task getQuestionsAsync(int questionId) + public async Task getQuestionsAsync(int questionId, string token) { try { url = urlBase + string.Format(configuration.GetValue("RessourceSettings:QuestionById"), questionId); - var responseJsonString = await httpUtil.SendAsync(HttpMethod.Get, url, null); + var responseJsonString = await httpUtil.SendAsync(HttpMethod.Get, url, null, token); var question = JsonConvert.DeserializeObject(responseJsonString); if (question == null) diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Services/RegionServiceProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Services/RegionServiceProvider.cs index 091512e..1b6ea07 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Services/RegionServiceProvider.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Services/RegionServiceProvider.cs @@ -9,11 +9,11 @@ namespace DamageAssesment.Api.SurveyResponses.Services public RegionServiceProvider(IConfiguration configuration, IHttpUtil httpUtil, ILogger logger) : base(configuration, httpUtil, logger, configuration.GetValue("RessourceSettings:Region"), configuration.GetValue("EndPointSettings:LocationUrlBase")) { } - public async Task> getRegionsAsync() + public async Task> getRegionsAsync(string token) { try { - var responseJsonString = await httpUtil.SendAsync(HttpMethod.Get, url, null); + var responseJsonString = await httpUtil.SendAsync(HttpMethod.Get, url, null, token); var regions = JsonConvert.DeserializeObject>(responseJsonString); if (regions == null || !regions.Any()) diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Services/SurveyServiceProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Services/SurveyServiceProvider.cs index c9df4db..fc08135 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Services/SurveyServiceProvider.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Services/SurveyServiceProvider.cs @@ -10,11 +10,11 @@ namespace DamageAssesment.Api.SurveyResponses.Services { } - public async Task> getSurveysAsync() + public async Task> getSurveysAsync(string token) { try { - var responseJsonString = await httpUtil.SendAsync(HttpMethod.Get, url, null); + var responseJsonString = await httpUtil.SendAsync(HttpMethod.Get, url, null, token); var surveys = JsonConvert.DeserializeObject>(responseJsonString); if (surveys == null || !surveys.Any()) @@ -28,12 +28,12 @@ namespace DamageAssesment.Api.SurveyResponses.Services } } - public async Task getSurveyAsync(int surveyId) + public async Task getSurveyAsync(int surveyId, string token) { try { url = urlBase + string.Format(configuration.GetValue("RessourceSettings:SurveyById"), surveyId); - var responseJsonString = await httpUtil.SendAsync(HttpMethod.Get, url, null); + var responseJsonString = await httpUtil.SendAsync(HttpMethod.Get, url, null, token); var survey = JsonConvert.DeserializeObject(responseJsonString); if (survey == null ) diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/appsettings.json b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/appsettings.json index d7b64fc..011232a 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/appsettings.json +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/appsettings.json @@ -6,6 +6,9 @@ } }, "AllowedHosts": "*", + "JwtSettings": { + "securitykey": "bWlhbWkgZGFkZSBzY2hvb2xzIHNlY3JldCBrZXk=" + }, "EndPointSettings": { "AnswerUrlBase": "http://localhost:5200", "LocationUrlBase": "http://localhost:5213", diff --git a/DamageAssesmentApi/DamageAssesment.Api.Surveys/Controllers/SurveysController.cs b/DamageAssesmentApi/DamageAssesment.Api.Surveys/Controllers/SurveysController.cs index 7853716..2500f8b 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Surveys/Controllers/SurveysController.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Surveys/Controllers/SurveysController.cs @@ -1,4 +1,5 @@ using DamageAssesment.Api.Surveys.Interfaces; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; namespace DamageAssesment.Api.Surveys.Controllers @@ -15,7 +16,7 @@ namespace DamageAssesment.Api.Surveys.Controllers /// /// GET request for retrieving surveys. /// - + [Authorize(Roles ="admin,survey,user,report")] [Route("Surveys")] [Route("Surveys/{language:alpha}")] [HttpGet] @@ -32,6 +33,7 @@ namespace DamageAssesment.Api.Surveys.Controllers /// /// GET request for retrieving surveys by ID. /// + [Authorize(Roles = "admin,survey,user,report")] [Route("Surveys/{id:int}")] [Route("Surveys/{id:int}/{language:alpha}")] [HttpGet] @@ -47,7 +49,7 @@ namespace DamageAssesment.Api.Surveys.Controllers /// /// POST request for creating a new survey. /// - + [Authorize(Roles = "admin,survey,user,report")] [HttpPost("Surveys")] public async Task PostSurveysAsync(Models.Survey survey) { @@ -62,7 +64,7 @@ namespace DamageAssesment.Api.Surveys.Controllers /// PUT request for updating an existing survey (surveyId,Updated Survey data). /// - + [Authorize(Roles = "admin,survey")] [HttpPut("Surveys/{id}")] public async Task PutSurveysAsync(int id, Models.Survey survey) { @@ -80,6 +82,7 @@ namespace DamageAssesment.Api.Surveys.Controllers /// /// DELETE request for deleting a survey by ID. /// + [Authorize(Roles = "admin,survey")] [HttpDelete("Surveys/{id}")] public async Task DeleteSurveysAsync(int id) { diff --git a/DamageAssesmentApi/DamageAssesment.Api.Surveys/Program.cs b/DamageAssesmentApi/DamageAssesment.Api.Surveys/Program.cs index fadf4de..433cc8b 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Surveys/Program.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Surveys/Program.cs @@ -6,6 +6,7 @@ using Microsoft.EntityFrameworkCore; using Microsoft.IdentityModel.Tokens; using System.Text; using System.Reflection; +using Microsoft.OpenApi.Models; var builder = WebApplication.CreateBuilder(args); @@ -34,14 +35,44 @@ builder.Services.AddControllers(); builder.Services.AddScoped(); builder.Services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); builder.Services.AddEndpointsApiExplorer(); -//builder.Services.AddSwaggerGen(); -builder.Services.AddSwaggerGen(c => + +builder.Services.AddSwaggerGen(options => { // Include XML comments from your assembly var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); - c.IncludeXmlComments(xmlPath); + options.IncludeXmlComments(xmlPath); + + OpenApiSecurityScheme securityDefinition = new OpenApiSecurityScheme() + { + Name = "Bearer", + BearerFormat = "JWT", + Scheme = "bearer", + Description = "Specify the authorization token.", + In = ParameterLocation.Header, + Type = SecuritySchemeType.Http, + }; + + options.AddSecurityDefinition("jwt_auth", securityDefinition); + + // Make sure swagger UI requires a Bearer token specified + OpenApiSecurityScheme securityScheme = new OpenApiSecurityScheme() + { + Reference = new OpenApiReference() + { + Id = "jwt_auth", + Type = ReferenceType.SecurityScheme + } + }; + + OpenApiSecurityRequirement securityRequirements = new OpenApiSecurityRequirement() + { + {securityScheme, new string[] { }}, + }; + + options.AddSecurityRequirement(securityRequirements); }); + builder.Services.AddDbContext(option => { option.UseInMemoryDatabase("Surveys"); diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Controllers/UsersAccessController.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Controllers/UsersAccessController.cs new file mode 100644 index 0000000..d18eb40 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Controllers/UsersAccessController.cs @@ -0,0 +1,127 @@ +using DamageAssesment.Api.UsersAccess.Interfaces; +using DamageAssesment.Api.UsersAccess.Models; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System.IdentityModel.Tokens.Jwt; +using System.IO; + +namespace DamageAssesment.Api.UsersAccess.Controllers +{ + [ApiController] + public class UsersAccessController : ControllerBase + { + private IUsersAccessProvider userAccessProvider; + + public UsersAccessController(IUsersAccessProvider userAccessProvider) + { + this.userAccessProvider = userAccessProvider; + } + [Authorize(Policy = "Dadeschools")] + [HttpPost("token/{employecode}")] + public async Task AuthenticateAsync(string employecode) + { + /* if (Request.Headers.TryGetValue("Authorization", out var headerAuth)) + { + var jwtToken = headerAuth.First().Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)[1]; + var handler = new JwtSecurityTokenHandler(); + var jsonToken = handler.ReadToken(jwtToken) as JwtSecurityToken; + return Ok(jsonToken.Payload.Sub); + } */ + + var result = await userAccessProvider.AuthenticateAsync(employecode); + if (result.IsSuccess) + { + return Ok(result.TokenResponse); + } + return Unauthorized(result.ErrorMessage); + } + + [Authorize(Policy = "Dadeschools")] + [HttpPost("refreshtoken")] + public async Task RefreshTokenAsync(TokenResponse tokenResponse) + { + var result = await userAccessProvider.RefreshTokenAsync(tokenResponse); + if (result.IsSuccess) + { + return Ok(result.TokenResponse); + } + return Unauthorized(result.ErrorMessage); + } + + [Authorize(Policy = "DamageApp", Roles ="admin")] + [HttpGet("users")] + public async Task GetUsersAsync() + { + var result = await userAccessProvider.GetUsersAsync(); + if (result.IsSuccess) + { + return Ok(result.Users); + } + return NoContent(); + } + + [Authorize(Policy = "DamageApp", Roles = "admin")] + [HttpGet("users/{Id}")] + public async Task GetUsersAsync(int Id) + { + var result = await userAccessProvider.GetUsersAsync(Id); + if (result.IsSuccess) + { + return Ok(result.User); + } + return NotFound(); + } + + [Authorize(Policy = "DamageApp", Roles = "admin")] + [HttpGet("roles")] + public async Task GetRolesAsync() + { + var result = await userAccessProvider.GetRolesAsync(); + if (result.IsSuccess) + { + return Ok(result.Roles); + } + return NoContent(); + } + [Authorize(Policy = "DamageApp", Roles = "admin")] + [HttpPost("users")] + public async Task PostUserAsync(User user) + { + var result = await userAccessProvider.PostUserAsync(user); + if (result.IsSuccess) + { + return Ok(result.User); + } + return BadRequest(result.ErrorMessage); + } + + [Authorize(Policy = "DamageApp", Roles = "admin")] + [HttpPut("users/{Id}")] + public async Task PutUserAsync(int Id, User user) + { + var result = await userAccessProvider.PutUserAsync(Id, user); + if (result.IsSuccess) + { + return Ok(result.User); + } + if (result.ErrorMessage == "Not Found") + return NotFound(result.ErrorMessage); + + return BadRequest(result.ErrorMessage); + } + + [Authorize(Policy = "DamageApp", Roles = "admin")] + [HttpDelete("users/{Id}")] + public async Task DeleteSurveysAsync(int Id) + { + var result = await userAccessProvider.DeleteUserAsync(Id); + if (result.IsSuccess) + { + return Ok(result.User); + } + return NotFound(); + } + + + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/DamageAssesment.Api.UsersAccess.csproj b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/DamageAssesment.Api.UsersAccess.csproj new file mode 100644 index 0000000..6eb08de --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/DamageAssesment.Api.UsersAccess.csproj @@ -0,0 +1,20 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + + + + diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Db/Role.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Db/Role.cs new file mode 100644 index 0000000..93e522a --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Db/Role.cs @@ -0,0 +1,21 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Text.Json.Serialization; + +namespace DamageAssesment.Api.UsersAccess.Db +{ + public class Role + { + [Key] + public int Id { get; set; } + + [StringLength(100)] + [Required] + public string Name { get; set; } + + // add a status field + + [StringLength(100)] + public string? Description { get; set; } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Db/Token.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Db/Token.cs new file mode 100644 index 0000000..bdfe576 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Db/Token.cs @@ -0,0 +1,17 @@ +using Microsoft.EntityFrameworkCore.Metadata.Internal; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace DamageAssesment.Api.UsersAccess.Db +{ + public class Token + { + [Key] + public int Id { get; set; } + [Required] + [ForeignKey("User")] + public int UserId { get; set; } + public string? RefreshToken { get; set; } + public bool? IsActive { get; set; } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Db/User.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Db/User.cs new file mode 100644 index 0000000..f99deb8 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Db/User.cs @@ -0,0 +1,31 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Text.Json.Serialization; + +namespace DamageAssesment.Api.UsersAccess.Db +{ + public class User + { + [Key] + public int Id { get; set; } + + [ForeignKey("Employee")] + public int EmployeeId { get; set; } + + [Required] + [StringLength(50)] + public string EmployeeCode { get; set; } + + [ForeignKey("Role")] + [Required] + public int RoleId { get; set; } + [Required] + public bool IsActive { get; set; } = true; + + [Required] + public DateTime CreateDate { get; set; } = DateTime.Now; + + public DateTime? UpdateDate { get; set; } + + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Db/UsersAccessDbContext.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Db/UsersAccessDbContext.cs new file mode 100644 index 0000000..2c9a2e1 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Db/UsersAccessDbContext.cs @@ -0,0 +1,32 @@ +using Microsoft.EntityFrameworkCore; + +namespace DamageAssesment.Api.UsersAccess.Db +{ + public class UsersAccessDbContext : DbContext + { + public DbSet Users { get; set; } + public DbSet Roles { get; set; } + public DbSet Tokens { get; set; } + public UsersAccessDbContext(DbContextOptions options) : base(options) + { + + } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + + modelBuilder.Entity() + .Property(item => item.Id) + .ValueGeneratedOnAdd(); + + modelBuilder.Entity() + .Property(item => item.Id) + .ValueGeneratedOnAdd(); + + modelBuilder.Entity() + .Property(item => item.Id) + .ValueGeneratedOnAdd(); + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Interfaces/IEmployeeServiceProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Interfaces/IEmployeeServiceProvider.cs new file mode 100644 index 0000000..255a954 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Interfaces/IEmployeeServiceProvider.cs @@ -0,0 +1,10 @@ +using DamageAssesment.Api.UsersAccess.Models; + +namespace DamageAssesment.Api.UsersAccess.Interfaces +{ + public interface IEmployeeServiceProvider + { + Task> getEmployeesAsync(); + Task getEmployeeAsync(int employeeId); + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Interfaces/IHttpUtil.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Interfaces/IHttpUtil.cs new file mode 100644 index 0000000..3d0a8ed --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Interfaces/IHttpUtil.cs @@ -0,0 +1,7 @@ +namespace DamageAssesment.Api.UsersAccess.Interfaces +{ + public interface IHttpUtil + { + Task SendAsync(HttpMethod method, string url, string JsonInput); + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Interfaces/IRoleProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Interfaces/IRoleProvider.cs new file mode 100644 index 0000000..6ca0209 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Interfaces/IRoleProvider.cs @@ -0,0 +1,12 @@ +namespace DamageAssesment.Api.UsersAccess.Interfaces +{ + public interface IRoleProvider + { + Task<(bool IsSuccess, IEnumerable< Models.Role> Roles, string ErrorMessage)> GetRolesAsync(); + Task<(bool IsSuccess, Models.Role Roles, string ErrorMessage)> GetRolesAsync(int Id); + Task<(bool IsSuccess, Models.Role Role, string ErrorMessage)> PostRoleAsync(Models.Role Role); + Task<(bool IsSuccess, Models.Role Role, string ErrorMessage)> PutRoleAsync(int Id,Models.Role Role); + Task<(bool IsSuccess, Models.Role Role, string ErrorMessage)> DeleteRoleAsync(int Id); + + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Interfaces/ITokenServiceProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Interfaces/ITokenServiceProvider.cs new file mode 100644 index 0000000..6115e7c --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Interfaces/ITokenServiceProvider.cs @@ -0,0 +1,11 @@ +using DamageAssesment.Api.UsersAccess.Models; +using System.Security.Claims; + +namespace DamageAssesment.Api.UsersAccess.Interfaces +{ + public interface ITokenServiceProvider + { + Task GenerateToken(Models.User user); + Task TokenAuthenticate(Models.User user, Claim[] claims); + } +} \ No newline at end of file diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Interfaces/IUsersAccessProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Interfaces/IUsersAccessProvider.cs new file mode 100644 index 0000000..ea64376 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Interfaces/IUsersAccessProvider.cs @@ -0,0 +1,17 @@ +using DamageAssesment.Api.UsersAccess.Models; + +namespace DamageAssesment.Api.UsersAccess.Interfaces +{ + public interface IUsersAccessProvider + { + public Task<(bool IsSuccess, IEnumerable< Models.User> Users, string ErrorMessage)> GetUsersAsync(); + public Task<(bool IsSuccess, Models.User User, string ErrorMessage)> GetUsersAsync(int Id); + public Task<(bool IsSuccess, Models.User User, string ErrorMessage)> PostUserAsync(Models.User User); + public Task<(bool IsSuccess, Models.User User, string ErrorMessage)> PutUserAsync(int Id,Models.User User); + public Task<(bool IsSuccess, Models.User User, string ErrorMessage)> DeleteUserAsync(int Id); + public Task<(bool IsSuccess, IEnumerable Roles, string ErrorMessage)> GetRolesAsync(); + public Task<(bool IsSuccess, Models.TokenResponse TokenResponse, string ErrorMessage)> AuthenticateAsync(string employeCode); + public Task<(bool IsSuccess, Models.TokenResponse TokenResponse, string ErrorMessage)>RefreshTokenAsync(TokenResponse tokenResponse); + public void seedData(); + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Models/Employee.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Models/Employee.cs new file mode 100644 index 0000000..b08d156 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Models/Employee.cs @@ -0,0 +1,14 @@ +namespace DamageAssesment.Api.UsersAccess.Models +{ + public class Employee + { + public int Id { get; set; } + public string EmployeeCode { get; set; } + public string Name { get; set; } + public DateTime BirthDate { get; set; } + public string OfficePhoneNumber { get; set; } + public string Email { get; set; } + public bool IsActive { get; set; } + public string PreferredLanguage { get; set; } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Models/JwtSettings.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Models/JwtSettings.cs new file mode 100644 index 0000000..3f9dadf --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Models/JwtSettings.cs @@ -0,0 +1,9 @@ +using System.ComponentModel.DataAnnotations; +namespace DamageAssesment.Api.UsersAccess.Models +{ + + public class JwtSettings + { + public string securitykey { get; set; } + } +} \ No newline at end of file diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Models/Role.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Models/Role.cs new file mode 100644 index 0000000..a275c60 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Models/Role.cs @@ -0,0 +1,8 @@ +namespace DamageAssesment.Api.UsersAccess.Models +{ + public class Role { + public int Id { get; set; } + public string Name { get; set; } + public string Description { get; set; } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Models/Token.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Models/Token.cs new file mode 100644 index 0000000..87f1ae3 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Models/Token.cs @@ -0,0 +1,10 @@ +namespace DamageAssesment.Api.UsersAccess.Models +{ + public class Token + { + public string Id { get; set; } + public int UserId { get; set; } + public string RefreshToken { get; set; } + public bool IsActive { get; set; } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Models/TokenResponse.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Models/TokenResponse.cs new file mode 100644 index 0000000..4d0b6da --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Models/TokenResponse.cs @@ -0,0 +1,8 @@ +namespace DamageAssesment.Api.UsersAccess.Models +{ + public class TokenResponse + { + public string? jwttoken { get; set; } + public string? refreshtoken { get; set; } + } +} \ No newline at end of file diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Models/User.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Models/User.cs new file mode 100644 index 0000000..e43bc20 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Models/User.cs @@ -0,0 +1,13 @@ +namespace DamageAssesment.Api.UsersAccess.Models +{ + public class User + { + public int Id { get; set; } + public int EmployeeId { get; set; } + public string EmployeeCode { get; set; } + public int RoleId { get; set; } + public bool IsActive { get; set; } + public DateTime CreateDate { get; set; } + public DateTime UpdateDate { get; set; } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Models/UserCredentials.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Models/UserCredentials.cs new file mode 100644 index 0000000..cf01fa3 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Models/UserCredentials.cs @@ -0,0 +1,5 @@ +public class UserCredentials +{ + public string username { get; set; } + // public string? password { get; set; } +} \ No newline at end of file diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Profiles/UsersAccessProfile.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Profiles/UsersAccessProfile.cs new file mode 100644 index 0000000..bf744eb --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Profiles/UsersAccessProfile.cs @@ -0,0 +1,14 @@ +namespace DamageAssesment.Api.UsersAccess.Profiles +{ + public class UsersAccessProfile : AutoMapper.Profile + { + public UsersAccessProfile() + { + CreateMap(); + CreateMap(); + + CreateMap(); + CreateMap(); + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Program.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Program.cs new file mode 100644 index 0000000..a7d12a5 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Program.cs @@ -0,0 +1,146 @@ +using DamageAssesment.Api.UsersAccess.Db; +using DamageAssesment.Api.UsersAccess.Interfaces; +using DamageAssesment.Api.UsersAccess.Providers; +using DamageAssesment.Api.UsersAccess.Models; +using Microsoft.EntityFrameworkCore; +using Microsoft.IdentityModel.Tokens; +using System.Text; +using Polly; +using DamageAssesment.Api.UsersAccess.Services; +using Microsoft.OpenApi.Models; +using System.Reflection; +using Microsoft.AspNetCore.Authorization; + +const int maxApiCallRetries = 3; +const int intervalToRetry = 2; //2 seconds +const int maxRetryForCircuitBraker = 5; +const int intervalForCircuitBraker = 5; //5 seconds + +var builder = WebApplication.CreateBuilder(args); + +// Add services to the container. +var authkey = builder.Configuration.GetValue("JwtSettings:securitykey"); + + +builder.Services.AddAuthentication(). + AddJwtBearer("DamageApp", item => +{ + + item.RequireHttpsMetadata = true; + item.SaveToken = true; + item.TokenValidationParameters = new TokenValidationParameters() + { + ValidateIssuerSigningKey = true, + IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(authkey)), + ValidateIssuer = false, + ValidateAudience = false, + ClockSkew = TimeSpan.Zero + }; +}).AddJwtBearer("Dadeschools", options => +{ + options.Authority = builder.Configuration["Dadeschools:Authority"]; + options.TokenValidationParameters.ValidTypes = new[] { "at+jwt" }; + options.TokenValidationParameters.ValidateAudience = false; +}); + + +builder.Services.AddAuthorization(options => +{ + var DamageAppPolicy = new AuthorizationPolicyBuilder() + .RequireAuthenticatedUser() + .AddAuthenticationSchemes("DamageApp") + .Build(); + var DadeschoolsPolicy = new AuthorizationPolicyBuilder() + .RequireAuthenticatedUser() + .AddAuthenticationSchemes("Dadeschools") + .Build(); + var allPolicy = new AuthorizationPolicyBuilder() + .RequireAuthenticatedUser() + .AddAuthenticationSchemes("DamageApp", "Dadeschools") + .Build(); + options.AddPolicy("DamageApp", DamageAppPolicy); + options.AddPolicy("Dadeschools", DadeschoolsPolicy); + options.AddPolicy("AllPolicies", allPolicy); + options.DefaultPolicy = options.GetPolicy("DamageApp")!; +}); + +var _jwtsettings = builder.Configuration.GetSection("JwtSettings"); +builder.Services.Configure(_jwtsettings); + +builder.Services.AddControllers(); +// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle +builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddScoped(); + +builder.Services.AddHttpClient(). + AddTransientHttpErrorPolicy(policy => policy.WaitAndRetryAsync(maxApiCallRetries, _ => TimeSpan.FromSeconds(intervalToRetry))). + AddTransientHttpErrorPolicy(policy => policy.CircuitBreakerAsync(maxRetryForCircuitBraker, TimeSpan.FromSeconds(intervalForCircuitBraker))); + +builder.Services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); +builder.Services.AddEndpointsApiExplorer(); +//builder.Services.AddSwaggerGen(); + +builder.Services.AddSwaggerGen(options => +{ + + // Include XML comments from your assembly + var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; + var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); + //options.IncludeXmlComments(xmlPath); + + OpenApiSecurityScheme securityDefinition = new OpenApiSecurityScheme() + { + Name = "Bearer", + BearerFormat = "JWT", + Scheme = "bearer", + Description = "Specify the authorization token.", + In = ParameterLocation.Header, + Type = SecuritySchemeType.Http, + }; + + options.AddSecurityDefinition("jwt_auth", securityDefinition); + + // Make sure swagger UI requires a Bearer token specified + OpenApiSecurityScheme securityScheme = new OpenApiSecurityScheme() + { + Reference = new OpenApiReference() + { + Id = "jwt_auth", + Type = ReferenceType.SecurityScheme + } + }; + + OpenApiSecurityRequirement securityRequirements = new OpenApiSecurityRequirement() + { + {securityScheme, new string[] { }}, + }; + + options.AddSecurityRequirement(securityRequirements); +}); + +builder.Services.AddDbContext(option => +{ + option.UseInMemoryDatabase("UsersAccess"); +}); +var app = builder.Build(); + +// Configure the HTTP request pipeline. +if (app.Environment.IsDevelopment()) +{ + app.UseSwagger(); + app.UseSwaggerUI(); + + using (var serviceScope = app.Services.CreateScope()) + { + var services = serviceScope.ServiceProvider; + var usersAccessProvider = services.GetRequiredService(); + usersAccessProvider.seedData(); + } +} + +app.UseAuthentication(); +app.UseAuthorization(); + +app.MapControllers(); +app.Run(); diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Properties/launchSettings.json b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Properties/launchSettings.json new file mode 100644 index 0000000..859e680 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Properties/launchSettings.json @@ -0,0 +1,31 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:28382", + "sslPort": 0 + } + }, + "profiles": { + "DamageAssesment.Api.Users": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "swagger", + "applicationUrl": "http://localhost:5027", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Providers/UserAccessProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Providers/UserAccessProvider.cs new file mode 100644 index 0000000..63a9772 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Providers/UserAccessProvider.cs @@ -0,0 +1,305 @@ +using AutoMapper; +using DamageAssesment.Api.UsersAccess.Db; +using DamageAssesment.Api.UsersAccess.Interfaces; +using DamageAssesment.Api.UsersAccess.Models; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Options; +using Microsoft.IdentityModel.Tokens; +using System.Data; +using System.IdentityModel.Tokens.Jwt; +using System.Security.Claims; +using System.Text; + +namespace DamageAssesment.Api.UsersAccess.Providers +{ + public class UsersAccessProvider : IUsersAccessProvider + { + private readonly UsersAccessDbContext userAccessDbContext; + private readonly ILogger logger; + private readonly IMapper mapper; + //private readonly IEmployeeServiceProvider employeeServiceProvider; + private readonly JwtSettings jwtSettings; + private readonly ITokenServiceProvider tokenServiceProvider; + + public UsersAccessProvider(IOptions options, ITokenServiceProvider tokenServiceProvider, UsersAccessDbContext userAccessDbContext, IEmployeeServiceProvider employeeServiceProvider, ILogger logger, IMapper mapper) + { + this.userAccessDbContext = userAccessDbContext; + //this.employeeServiceProvider = employeeServiceProvider; + this.logger = logger; + this.mapper = mapper; + jwtSettings = options.Value; + this.tokenServiceProvider = tokenServiceProvider; + // seedData(); + } + + public void seedData() + { + if (!userAccessDbContext.Users.Any()) + { + userAccessDbContext.Users.Add(new Db.User { Id = 1, EmployeeId = 1, EmployeeCode = "Emp1", RoleId = 1, IsActive = true, CreateDate = DateTime.Now }); + userAccessDbContext.Users.Add(new Db.User { Id = 2, EmployeeId = 2, EmployeeCode = "Emp2", RoleId = 2, IsActive = true, CreateDate = DateTime.Now }); + userAccessDbContext.Users.Add(new Db.User { Id = 3, EmployeeId = 3, EmployeeCode = "Emp3", RoleId = 3, IsActive = true, CreateDate = DateTime.Now }); + userAccessDbContext.SaveChanges(); + } + + if (!userAccessDbContext.Roles.Any()) + { + userAccessDbContext.Roles.Add(new Db.Role { Id = 1, Name = "admin", Description ="Administrator role have full access" }); + userAccessDbContext.Roles.Add(new Db.Role { Id = 2, Name = "user", Description =" User role"}); + userAccessDbContext.Roles.Add(new Db.Role { Id = 3, Name = "survey", Description ="Survey role" }); + userAccessDbContext.Roles.Add(new Db.Role { Id = 4, Name = "report", Description ="Report role"}); + userAccessDbContext.Roles.Add(new Db.Role { Id = 5, Name = "document", Description ="Document role" }); + userAccessDbContext.SaveChanges(); + } + } + + public async Task<(bool IsSuccess, IEnumerable Users, string ErrorMessage)> GetUsersAsync() + { + try + { + logger?.LogInformation("Gell all Users from DB"); + var users = await userAccessDbContext.Users.ToListAsync(); + if (users != null) + { + logger?.LogInformation($"{users.Count} Items(s) found"); + var result = mapper.Map, IEnumerable>(users); + return (true, result, null); + } + return (false, null, "Not found"); + } + catch (Exception ex) + { + logger?.LogError(ex.ToString()); + return (false, null, ex.Message); + } + } + + public async Task<(bool IsSuccess, Models.User User, string ErrorMessage)> GetUsersAsync(int Id) + { + try + { + logger?.LogInformation("Querying Users table"); + var user = await userAccessDbContext.Users.SingleOrDefaultAsync(s => s.Id == Id); + if (user != null) + { + logger?.LogInformation($"User Id: {Id} found"); + var result = mapper.Map(user); + return (true, result, null); + } + return (false, null, "Not found"); + } + catch (Exception ex) + { + logger?.LogError(ex.ToString()); + return (false, null, ex.Message); + } + } + + public async Task<(bool IsSuccess, Models.User User, string ErrorMessage)> PostUserAsync(Models.User user) + { + try + { + if (user != null) + { + var _user = mapper.Map(user); + userAccessDbContext.Users.Add(_user); + user.Id = _user.Id; + await userAccessDbContext.SaveChangesAsync(); + return (true, user, "Successful"); + } + else + { + logger?.LogInformation($"null object cannot be added"); + return (false, null, $"null object cannot be added"); + } + } + catch (Exception ex) + { + logger?.LogError(ex.ToString()); + return (false, null, ex.Message); + } + } + + public async Task<(bool IsSuccess, Models.User User, string ErrorMessage)> PutUserAsync(int Id, Models.User user) + { + try + { + if (user != null) + { + var _user = await userAccessDbContext.Users.AsNoTracking().Where(s => s.Id == Id).SingleOrDefaultAsync(); + + if (_user != null) + { + int count = userAccessDbContext.Users.Where(u => u.Id != user.Id).Count(); + if (count == 0) + { + await userAccessDbContext.SaveChangesAsync(); + logger?.LogInformation($"Employee Id: {user.EmployeeId} updated successfuly"); + return (true, mapper.Map(_user), $"Employee Id: {_user.EmployeeId} updated successfuly"); + } + else + { + logger?.LogInformation($"Employee Id: {user.EmployeeId} is already exist"); + return (false, null, $"Employee Id: {user.EmployeeId} is already exist"); + } + } + else + { + logger?.LogInformation($"User Id : {Id} Not found"); + return (false, null, "Not Found"); + } + } + else + { + logger?.LogInformation($"User Id: {Id} Bad Request"); + return (false, null, "Bad request"); + } + } + catch (Exception ex) + { + logger?.LogError(ex.ToString()); + return (false, null, ex.Message); + } + } + + public async Task<(bool IsSuccess, Models.User User, string ErrorMessage)> DeleteUserAsync(int Id) + { + try + { + var user = await userAccessDbContext.Users.Where(x => x.Id == Id).SingleOrDefaultAsync(); + + if (user != null) + { + userAccessDbContext.Users.Remove(user); + await userAccessDbContext.SaveChangesAsync(); + logger?.LogInformation($"User Id: {Id} deleted Successfuly"); + return (true, mapper.Map(user), $"User Id: {Id} deleted Successfuly"); + } + else + { + logger?.LogInformation($"User Id : {Id} Not found"); + return (false, null, "Not Found"); + } + } + catch (Exception ex) + { + logger?.LogError(ex.ToString()); + return (false, null, ex.Message); + } + } + + public async Task<(bool IsSuccess, TokenResponse TokenResponse, string ErrorMessage)> AuthenticateAsync(string employecode) + { + + if (employecode != null) + { + //implementation for dadeschools authentication + // var employees = await employeeServiceProvider.getEmployeesAsync(); + // var employee = employees.Where(e=> e.EmployeeCode.ToLower() == employecode.ToLower()).SingleOrDefault(); + var user = userAccessDbContext.Users.Where(x => x.IsActive == true && x.EmployeeCode.ToLower() == employecode.ToLower()).SingleOrDefault(); + + if (user != null) + { + + var r = await GetRolesAsync(); + var role = r.Roles.Where(x => x.Id == user.RoleId).SingleOrDefault(); + + var authClaims = new List { + new Claim(ClaimTypes.Name, user.EmployeeCode), + new Claim(ClaimTypes.Role, role.Name), + new Claim(JwtRegisteredClaimNames.Jti,Guid.NewGuid().ToString()) + + }; + + /// Generate Token + var tokenhandler = new JwtSecurityTokenHandler(); + var tokenkey = Encoding.UTF8.GetBytes(jwtSettings.securitykey); + var tokendesc = new SecurityTokenDescriptor + { + Audience = "", + NotBefore = DateTime.Now, + Subject = new ClaimsIdentity(authClaims), + Expires = DateTime.Now.AddMinutes(30), + SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(tokenkey), SecurityAlgorithms.HmacSha256) + }; + var token = tokenhandler.CreateToken(tokendesc); + string finaltoken = tokenhandler.WriteToken(token); + + var response = new TokenResponse() { jwttoken = finaltoken, refreshtoken = await tokenServiceProvider.GenerateToken(mapper.Map(user)) }; + return (true, response, "Authentication success and token issued."); + } + else + { + return (false, null, "user inactive or not exist."); + } + } + + else + { + return (false, null, "Credentials are required to authenticate."); + } + } + public async Task<(bool IsSuccess, IEnumerable Roles, string ErrorMessage)> GetRolesAsync() + { + try + { + logger?.LogInformation("Gell all Roles from DB"); + var roles = await userAccessDbContext.Roles.ToListAsync(); + if (roles != null) + { + logger?.LogInformation($"{roles.Count} Items(s) found"); + var result = mapper.Map, IEnumerable>(roles); + return (true, result, null); + } + return (false, null, "Not found"); + } + catch (Exception ex) + { + logger?.LogError(ex.ToString()); + return (false, null, ex.Message); + } + } + + public async Task<(bool IsSuccess, Models.TokenResponse TokenResponse, string ErrorMessage)> RefreshTokenAsync(TokenResponse tokenResponse) + { + //Generate token + var tokenhandler = new JwtSecurityTokenHandler(); + var tokenkey = Encoding.UTF8.GetBytes(this.jwtSettings.securitykey); + SecurityToken securityToken; + var principal = tokenhandler.ValidateToken(tokenResponse.jwttoken, new TokenValidationParameters + { + ValidateIssuerSigningKey = true, + IssuerSigningKey = new SymmetricSecurityKey(tokenkey), + ValidateIssuer = false, + ValidateAudience = false, + + }, out securityToken); + + var token = securityToken as JwtSecurityToken; + if (token != null && !token.Header.Alg.Equals(SecurityAlgorithms.HmacSha256)) + { + return (false, null, "Unauthorized"); + } + var username = principal.Identity?.Name; + + var tokens = await userAccessDbContext.Tokens.ToListAsync(); + var users = await userAccessDbContext.Users.ToListAsync(); + + var user = (from u in users + join t in tokens + on u.Id equals t.UserId + where u.EmployeeId == 1 + && t.RefreshToken == tokenResponse.refreshtoken + select u).FirstOrDefault(); + + if (user == null) + return (false, null, "Invalid Token Response object provided"); + + var _user = mapper.Map(user); + var response = tokenServiceProvider.TokenAuthenticate(_user, principal.Claims.ToArray()).Result; + return (true, response, "Token authenticated and refreshed."); + } + + + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Services/EmployeeServiceProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Services/EmployeeServiceProvider.cs new file mode 100644 index 0000000..a06c646 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Services/EmployeeServiceProvider.cs @@ -0,0 +1,50 @@ +using DamageAssesment.Api.UsersAccess.Interfaces; +using DamageAssesment.Api.UsersAccess.Models; +using Newtonsoft.Json; + +namespace DamageAssesment.Api.UsersAccess.Services +{ + public class EmployeeServiceProvider : ServiceProviderBase, IEmployeeServiceProvider + { + public EmployeeServiceProvider(IConfiguration configuration, IHttpUtil httpUtil, ILogger logger) : base(configuration, httpUtil, logger, configuration.GetValue("RessourceSettings:Employee"), configuration.GetValue("EndPointSettings:EmployeeUrlBase")) + { + } + + public async Task> getEmployeesAsync() + { + try + { + var responseJsonString = await httpUtil.SendAsync(HttpMethod.Get, url, null); + var employees = JsonConvert.DeserializeObject>(responseJsonString); + + if (employees == null || !employees.Any()) + return new List(); + else return employees; + } + catch (Exception ex) + { + logger?.LogError($"Exception Found : {ex.Message} - Ref: EmployeeServiceProvider.getEmployeesAsync()"); + return new List(); + } + } + + public async Task getEmployeeAsync(int employeeId) + { + try + { + url = urlBase + string.Format(configuration.GetValue("RessourceSettings:EmployeeById"), employeeId); + var responseJsonString = await httpUtil.SendAsync(HttpMethod.Get, url, null); + var employee = JsonConvert.DeserializeObject(responseJsonString); + + if (employee == null) + return null; + else return employee; + } + catch (Exception ex) + { + logger?.LogError($"Exception Found : {ex.Message} - Ref: EmployeeServiceProvider.getEmployeeAsync()"); + return null; + } + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Services/HttpUtil.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Services/HttpUtil.cs new file mode 100644 index 0000000..973278d --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Services/HttpUtil.cs @@ -0,0 +1,42 @@ +using DamageAssesment.Api.UsersAccess.Interfaces; +using System.Net.Http.Headers; +using System.Text; + +namespace DamageAssesment.Api.UsersAccess.Services +{ + public class HttpUtil : IHttpUtil + { + private readonly HttpClient httpClient; + private readonly ILogger logger; + + public HttpUtil(HttpClient httpClient, ILogger logger) + { + this.httpClient = httpClient; + this.logger = logger; + } + public async Task SendAsync(HttpMethod method, string url, string JsonInput) + { + try + { + var request = new HttpRequestMessage(method, url); + request.Headers.Accept.Clear(); + request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); + + //request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token); + if (method == HttpMethod.Post) + { + request.Content = new StringContent(JsonInput, Encoding.UTF8, "application/json"); + } + var response = await httpClient.SendAsync(request, CancellationToken.None); + response.EnsureSuccessStatusCode(); + var responseString = await response.Content.ReadAsStringAsync(); + return responseString; + } + catch (Exception ex) + { + logger?.LogError($"Exception Message : {ex.Message} - Ref: HttpUtil.SendAsync()"); + return null; + } + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Services/ServiceProviderBase.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Services/ServiceProviderBase.cs new file mode 100644 index 0000000..a90b839 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Services/ServiceProviderBase.cs @@ -0,0 +1,25 @@ +using DamageAssesment.Api.UsersAccess.Interfaces; + +namespace DamageAssesment.Api.UsersAccess.Services +{ + public class ServiceProviderBase + { + protected readonly IConfiguration configuration; + protected readonly IHttpUtil httpUtil; + protected readonly ILogger logger; + protected string ressource; + protected string urlBase; + protected string url; + + + public ServiceProviderBase(IConfiguration configuration, IHttpUtil httpUtil, ILogger logger, string ressource, string urlBase) + { + this.configuration = configuration; + this.httpUtil = httpUtil; + this.logger = logger; + this.ressource = ressource; + this.urlBase = urlBase; + url = urlBase + ressource; + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Services/TokenServiceProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Services/TokenServiceProvider.cs new file mode 100644 index 0000000..91645b9 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Services/TokenServiceProvider.cs @@ -0,0 +1,59 @@ +using System.IdentityModel.Tokens.Jwt; +using System.Security.Claims; +using System.Security.Cryptography; +using System.Text; +using DamageAssesment.Api.UsersAccess.Db; +using DamageAssesment.Api.UsersAccess.Interfaces; +using DamageAssesment.Api.UsersAccess.Models; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Options; +using Microsoft.IdentityModel.Tokens; + +namespace DamageAssesment.Api.UsersAccess.Services +{ + public class TokenServiceProvider : ITokenServiceProvider + { + private readonly UsersAccessDbContext usersAccessDbContext; + private readonly JwtSettings jwtSettings; + public TokenServiceProvider(IOptions options, UsersAccessDbContext usersAccessDbContext) + { + this.usersAccessDbContext = usersAccessDbContext; + this.jwtSettings = options.Value; + } + public async Task GenerateToken(Models.User user) + { + var randomnumber = new byte[32]; + using (var ramdomnumbergenerator = RandomNumberGenerator.Create()) + { + ramdomnumbergenerator.GetBytes(randomnumber); + string refreshtoken = Convert.ToBase64String(randomnumber); + var token = await usersAccessDbContext.Tokens.FirstOrDefaultAsync(item => item.UserId == user.Id); + if (token != null) + { + token.RefreshToken = refreshtoken; + } + else + { + usersAccessDbContext.Tokens.Add(new Db.Token() + { + UserId = user.Id, + RefreshToken = refreshtoken, + IsActive = true + }); + } + await usersAccessDbContext.SaveChangesAsync(); + + return refreshtoken; + } + } + + public async Task TokenAuthenticate(Models.User user, Claim[] claims) + { + var token = new JwtSecurityToken(claims: claims, expires: DateTime.Now.AddSeconds(20), + signingCredentials: new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings.securitykey)), SecurityAlgorithms.HmacSha256) + ); + var jwttoken = new JwtSecurityTokenHandler().WriteToken(token); + return new TokenResponse() { jwttoken = jwttoken, refreshtoken = await GenerateToken(user) }; + } + } +} \ No newline at end of file diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/appsettings.Development.json b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/appsettings.Development.json new file mode 100644 index 0000000..0c208ae --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/appsettings.json b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/appsettings.json new file mode 100644 index 0000000..38fe47e --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/appsettings.json @@ -0,0 +1,36 @@ +{ + "JwtSettings": { + "securitykey": "bWlhbWkgZGFkZSBzY2hvb2xzIHNlY3JldCBrZXk=" + }, + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "EndPointSettings": { + "EmployeeUrlBase": "http://localhost:5135" + }, + "RessourceSettings": { + "Employee": "/Employees", + "EmployeeById": "/Employees/{0}" + }, + "AllowedHosts": "*", + "Dadeschools": { + "Authority": "https://dev-graph.dadeschools.net", + "TokenUrl": "https://dev-graph.dadeschools.net/connect/token", + "ClientId": "dmapi", + "ClientSecret": "bfce2c8d-2064-4a02-b19d-7f1d42b16eae", + "Name": "Dadeschools Identity Server" + }, + "Scopes": [ + { + "Name": "openid", + "Description": "Request an authentication token on your behalf" + }, + { + "Name": "profile", + "Description": "Read basic information about you such as your date of brith and full name" + } + ] +} diff --git a/DamageAssesmentApi/DamageAssesment.SurveyResponses.Test/DamageAssesment.Api.SurveyResponses.Test.csproj b/DamageAssesmentApi/DamageAssesment.SurveyResponses.Test/DamageAssesment.Api.Responses.Test.csproj similarity index 95% rename from DamageAssesmentApi/DamageAssesment.SurveyResponses.Test/DamageAssesment.Api.SurveyResponses.Test.csproj rename to DamageAssesmentApi/DamageAssesment.SurveyResponses.Test/DamageAssesment.Api.Responses.Test.csproj index a384a67..03b9b5c 100644 --- a/DamageAssesmentApi/DamageAssesment.SurveyResponses.Test/DamageAssesment.Api.SurveyResponses.Test.csproj +++ b/DamageAssesmentApi/DamageAssesment.SurveyResponses.Test/DamageAssesment.Api.Responses.Test.csproj @@ -24,7 +24,7 @@ - + diff --git a/DamageAssesmentApi/DamageAssesment.SurveyResponses.Test/SurveyResponsesServiceTest.cs b/DamageAssesmentApi/DamageAssesment.SurveyResponses.Test/SurveyResponsesServiceTest.cs index 47685a5..593038d 100644 --- a/DamageAssesmentApi/DamageAssesment.SurveyResponses.Test/SurveyResponsesServiceTest.cs +++ b/DamageAssesmentApi/DamageAssesment.SurveyResponses.Test/SurveyResponsesServiceTest.cs @@ -12,10 +12,12 @@ namespace DamageAssesment.SurveyResponses.Test { public class SurveyResponsesServiceTest { - Mock mockSurveyResponseService; + private Mock mockSurveyResponseService; + private string token { get; set; } public SurveyResponsesServiceTest() { mockSurveyResponseService = new Mock(); + token = Guid.NewGuid().ToString(); } [Fact(DisplayName = "Get SurveyResponses - Ok case")] @@ -23,7 +25,7 @@ namespace DamageAssesment.SurveyResponses.Test { SurveyResponse mockRequestObject = await MockData.getSurveyResponseObject(); var mockResponse = await MockData.getOkResponse(mockRequestObject); - mockSurveyResponseService.Setup(service => service.GetSurveyResponsesAsync()).ReturnsAsync(mockResponse); + mockSurveyResponseService.Setup(service => service.GetSurveyResponsesAsync(token)).ReturnsAsync(mockResponse); var surveyResponseProvider = new SurveyResponsesController(mockSurveyResponseService.Object); var result = (OkObjectResult)await surveyResponseProvider.GetSurveyResponsesAsync(); Assert.Equal(200, result.StatusCode); @@ -33,7 +35,7 @@ namespace DamageAssesment.SurveyResponses.Test public async Task GetSurveyResponsesAsync_ShouldReturnStatusCode204() { var mockResponse = await MockData.getResponse(); - mockSurveyResponseService.Setup(service => service.GetSurveyResponsesAsync()).ReturnsAsync(mockResponse); + mockSurveyResponseService.Setup(service => service.GetSurveyResponsesAsync(token)).ReturnsAsync(mockResponse); var surveyResponseProvider = new SurveyResponsesController(mockSurveyResponseService.Object); var result = (BadRequestObjectResult)await surveyResponseProvider.GetSurveyResponsesAsync(); Assert.Equal(400, result.StatusCode); @@ -44,7 +46,7 @@ namespace DamageAssesment.SurveyResponses.Test { SurveyResponse mockRequestObject = await MockData.getSurveyResponseObject(); var mockResponse = await MockData.getOkResponse(); - mockSurveyResponseService.Setup(service => service.GetSurveyResponsesBySurveyAsync(1)).ReturnsAsync(mockResponse); + mockSurveyResponseService.Setup(service => service.GetSurveyResponsesBySurveyAsync(1, token)).ReturnsAsync(mockResponse); var surveyResponseProvider = new SurveyResponsesController(mockSurveyResponseService.Object); var result = (OkObjectResult)await surveyResponseProvider.GetSurveyResponsesAsync(1); Assert.Equal(200, result.StatusCode); @@ -54,7 +56,7 @@ namespace DamageAssesment.SurveyResponses.Test public async Task GetSurveyResponsesBySurveyAsync_ShouldReturnStatusCode204() { var mockResponse = await MockData.getResponse(); - mockSurveyResponseService.Setup(service => service.GetSurveyResponsesBySurveyAsync(1)).ReturnsAsync(mockResponse); + mockSurveyResponseService.Setup(service => service.GetSurveyResponsesBySurveyAsync(1, token)).ReturnsAsync(mockResponse); var surveyResponseProvider = new SurveyResponsesController(mockSurveyResponseService.Object); var result = (NoContentResult)await surveyResponseProvider.GetSurveyResponsesAsync(1); Assert.Equal(204, result.StatusCode); @@ -68,7 +70,7 @@ namespace DamageAssesment.SurveyResponses.Test { SurveyResponse mockRequestObject = await MockData.getSurveyResponseObject(); var mockResponse = await MockData.getOkResponse(); - mockSurveyResponseService.Setup(service => service.GetSurveyResponsesBySurveyAndLocationAsync(1, 1)).ReturnsAsync(mockResponse); + mockSurveyResponseService.Setup(service => service.GetSurveyResponsesBySurveyAndLocationAsync(1, 1, token)).ReturnsAsync(mockResponse); var surveyResponseProvider = new SurveyResponsesController(mockSurveyResponseService.Object); var result = (OkObjectResult)await surveyResponseProvider.GetSurveyResponsesBySurveyAndLocationAsync(1, 1); Assert.Equal(200, result.StatusCode); @@ -78,7 +80,7 @@ namespace DamageAssesment.SurveyResponses.Test public async Task GetSurveyResponsesBySurveyLocationAsync_ShouldReturnStatusCode204() { var mockResponse = await MockData.getResponse(); - mockSurveyResponseService.Setup(service => service.GetSurveyResponsesBySurveyAndLocationAsync(1, 1)).ReturnsAsync(mockResponse); + mockSurveyResponseService.Setup(service => service.GetSurveyResponsesBySurveyAndLocationAsync(1, 1, token)).ReturnsAsync(mockResponse); var surveyResponseProvider = new SurveyResponsesController(mockSurveyResponseService.Object); var result = (NoContentResult)await surveyResponseProvider.GetSurveyResponsesBySurveyAndLocationAsync(1, 1); Assert.Equal(204, result.StatusCode); @@ -89,7 +91,7 @@ namespace DamageAssesment.SurveyResponses.Test { SurveyResponse mockRequestObject = await MockData.getSurveyResponseObject(); var mockResponse = await MockData.getOkResponse(); - mockSurveyResponseService.Setup(service => service.GetResponsesByAnswerAsync(1, 1, "Yes")).ReturnsAsync(mockResponse); + mockSurveyResponseService.Setup(service => service.GetResponsesByAnswerAsync(1, 1, "Yes", token)).ReturnsAsync(mockResponse); var surveyResponseProvider = new SurveyResponsesController(mockSurveyResponseService.Object); var result = (OkObjectResult)await surveyResponseProvider.GetSurveyResponsesByAnswerAsyncAsync(1, 1, "Yes"); Assert.Equal(200, result.StatusCode); @@ -99,7 +101,7 @@ namespace DamageAssesment.SurveyResponses.Test public async Task GetSurveyResponsesBySurveyQuestionAnswerAsync_ShouldReturnStatusCode204() { var mockResponse = await MockData.getResponse(); - mockSurveyResponseService.Setup(service => service.GetResponsesByAnswerAsync(1, 1, "Yes")).ReturnsAsync(mockResponse); + mockSurveyResponseService.Setup(service => service.GetResponsesByAnswerAsync(1, 1, "Yes", token)).ReturnsAsync(mockResponse); var surveyResponseProvider = new SurveyResponsesController(mockSurveyResponseService.Object); var result = (NoContentResult)await surveyResponseProvider.GetSurveyResponsesByAnswerAsyncAsync(1, 1, "Yes"); Assert.Equal(204, result.StatusCode); @@ -111,7 +113,7 @@ namespace DamageAssesment.SurveyResponses.Test { SurveyResponse mockRequestObject = await MockData.getSurveyResponseObject(); var mockResponse = await MockData.getOkResponse(); - mockSurveyResponseService.Setup(service => service.GetAnswersByRegionAsync(1)).ReturnsAsync(mockResponse); + mockSurveyResponseService.Setup(service => service.GetAnswersByRegionAsync(1, token)).ReturnsAsync(mockResponse); var surveyResponseProvider = new SurveyResponsesController(mockSurveyResponseService.Object); var result = (OkObjectResult)await surveyResponseProvider.GetAnswersByRegionAsync(1); Assert.Equal(200, result.StatusCode); @@ -121,7 +123,7 @@ namespace DamageAssesment.SurveyResponses.Test public async Task GetSurveyResponsesByRegionSurveyAsync_ShouldReturnStatusCode204() { var mockResponse = await MockData.getResponse(); - mockSurveyResponseService.Setup(service => service.GetAnswersByRegionAsync(1)).ReturnsAsync(mockResponse); + mockSurveyResponseService.Setup(service => service.GetAnswersByRegionAsync(1, token)).ReturnsAsync(mockResponse); var surveyResponseProvider = new SurveyResponsesController(mockSurveyResponseService.Object); var result = (NoContentResult)await surveyResponseProvider.GetAnswersByRegionAsync(1); Assert.Equal(204, result.StatusCode); @@ -132,7 +134,7 @@ namespace DamageAssesment.SurveyResponses.Test { SurveyResponse mockRequestObject = await MockData.getSurveyResponseObject(); var mockResponse = await MockData.getOkResponse(); - mockSurveyResponseService.Setup(service => service.GetSurveyResponsesByMaintenanceCenterAsync(1)).ReturnsAsync(mockResponse); + mockSurveyResponseService.Setup(service => service.GetSurveyResponsesByMaintenanceCenterAsync(1, token)).ReturnsAsync(mockResponse); var surveyResponseProvider = new SurveyResponsesController(mockSurveyResponseService.Object); var result = (OkObjectResult)await surveyResponseProvider.GetAnswersByMaintenaceCentersync(1); Assert.Equal(200, result.StatusCode); @@ -142,7 +144,7 @@ namespace DamageAssesment.SurveyResponses.Test public async Task GetSurveyResponsesMaintenanceCenterSurveyAsync_ShouldReturnStatusCode204() { var mockResponse = await MockData.getResponse(); - mockSurveyResponseService.Setup(service => service.GetSurveyResponsesByMaintenanceCenterAsync(1)).ReturnsAsync(mockResponse); + mockSurveyResponseService.Setup(service => service.GetSurveyResponsesByMaintenanceCenterAsync(1, token)).ReturnsAsync(mockResponse); var surveyResponseProvider = new SurveyResponsesController(mockSurveyResponseService.Object); var result = (NoContentResult)await surveyResponseProvider.GetAnswersByMaintenaceCentersync(1); Assert.Equal(204, result.StatusCode); @@ -153,7 +155,7 @@ namespace DamageAssesment.SurveyResponses.Test { SurveyResponse mockRequestObject = await MockData.getSurveyResponseObject(); var mockResponse = await MockData.getOkResponse(); - mockSurveyResponseService.Setup(service => service.GetSurveyResponseByIdAsync(1)).ReturnsAsync(mockResponse); + mockSurveyResponseService.Setup(service => service.GetSurveyResponseByIdAsync(1, token)).ReturnsAsync(mockResponse); var surveyResponseProvider = new SurveyResponsesController(mockSurveyResponseService.Object); var result = (OkObjectResult)await surveyResponseProvider.GetSurveyResponseByIdAsync(1); Assert.Equal(200, result.StatusCode); @@ -163,7 +165,7 @@ namespace DamageAssesment.SurveyResponses.Test public async Task GetSurveyResponsesByResponseIdyAsync_ShouldReturnStatusCode204() { var mockResponse = await MockData.getResponse(); - mockSurveyResponseService.Setup(service => service.GetSurveyResponseByIdAsync(1)).ReturnsAsync(mockResponse); + mockSurveyResponseService.Setup(service => service.GetSurveyResponseByIdAsync(1, token)).ReturnsAsync(mockResponse); var surveyResponseProvider = new SurveyResponsesController(mockSurveyResponseService.Object); var result = (NoContentResult)await surveyResponseProvider.GetSurveyResponseByIdAsync(1); Assert.Equal(204, result.StatusCode); diff --git a/DamageAssesmentApi/DamageAssesment.sln b/DamageAssesmentApi/DamageAssesment.sln index 0cb2d7c..a9ec1fe 100644 --- a/DamageAssesmentApi/DamageAssesment.sln +++ b/DamageAssesmentApi/DamageAssesment.sln @@ -17,13 +17,13 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DamageAssesment.Api.Locations", "DamageAssesment.Api.Locations\DamageAssesment.Api.Locations.csproj", "{746C67BF-9949-4361-B5D2-358C7607750E}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DamageAssesment.Api.SurveyResponses", "DamageAssesment.Api.SurveyResponses\DamageAssesment.Api.SurveyResponses.csproj", "{D11808FE-AD1C-4BA6-87FD-9D18B2DC81F2}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DamageAssesment.Api.Responses", "DamageAssesment.Api.SurveyResponses\DamageAssesment.Api.Responses.csproj", "{D11808FE-AD1C-4BA6-87FD-9D18B2DC81F2}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DamageAssesment.Api.Questions.Test", "DamageAssesment.Api.QuestionsTest\DamageAssesment.Api.Questions.Test.csproj", "{35CD9231-034D-4999-BCFC-1786DD007ED2}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DamageAssesment.Api.Surveys.Test", "DamageAssesment.Api.Surveys.Test\DamageAssesment.Api.Surveys.Test.csproj", "{ADFB79E3-83C9-454F-A070-49D167BD28CC}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DamageAssesment.Api.SurveyResponses.Test", "DamageAssesment.SurveyResponses.Test\DamageAssesment.Api.SurveyResponses.Test.csproj", "{6F4B9C9D-CE5D-421A-876F-57D0FEDF8049}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DamageAssesment.Api.Responses.Test", "DamageAssesment.SurveyResponses.Test\DamageAssesment.Api.Responses.Test.csproj", "{6F4B9C9D-CE5D-421A-876F-57D0FEDF8049}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DamageAssesment.Api.Attachments.Test", "DamageAssesment.Api.Attachments.Test\DamageAssesment.Api.Attachments.Test.csproj", "{730E5718-FCE1-42C0-AB76-EA020896A788}" EndProject @@ -41,6 +41,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DamageAssesment.Api.DocuLin EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DamageAssesment.Api.DocuLinks.Test", "DamageAssesment.Api.Documents.Test\DamageAssesment.Api.DocuLinks.Test.csproj", "{884BA4AC-9170-49B1-BD6B-850B350C95C0}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DamageAssesment.Api.UsersAccess", "DamageAssesment.Api.UsersAccess\DamageAssesment.Api.UsersAccess.csproj", "{40240AD6-90D2-4128-BCDF-12C77D1B1B55}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -76,7 +78,6 @@ Global {ADFB79E3-83C9-454F-A070-49D167BD28CC}.Release|Any CPU.ActiveCfg = Release|Any CPU {ADFB79E3-83C9-454F-A070-49D167BD28CC}.Release|Any CPU.Build.0 = Release|Any CPU {6F4B9C9D-CE5D-421A-876F-57D0FEDF8049}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6F4B9C9D-CE5D-421A-876F-57D0FEDF8049}.Debug|Any CPU.Build.0 = Debug|Any CPU {6F4B9C9D-CE5D-421A-876F-57D0FEDF8049}.Release|Any CPU.ActiveCfg = Release|Any CPU {6F4B9C9D-CE5D-421A-876F-57D0FEDF8049}.Release|Any CPU.Build.0 = Release|Any CPU {730E5718-FCE1-42C0-AB76-EA020896A788}.Debug|Any CPU.ActiveCfg = Debug|Any CPU @@ -111,6 +112,10 @@ Global {884BA4AC-9170-49B1-BD6B-850B350C95C0}.Debug|Any CPU.Build.0 = Debug|Any CPU {884BA4AC-9170-49B1-BD6B-850B350C95C0}.Release|Any CPU.ActiveCfg = Release|Any CPU {884BA4AC-9170-49B1-BD6B-850B350C95C0}.Release|Any CPU.Build.0 = Release|Any CPU + {40240AD6-90D2-4128-BCDF-12C77D1B1B55}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {40240AD6-90D2-4128-BCDF-12C77D1B1B55}.Debug|Any CPU.Build.0 = Debug|Any CPU + {40240AD6-90D2-4128-BCDF-12C77D1B1B55}.Release|Any CPU.ActiveCfg = Release|Any CPU + {40240AD6-90D2-4128-BCDF-12C77D1B1B55}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE