Skip to content

Commit

Permalink
Added Keycloak integrationa and added RabbitMQ
Browse files Browse the repository at this point in the history
  • Loading branch information
KevinOomenTheDeveloper committed May 6, 2024
1 parent f47749b commit 34c3078
Show file tree
Hide file tree
Showing 8 changed files with 294 additions and 39 deletions.
28 changes: 14 additions & 14 deletions MusicService/Controllers/SongController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,21 @@ namespace MusicService.Controllers
[ApiController]
public class SongController : ControllerBase
{

private readonly ISongService _songService;

public SongController(ISongService songService)
{
_songService = songService;
}

[Authorize(Roles = "Admin")]
[HttpGet("all")]
public async Task<ActionResult<ServiceResponse<List<GetSongDto>>>> GetAllSongs()
{
var response = await _songService.GetAllSongs();

if (response.Data == null)
return StatusCode(StatusCodes.Status404NotFound, response);
return StatusCode(StatusCodes.Status503ServiceUnavailable, response);

return StatusCode(StatusCodes.Status200OK, response);
}
Expand All @@ -35,20 +35,20 @@ public async Task<ActionResult<ServiceResponse<GetSongDto>>> GetSong(int songId)
var response = await _songService.GetSong(songId);

if (response.Data == null)
return StatusCode(StatusCodes.Status404NotFound, response);
return StatusCode(StatusCodes.Status503ServiceUnavailable, response);

return StatusCode(StatusCodes.Status200OK, response);
}

[HttpPost]
public async Task<ActionResult<ServiceResponse<GetSongDto>>> AddSong(AddSongDto request)
{
var songResponse = await _songService.AddSong(request);
var response = await _songService.AddSong(request);

if (!songResponse.Success)
return StatusCode(StatusCodes.Status404NotFound, songResponse);
if (!response.Success)
return StatusCode(StatusCodes.Status503ServiceUnavailable, response);

return StatusCode(StatusCodes.Status201Created, songResponse);
return StatusCode(StatusCodes.Status201Created, response);
}

[HttpPut]
Expand All @@ -57,20 +57,20 @@ public async Task<ActionResult<ServiceResponse<GetSongDto>>> UpdateSong(UpdateSo
var response = await _songService.UpdateSong(request);

if (response.Data == null)
return StatusCode(StatusCodes.Status404NotFound, response);
return StatusCode(StatusCodes.Status503ServiceUnavailable, response);

return StatusCode(StatusCodes.Status200OK, response);
}

/*[HttpDelete("{songId}")]
[HttpDelete("{songId}")]
public async Task<ActionResult<ServiceResponse<GetSongDto>>> DeleteSong(int songId)
{
/*var response = await _songService;
var response = await _songService.DeleteSong(songId);

if (response.Data == null)
return StatusCode(StatusCodes.Status404NotFound, response);
if (!response.Success)
return StatusCode(StatusCodes.Status503ServiceUnavailable, response);

return StatusCode(StatusCodes.Status200OK, response);
}*/
return StatusCode(StatusCodes.Status204NoContent, response);
}
}
}
10 changes: 9 additions & 1 deletion MusicService/Data/DataContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,15 @@ namespace MusicService.Data
public class DataContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.UseNpgsql("Host=localhost;Port=5432;Database=music;Username=postgres;Password=example");
{
IConfigurationRoot configuration = new ConfigurationBuilder()
.SetBasePath(AppDomain.CurrentDomain.BaseDirectory)
.AddJsonFile("appsettings.json")
.Build();

optionsBuilder.UseNpgsql(configuration.GetConnectionString("DefaultConnection"));
}


public DataContext()
{
Expand Down
2 changes: 2 additions & 0 deletions MusicService/MusicService.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@

<ItemGroup>
<PackageReference Include="AutoMapper" Version="13.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="7.0.18" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.11">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="7.0.11" />
<PackageReference Include="RabbitMQ.Client" Version="6.8.1" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
</ItemGroup>

Expand Down
126 changes: 119 additions & 7 deletions MusicService/Program.cs
Original file line number Diff line number Diff line change
@@ -1,18 +1,125 @@
using MusicService.Data;
using MusicService.Services.Song;
using Microsoft.IdentityModel.Tokens;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.OpenApi.Models;
using MusicService.Services.Event;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddDbContext<DataContext>();
var services = builder.Services;

// Add authentication services
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(o =>
{

//authority runs behind reverse proxy
o.RequireHttpsMetadata = false;

o.Authority = builder.Configuration["Jwt:Authority"];
o.Audience = builder.Configuration["Jwt:Audience"];


o.TokenValidationParameters = new TokenValidationParameters
{
//asp.net core seems to expect an audience with the name of the client, this disables the check
//This is primarily for architectures where certain services aren't trusted.
//The person sending the token can specify what service the token is meant for.
//This prevents "bad" services from using the token to send requests to other services.
//Since this architecture doesn't have untrusted services, this is not necessary.
ValidateAudience = false
};

});

/*.AddOpenIdConnect(options =>
{
// Configure the authority to your Keycloak realm URL
options.Authority = "http://localhost:8080/realms/SpotiCloud";
options.RequireHttpsMetadata = false;
// Configure the client ID and client secret
options.ClientId = "test";
options.ClientSecret = "DRW0BGdceP1mMdO7tYo0NIycGYyPVifx";
// Set the callback path
options.CallbackPath = "/swagger/index.html";
// Configure the response type
options.ResponseType = OpenIdConnectResponseType.Code;
// Configure the scope
options.Scope.Clear();
options.Scope.Add("openid");
//options.Scope.Add("profile");
//options.Scope.Add("email");
// Configure the token validation parameters
options.TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = "name",
RoleClaimType = "role"
};
});*/

services.AddDbContext<DataContext>();
// Add services to the container.
builder.Services.AddControllers();
services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(setup =>
{
setup.SwaggerDoc("v1", new OpenApiInfo { Title = "Music API v1.0", Version = "v1" });
setup.AddSecurityDefinition("OAuth2", new OpenApiSecurityScheme
{
Type = SecuritySchemeType.OAuth2,
Flows = new OpenApiOAuthFlows
{
Implicit = new OpenApiOAuthFlow
{
AuthorizationUrl = new Uri("http://localhost:8080/realms/SpotiCloud/protocol/openid-connect/auth"),
}
}
});
setup.AddSecurityRequirement(new OpenApiSecurityRequirement{
{
new OpenApiSecurityScheme{
Reference = new OpenApiReference{
Type = ReferenceType.SecurityScheme,
Id = "OAuth2" //The name of the previously defined security scheme.
}
},
new string[] {}
}
});

builder.Services.AddAutoMapper(typeof(Program).Assembly);
/*var jwtSecurityScheme = new OpenApiSecurityScheme
{
Scheme = "bearer",
BearerFormat = "JWT",
Name = "Authentication",
In = ParameterLocation.Header,
Type = SecuritySchemeType.Http,
builder.Services.AddScoped<ISongService, SongService>();
Reference = new OpenApiReference
{
Id = JwtBearerDefaults.AuthenticationScheme,
Type = ReferenceType.SecurityScheme
}
};
setup.AddSecurityDefinition(jwtSecurityScheme.Reference.Id, jwtSecurityScheme);
setup.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{ jwtSecurityScheme, Array.Empty<string>() }
});*/
});

services.AddAutoMapper(typeof(Program).Assembly);

services.AddScoped<ISongService, SongService>();
services.AddSingleton<IEventService, EventService>();

var app = builder.Build();

Expand All @@ -23,10 +130,15 @@
app.UseSwaggerUI();
}

app.UseHttpsRedirection();
//app.UseHttpsRedirection();

app.UseAuthentication();
app.UseAuthorization();

/*app.UseCookiePolicy(new CookiePolicyOptions{
MinimumSameSitePolicy = SameSiteMode.Lax
});*/

app.MapControllers();

app.Run();
64 changes: 64 additions & 0 deletions MusicService/Services/Event/EventService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
using RabbitMQ.Client.Events;
using RabbitMQ.Client;
using System.Text.Json;
using System.Text;

namespace MusicService.Services.Event
{
public class EventService : IEventService, IDisposable
{
private readonly IConnection connection;
public EventService(IConfiguration configuration)
{
var factory = new ConnectionFactory
{
HostName = configuration.GetConnectionString("rabbitmq")
};

connection = factory.CreateConnection();
}

public void Dispose()
{
connection.Close();
}

public void Publish<T>(string exchange, string topic, T data)
{
using var channel = connection.CreateModel();

channel.ExchangeDeclare(exchange, ExchangeType.Direct, durable: true, autoDelete: false);

var json = JsonSerializer.Serialize(data);
var body = Encoding.UTF8.GetBytes(json);

channel.BasicPublish(exchange: exchange, routingKey: topic, body: body);
}

public void subscribe<T>(string exchange, string queue, string topic, Action<T> handler)
{
var channel = connection.CreateModel();

channel.ExchangeDeclare(exchange: exchange, type: ExchangeType.Direct, durable: true, autoDelete: false);
channel.QueueDeclare(queue, exclusive: false, autoDelete: false);
channel.QueueBind(exchange: exchange, routingKey: topic, queue: queue);

channel.BasicQos(0, 1, false);


var consumer = new EventingBasicConsumer(channel);

consumer.Received += (model, eventArgs) =>
{
var body = eventArgs.Body.ToArray();
var message = Encoding.UTF8.GetString(body);

var data = JsonSerializer.Deserialize<T>(message);

handler.Invoke(data);

Check warning on line 58 in MusicService/Services/Event/EventService.cs

View workflow job for this annotation

GitHub Actions / build

Possible null reference argument for parameter 'obj' in 'void Action<T>.Invoke(T obj)'.

Check warning on line 58 in MusicService/Services/Event/EventService.cs

View workflow job for this annotation

GitHub Actions / build

Possible null reference argument for parameter 'obj' in 'void Action<T>.Invoke(T obj)'.
};

channel.BasicConsume(queue: queue, autoAck: true, consumer: consumer);
}
}
}
8 changes: 8 additions & 0 deletions MusicService/Services/Event/IEventService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace MusicService.Services.Event
{
public interface IEventService
{
public void Publish<T>(string exchange, string topic, T data);
public void subscribe<T>(string exchange, string queue, string topic, Action<T> handler);
}
}
Loading

0 comments on commit 34c3078

Please sign in to comment.