Created
December 3, 2023 21:24
-
-
Save shanji97/19022c72218e07e692667c1042223903 to your computer and use it in GitHub Desktop.
Swagger issue.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Carter; | |
using Microsoft.AspNetCore.Authentication.JwtBearer; | |
using Microsoft.EntityFrameworkCore; | |
using Microsoft.Extensions.Options; | |
using Microsoft.IdentityModel.Tokens; | |
using Microsoft.OpenApi.Models; | |
using RSO.Core.BL; | |
using RSO.Core.Configurations; | |
using RSO.Core.Models; | |
using RSO.Core.Repository; | |
using System.Text; | |
using UserServiceRSO.Repository; | |
namespace UserServiceRSO; | |
public class Program | |
{ | |
public static void Main(string[] args) | |
{ | |
var builder = WebApplication.CreateBuilder(args); | |
// Register the IOptions object. | |
builder.Services.AddOptions<UserServicesSettingsConfiguration>() | |
.BindConfiguration("UserServicesSettingsConfiguration"); | |
// Explicitly register the settings objects by delegating to the IOptions object. | |
builder.Services.AddSingleton(resolver => resolver.GetRequiredService<IOptions<UserServicesSettingsConfiguration>>().Value); | |
// Register the IOptions object. | |
builder.Services.AddOptions<JwtSecurityTokenConfiguration>() | |
.BindConfiguration("JwtSecurityTokenConfiguration"); | |
// Explicitly register the settings objects by delegating to the IOptions object. | |
builder.Services.AddSingleton(resolver => resolver.GetRequiredService<IOptions<JwtSecurityTokenConfiguration>>().Value); | |
//Database settings | |
builder.Services.AddDbContext<UserServicesRSOContext>(options => | |
options.UseNpgsql(builder.Configuration.GetConnectionString("UserServicesRSOdB"))); | |
//Lazy cache | |
builder.Services.AddLazyCache(); | |
// Add unit of work & repositories. | |
builder.Services.AddScoped<IUnitOfWork, UnitOfWork>(); | |
builder.Services.AddScoped<IUserRepository, UserRepository>(); //In each microservice a different repository/serice is inlcuded. If more tables are needed add more repos related to the microservice. | |
// Logic | |
builder.Services.AddScoped<IUserLogic, UserLogic>(); //In each microservice a different repository/serice is inlcuded. | |
//JWT | |
builder.Services | |
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) | |
.AddJwtBearer(o => o.TokenValidationParameters = new() | |
{ | |
ValidateIssuer = true, | |
ValidateAudience = true, | |
ValidateLifetime = true, | |
ValidateIssuerSigningKey = true, | |
// Read from appsettings.json ...WARNING VALUES MUST BE THE SAME IN ALL IMPLEMENTATIONS. | |
// BETTER, CLEANER WAY? | |
IssuerSigningKey = new SymmetricSecurityKey( | |
Encoding.UTF8.GetBytes(builder.Configuration | |
.GetSection("JwtSecurityTokenConfiguration"). | |
Get<JwtSecurityTokenConfiguration>().SecretKey)), | |
ValidIssuer = builder.Configuration | |
.GetSection("JwtSecurityTokenConfiguration"). | |
Get<JwtSecurityTokenConfiguration>().Issuer, | |
ValidAudience = builder.Configuration | |
.GetSection("JwtSecurityTokenConfiguration"). | |
Get<JwtSecurityTokenConfiguration>().Audience | |
}); | |
//Carter | |
builder.Services.AddHttpContextAccessor(); | |
builder.Services.AddCarter(); | |
// Add services to the container. | |
builder.Services.AddAuthorization(); | |
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle | |
builder.Services.AddEndpointsApiExplorer(); | |
builder.Services.AddSwaggerGen(swagger => | |
{ | |
swagger.SwaggerDoc("v1", new OpenApiInfo() | |
{ | |
Description = "User microservice for E-commerce app.", | |
Title = "RSO project.", | |
Version = "v1", | |
Contact = new OpenApiContact() | |
{ | |
Name = "Aleksander Kovac & Urban Poljsak", | |
Url = new Uri("https://www.youtube.com/watch?v=dQw4w9WgXcQ") | |
} | |
}); | |
swagger.AddSecurityDefinition("jwt_auth", new OpenApiSecurityScheme() | |
{ | |
Description = "Basic authorization with JWT token.", | |
Name = "Bearer", | |
BearerFormat ="JWT", | |
In = ParameterLocation.Header, | |
Type = SecuritySchemeType.ApiKey | |
}); | |
swagger.AddSecurityRequirement(new OpenApiSecurityRequirement() | |
{ | |
{new OpenApiSecurityScheme() | |
{ | |
Reference = new OpenApiReference() | |
{ | |
Id="jwt_auth", | |
Type = ReferenceType.SecurityScheme | |
} | |
},Array.Empty<string>() }, | |
}); | |
}); | |
// APP. | |
var app = builder.Build(); | |
// Carter | |
app.MapCarter(); | |
app.UseSwagger(); | |
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "API")); | |
app.UseAuthentication(); | |
app.UseAuthorization(); | |
app.Run(); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Carter; | |
using Microsoft.AspNetCore.Authorization; | |
using Microsoft.AspNetCore.Http.HttpResults; | |
using RSO.Core.BL; | |
using RSO.Core.BL.LogicModels; | |
using RSO.Core.Models; | |
namespace UserServiceRSO.CarterModules; | |
public class UserEndpoints : ICarterModule | |
{ | |
public void AddRoutes(IEndpointRouteBuilder app) | |
{ | |
// Login and register options. | |
app.MapPost("/login", Login).WithName(nameof(Login)). | |
Produces(StatusCodes.Status200OK). | |
Produces(StatusCodes.Status400BadRequest); | |
app.MapPost("/register", Register).WithName(nameof(Register)). | |
Produces(StatusCodes.Status201Created). | |
Produces(StatusCodes.Status400BadRequest). | |
Produces(StatusCodes.Status404NotFound); | |
// Group for /api/user endpoinds. | |
var group = app.MapGroup("/api/user/"); | |
// Methods for /api/user/id endpoints. | |
group.MapGet("{id}", GetUserById).WithName(nameof(GetUserById)). | |
Produces(StatusCodes.Status200OK). | |
Produces(StatusCodes.Status400BadRequest). | |
Produces(StatusCodes.Status401Unauthorized); | |
} | |
/// <summary> | |
/// Performs login and gets the JWT token. | |
/// </summary> | |
/// <param name="emailOrUsername"></param> | |
/// <param name="password"></param> | |
/// <param name="userLogic"></param> | |
/// <returns>A JWT token as a string.</returns> | |
public static async Task<Results<Ok<string>, BadRequest<string>>> Login(string emailOrUsername, string password, IUserLogic userLogic) | |
{ | |
if (string.IsNullOrEmpty(emailOrUsername) || string.IsNullOrEmpty(password)) | |
return TypedResults.BadRequest("Username (or email) and password cannot be null"); | |
else | |
{ | |
var user = await userLogic.GetUserByUsernameOrEmailAndPasswordAsync(emailOrUsername, password); | |
var jwt = userLogic.GetJwtToken(user); | |
return jwt is null | |
? TypedResults.BadRequest("The user with the specified username/email and password doesn't exist.") | |
: TypedResults.Ok(jwt); | |
} | |
} | |
/// <summary> | |
/// Performs registration and gets the JWT token. | |
/// </summary> | |
/// <param name="newUser">Data for the new user that is going to be created.</param> | |
/// <param name="userLogic">DI for B(usiness) L(logic) layer.</param> | |
/// <returns>A JWT token as a string.</returns> | |
public static async Task<Results<Created<string>, NotFound<string>, BadRequest<string>>> Register( User newUser, IUserLogic userLogic) | |
{ | |
//SKIP VALIDATION (IMPLEMENT IT WHEN TIME REMAINS | |
newUser.UserCity = await userLogic.GetCityFromZipCodeAsync(newUser.UserZipCode); | |
newUser.UserZipCode = string.IsNullOrEmpty(newUser.UserCity) ? null : newUser.UserZipCode; | |
//Insert user and create a logic for the JWT | |
try | |
{ | |
// Inser user into database | |
var user = await userLogic.RegisterUserAsync(newUser); | |
if (user is null) return TypedResults.NotFound("Something happened with the database that prevented the insertion of the user."); | |
// Generate a JWT token. | |
var jwt = userLogic.GetJwtToken(user); | |
return string.IsNullOrEmpty(jwt) ? TypedResults.BadRequest("User has been successfully registered but failed to retrieve the JWT token.") : TypedResults.Created("/", jwt); | |
} | |
catch (Exception ex) | |
{ | |
return TypedResults.BadRequest(ex.Message); | |
} | |
} | |
/// <summary> | |
/// Gets the user by id. | |
/// </summary> | |
/// <param name="id">Id of the user.</param> | |
/// <param name="userLogic"><see cref="IUserLogic"/> instance.</param> | |
/// <returns>User data for the user.</returns> | |
[Authorize(AuthenticationSchemes = Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerDefaults.AuthenticationScheme)] | |
public static async Task<Results<Ok<UserDataDTO>, BadRequest<string>>> GetUserById(int id, IUserLogic userLogic) | |
{ | |
/// Read the JWT token. | |
var user = await userLogic.GetUserByIdAsync(id); | |
if (user is null) | |
return TypedResults.BadRequest("User with the specified doesn't exist."); | |
var userData = new UserDataDTO(user); | |
return TypedResults.Ok(userData); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
... | |
public string GetJwtToken(User existingUser) | |
{ | |
var claims = new Claim[] { | |
new(JwtRegisteredClaimNames.Sub,existingUser.UserId.ToString()), | |
new(JwtRegisteredClaimNames.Email,existingUser.UserEmail), | |
new(JwtRegisteredClaimNames.AuthTime, DateTime.UtcNow.ToString()), | |
}; | |
var signingCredentials = new SigningCredentials( | |
new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtConfiguration.SecretKey)), | |
SecurityAlgorithms.HmacSha256); | |
var jwtToken = new JwtSecurityToken( | |
_jwtConfiguration.Issuer, | |
_jwtConfiguration.Audience, | |
claims, | |
DateTime.UtcNow.AddSeconds(-5), | |
DateTime.UtcNow.AddDays(7), | |
signingCredentials); | |
return new JwtSecurityTokenHandler().WriteToken(jwtToken); | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment