Skip to content

Commit

Permalink
feat: firebase auth and rbac
Browse files Browse the repository at this point in the history
  • Loading branch information
qin-guan committed Jan 21, 2024
1 parent 4e5fab9 commit 866688f
Show file tree
Hide file tree
Showing 6 changed files with 109 additions and 2 deletions.
3 changes: 3 additions & 0 deletions Api/Api.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="FirebaseAdmin" Version="2.4.0" />
<PackageReference Include="Grpc.AspNetCore" Version="2.60.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Grpc.JsonTranscoding" Version="8.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Grpc.Swagger" Version="0.8.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.1">
Expand All @@ -37,6 +39,7 @@
<PackageReference Include="OpenTelemetry.Exporter.Console" Version="1.7.0" />
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.7.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.7.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.7.0" />
</ItemGroup>

</Project>
12 changes: 12 additions & 0 deletions Api/Authorization/AuthorizeMembersAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Api.Entities;
using Microsoft.AspNetCore.Authorization;

namespace Api.Authorization;

public class AuthorizeMembersAttribute: AuthorizeAttribute
{
public AuthorizeMembersAttribute(params UserMemberType[] memberTypes)
{
Roles = string.Join(",", memberTypes);
}
}
31 changes: 31 additions & 0 deletions Api/Authorization/ClaimsTransformation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System.Security.Claims;
using Api.Context;
using Microsoft.AspNetCore.Authentication;
using Microsoft.EntityFrameworkCore;

namespace Api.Authorization;

public class ClaimsTransformation(AppDbContext dbContext): IClaimsTransformation
{
public async Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
{
var sub = principal.Claims.SingleOrDefault(c => c.Type == "user_id");
if (sub is null)
{
return principal;
}

var user = await dbContext.Users.SingleOrDefaultAsync(u => u.FirebaseId == sub.Value);
if (user is null)
{
return principal;
}

var ci = new ClaimsIdentity();
ci.AddClaim(new Claim(ClaimTypes.Role, user.MemberType.ToString()));

principal.AddIdentity(ci);

return principal;
}
}
55 changes: 54 additions & 1 deletion Api/Program.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
using Api.Authorization;
using Api.Context;
using Api.Services.V1;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using Npgsql;
using OpenTelemetry.Trace;
Expand All @@ -9,10 +13,27 @@

builder.Services.AddOpenTelemetry()
.WithTracing(tracerProviderBuilder => tracerProviderBuilder
.AddAspNetCoreInstrumentation()
.AddNpgsql()
.AddHttpClientInstrumentation()
.AddAspNetCoreInstrumentation()
.AddConsoleExporter());

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
var projectId = builder.Configuration.GetValue<string>("Firebase:ProjectId");
options.Authority = $"https://securetoken.google.com/{projectId}";
options.TokenValidationParameters = new TokenValidationParameters
{
ValidIssuer = $"https://securetoken.google.com/{projectId}",
ValidAudience = projectId,
ValidateIssuerSigningKey = true,
ValidateTokenReplay = true
};
});

builder.Services.AddAuthorization();

builder.Services
.AddGrpc()
.AddJsonTranscoding();
Expand All @@ -21,6 +42,33 @@
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "SST Alumni Association API", Version = "v1" });
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
In = ParameterLocation.Header,
Description = "Firebase ID Token",
Name = "Authorization",
Type = SecuritySchemeType.Http,
BearerFormat = "JWT",
Scheme = JwtBearerDefaults.AuthenticationScheme
});
c.AddSecurityRequirement(
new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
}
},
Array.Empty<string>()
}
}
);
var filePath = Path.Combine(AppContext.BaseDirectory, "Api.xml");
c.IncludeXmlComments(filePath);
c.IncludeGrpcXmlComments(filePath, includeControllerXmlComments: true);
Expand All @@ -32,6 +80,8 @@
builder.Configuration.GetConnectionString("Postgres")
);

builder.Services.AddTransient<IClaimsTransformation, ClaimsTransformation>();

var app = builder.Build();

using (var scope = app.Services.CreateScope())
Expand All @@ -40,6 +90,9 @@
await db.Database.MigrateAsync();
}

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

app.MapGrpcService<ArticleServiceV1>();
app.MapGrpcService<UserServiceV1>();
app.MapGrpcService<EventServiceV1>();
Expand Down
5 changes: 5 additions & 0 deletions Api/Services/V1/UserService.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
using Api.Authorization;
using Api.Context;
using Api.Extensions;
using Google.Protobuf.WellKnownTypes;
using Grpc.Core;
using Microsoft.AspNetCore.Authorization;
using Microsoft.EntityFrameworkCore;
using User.V1;
using Enum = System.Enum;
using UserMemberType = Api.Entities.UserMemberType;

namespace Api.Services.V1;

/// <inheritdoc />
public class UserServiceV1(ILogger<UserServiceV1> logger, AppDbContext dbContext) : UserService.UserServiceBase
{
[AuthorizeMembers(UserMemberType.Exco)]
public override async Task<ListUsersResponse> ListUsers(ListUsersRequest request, ServerCallContext context)
{
return new ListUsersResponse
Expand Down
5 changes: 4 additions & 1 deletion Api/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,8 @@
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
"AllowedHosts": "*",
"Firebase": {
"ProjectId": "sstaa-app"
}
}

0 comments on commit 866688f

Please sign in to comment.