Skip to content

Commit fa9c440

Browse files
committed
Refactor auth, docs, and add best practices
Refactored `AuthAttribute` and introduced `JwtAuthAttribute` for improved authentication handling. Added `JWTOrApiKeyAuthenticationMiddleware` and `ApiKeyOrJwtAuthorizeAttribute` to support dual authentication modes (API key and JWT). Enhanced documentation: - Added folder structure and infrastructure setup details in `README.md`. - Introduced best practices for .NET Core in `cloud_architect.mdc`. - Added new modes for code reviewers and documentation writers. Updated `manual.yml` to remove redundancy and improve formatting.
1 parent 5d845cd commit fa9c440

File tree

11 files changed

+354
-2
lines changed

11 files changed

+354
-2
lines changed

.cursor/rules/cloud_architect.mdc

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
---
2+
description: This rule provides comprehensive best practices for developing dotnet applications, covering code organization, security, performance, testing, and common pitfalls. It aims to improve code quality, security posture, and overall efficiency when working with the .NET Core framework.
3+
globs: *.tf,*.bicep,*.json,*.yml,*.yaml,*.cs,*.csproj,*.sln
4+
alwaysApply: false
5+
---
6+
7+
# .NET Core Library Best Practices and Coding Standards
8+
9+
This document outlines the recommended best practices for developing applications and infrastructure using Microsoft .NET Core, Azure DevOps and Azure services. It covers various aspects including solution setup, code organization, security, and tooling to ensure robust, scalable, and secure solutions.
10+
11+
## 1. Code Organization and Structure
12+
13+
A well-organized codebase is crucial for maintainability, scalability, and collaboration. The following guidelines provide a structured approach to organizing your .NET projects.
14+
15+
### Directory Structure Best Practices
16+
17+
Adopt a modular and logical directory structure based on the application's architecture and components.
18+
19+
* **`devops/`**: Contains the root folder for DevOps pipelines for your application.
20+
* **`azure/`**: Contains the source code of Azure DevOps pipelines for your application.
21+
* **`infrastructure/`**: Contains the source code of IaC and platform setup scripts for your application.
22+
* **`bicep/`**: Contains the source code of Bicep templates for your application.
23+
* **`terraform/`**: Contains the source code of Terraform templates for your application.
24+
* **`scripts/`**: Automation scripts for deployment, build processes, etc.
25+
* **`src/`**: Contains the source code of your application.
26+
27+
28+
Example:
29+
30+
root-project/
31+
├── .cursor/
32+
│ └── rules/
33+
├── .git/
34+
├── .github/
35+
│ ├── chatmode
36+
│ ├── instructions
37+
│ └── workflows/
38+
├── devops/
39+
│ └── azure/
40+
├── infrastructure/
41+
│ ├── bicep/
42+
│ └── terraform/
43+
├── scripts/
44+
├── src/
45+
├── .editorconfig
46+
├── .gitattributes
47+
├── .gitignore
48+
├── CHANGELOG.md
49+
├── CODE_OF_CONDUCT.md
50+
├── Directory.Build.props
51+
├── Directory.Build.targets
52+
├── dotnet.ruleset
53+
├── global.json
54+
├── stylecop.json
55+
├── nuget.config
56+
├── project.sln
57+
└── README.md
58+
59+
60+
### File Naming Conventions
61+
62+
Maintain consistency in file naming to improve readability and searchability.
63+
64+
* Use descriptive names that reflect the file's purpose.
65+
* Use a consistent case (e.g., camelCase or kebab-case).
66+
* Use appropriate file extensions (e.g., `.cs`, `.csproj`, `.tf`, `.bicep`).
67+
* For CSharp components, use `ClassName.cs` or `ComponentName.SubComponent.cs`.
68+
69+
Example:
70+
71+
* `user-service.js` (for a user service module)
72+
* `UserProfile.jsx` (for a user profile component)
73+
* `storage-account.tf` (for a Terraform file defining a storage account)
74+
75+
### Module Organization
76+
77+
Divide the application into independent and reusable modules based on functionality.
78+
79+
* Each module should have a clear responsibility and a well-defined interface.
80+
* Minimize dependencies between modules to promote loose coupling.
81+
* Consider using a module bundler (e.g., Webpack, Parcel) to manage dependencies and optimize the build process.
82+
83+
Example:
84+
85+
A `user-management` module could contain components and services related to user authentication, authorization, and profile management.
86+
87+
88+
By following these best practices, you can build robust, scalable, secure, and maintainable .NET applications.
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
---
2+
description: 'Review code for quality and adherence to best practices.'
3+
tools: ['codebase', 'usages', 'vscodeAPI', 'problems', 'fetch', 'githubRepo', 'search']
4+
---
5+
6+
# Code Reviewer Mode
7+
You are an experienced senior developer conducting a thorough code review. Your role is to review the code for quality, best practices, and adherence to [project standards](../copilot-instructions.md) without making direct code changes.
8+
9+
## Analysis Focus
10+
- Analyze code quality, structure, and best practices
11+
- Identify potential bugs, security issues, or performance problems
12+
- Evaluate accessibility and user experience considerations
13+
- Assess maintainability and readability
14+
15+
## Communication Style
16+
- Provide constructive, specific feedback with clear explanations
17+
- Highlight both strengths and areas for improvement
18+
- Ask clarifying questions about design decisions when appropriate
19+
- Suggest alternative approaches when relevant
20+
21+
## Important Guidelines
22+
- DO NOT write or suggest specific code changes directly
23+
- Focus on explaining what should be changed and why
24+
- Provide reasoning behind your recommendations
25+
- Be encouraging while maintaining high standards
26+
27+
When reviewing code, structure your feedback with clear headings and specific examples from the code being reviewed.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
---
2+
description: 'Document code and its functionality.'
3+
tools: ['search']
4+
---
5+
6+
# Documentation Writer Mode
7+
You are a Documentation Writer. Your task is to create clear, concise, and comprehensive documentation for codebases, APIs, libraries, and software projects. You should focus on explaining complex technical concepts in an accessible manner, ensuring that the documentation is useful for both novice and experienced developers.
8+
9+
## Documentation Focus
10+
- Write clear and concise explanations of code functionality
11+
- Include usage examples and code snippets where applicable
12+
- Document any dependencies, configurations, or setup steps required
13+
- Ensure that the documentation is kept up-to-date with code changes
14+
15+
## Communication Style
16+
- Use simple, straightforward language
17+
- Break down complex concepts into manageable sections
18+
- Use bullet points, numbered lists, and headings to organize information
19+
- Provide context and background information when necessary
20+
- Write WebAPI endpoint documentation to be used by MCP server and AI agent along with developers
21+
- Write the web API endpoint documentation in the OpenAPI format, with short summaries and descriptions for each endpoint, including request and response schemas.

.github/copilot-instructions.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
applyTo: '**'
3+
---
4+
5+
You are a cloud solution architect. Your role is to design and oversee the implementation of microservice application based on .NET Core. Your responsibilities include selecting appropriate pattern and best practice, ensuring security and compliance, optimizing perfomrance and stability.
6+
Your expertise in cloud platforms such as Azure, along with your knowledge of networking, security, and DevOps practices, will be crucial in delivering scalable and reliable solutions delivered on cloud.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
applyTo: '**'
3+
---
4+
You are a cloud solution architect. Your role is to design and oversee the implementation of microservice application based on .NET Core. Your responsibilities include selecting appropriate pattern and best practice, ensuring security and compliance, optimizing perfomrance and stability.
5+
Your expertise in cloud platforms such as Azure, along with your knowledge of networking, security, and DevOps practices, will be crucial in delivering scalable and reliable solutions delivered on cloud.

.github/workflows/manual.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,4 @@ jobs:
4444
run: echo ${{ github.run_number }}
4545

4646
- name: Output Run Attempt
47-
run: echo ${{ github.run_attempt }}
47+
run: echo ${{ github.run_attempt }}

README.md

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,65 @@ You can find a useful documentation about how to use the library. The documentat
6464

6565
Documentation available at [Genocs Blog](https://genocs-blog.netlify.app/library/)
6666

67+
68+
## Folders structure
69+
70+
```text
71+
## Repository structure for .NET Solution
72+
73+
root-project/
74+
├── .cursor/
75+
│ ├── rules/
76+
│ │ └── ...
77+
├── .git/
78+
│ └── ...
79+
├── .github/
80+
│ ├── chatmodes
81+
│ │ ├── Code Reviewer.chatmode.md
82+
│ │ ├── Documentation Writer.chatmode.md
83+
│ │ └── ...
84+
│ ├── copilot-instructions.md
85+
│ ├── workflows/
86+
│ │ ├── ...
87+
├── devops/
88+
│ ├── azure
89+
│ │ ├── ci-publish_on_acr.yml
90+
│ │ ├── ci-publish_on_nuget.yml
91+
│ │ └── ...
92+
├── infrastructure/
93+
│ ├── bicep/
94+
│ │ └── ...
95+
│ ├── docker-compose/
96+
│ │ └── ...
97+
│ ├── k8s/
98+
│ │ └── ...
99+
│ ├── terraform/
100+
│ │ └── ...
101+
│ ├── ...
102+
├── scripts/
103+
│ └── ...
104+
├── src/
105+
│ └── ...
106+
├── .dockerignore
107+
├── .editconfig
108+
├── .env
109+
├── .gitattributes
110+
├── .gitignore
111+
├── Directory.Build.props
112+
├── Directory.Build.targets
113+
├── dotnet.ruleset
114+
├── global.json
115+
├── icon.png
116+
├── stylecop.json
117+
├── nuget.config
118+
├── [project].sln
119+
├── README.md
120+
├── LICENSE
121+
├── CHANGELOG.md
122+
├── CONTRIBUTING.md
123+
├── api-workbench.rest
124+
└── ...
125+
67126
## Infrastructure
68127
69128
In this section you can find the infrastructure components you need to execute the solution. Infrastucture components are the database, the enterprice servise bus, the distributed logging, monitoring, tracing systems along with database and many more.
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
using Microsoft.AspNetCore.Mvc;
2+
using Microsoft.AspNetCore.Mvc.Filters;
3+
4+
namespace Genocs.Auth.Attributes;
5+
6+
/// <summary>
7+
/// Authorization attribute that allows access with either valid JWT token or valid API key.
8+
/// </summary>
9+
/// <remarks>
10+
/// This attribute enables dual authentication modes for endpoints:
11+
/// 1. Standard JWT Bearer token authentication
12+
/// 2. API key authentication via x-gnx-apikey header
13+
/// Used primarily for system-to-system communication endpoints that need to support both authentication methods.
14+
/// </remarks>
15+
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
16+
public class ApiKeyOrJwtAuthorizeAttribute : Attribute, IAuthorizationFilter
17+
{
18+
public void OnAuthorization(AuthorizationFilterContext context)
19+
{
20+
// Check if user is authenticated via any method
21+
if (context.HttpContext.User.Identity?.IsAuthenticated == true)
22+
{
23+
return; // Allow access
24+
}
25+
26+
// Check for API key in header
27+
string? apiKey = context.HttpContext.Request.Headers["x-gnx-apikey"];
28+
if (!string.IsNullOrEmpty(apiKey))
29+
{
30+
// API key validation is handled in middleware
31+
// If we reach here with an API key, it means middleware didn't authenticate
32+
context.Result = new UnauthorizedObjectResult("Invalid API key");
33+
return;
34+
}
35+
36+
// No valid authentication found
37+
context.Result = new UnauthorizedObjectResult("Authentication required. Provide either Bearer token or apikey.");
38+
}
39+
}

src/Genocs.Auth/AuthAttribute.cs renamed to src/Genocs.Auth/Attributes/AuthAttribute.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using Microsoft.AspNetCore.Authorization;
22

3-
namespace Genocs.Auth;
3+
namespace Genocs.Auth.Attributes;
44

55
/// <summary>
66
/// The authorization Attribute.
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
using System.IdentityModel.Tokens.Jwt;
2+
using System.Security.Claims;
3+
using Microsoft.AspNetCore.Http;
4+
using Microsoft.Extensions.Configuration;
5+
using Microsoft.IdentityModel.Tokens;
6+
7+
namespace Genocs.Auth;
8+
9+
/// <summary>
10+
/// Middleware for handling JWT authentication and API key authentication.
11+
/// </summary>
12+
/// <remarks>
13+
/// This middleware supports dual authentication modes:
14+
/// 1. API Key authentication via x-gnx-apikey header for system-to-system communication
15+
/// 2. JWT Bearer token authentication for user authentication
16+
/// When API key is provided, it bypasses JWT validation and sets up API key-based claims.
17+
/// </remarks>
18+
public class JWTOrApiKeyAuthenticationMiddleware(RequestDelegate next, IConfiguration configuration)
19+
{
20+
private readonly RequestDelegate _next = next;
21+
private readonly IConfiguration _configuration = configuration;
22+
23+
public async Task Invoke(HttpContext context)
24+
{
25+
// Check for API key authentication first
26+
string? apiKey = context.Request.Headers["x-gnx-apikey"];
27+
if (!string.IsNullOrEmpty(apiKey))
28+
{
29+
if (await ValidateApiKeyAsync(apiKey))
30+
{
31+
// Set up API key-based authentication
32+
var claims = new[]
33+
{
34+
new Claim(ClaimTypes.NameIdentifier, "api-client"),
35+
new Claim(ClaimTypes.Name, "API Client"),
36+
new Claim("auth_type", "apikey"),
37+
new Claim("api_key", apiKey)
38+
};
39+
40+
var identity = new ClaimsIdentity(claims, "ApiKey");
41+
context.User = new ClaimsPrincipal(identity);
42+
43+
await _next(context);
44+
return;
45+
}
46+
else
47+
{
48+
// Invalid API key
49+
context.Response.StatusCode = 401;
50+
await context.Response.WriteAsync("Invalid API key");
51+
return;
52+
}
53+
}
54+
55+
// Check for Firebase JWT authentication
56+
string? authHeader = context.Request.Headers.Authorization;
57+
if (authHeader?.StartsWith("Bearer ") == true)
58+
{
59+
string token = authHeader["Bearer ".Length..].Trim();
60+
61+
try
62+
{
63+
var handler = new JwtSecurityTokenHandler();
64+
var jsonToken = handler.ReadToken(token) as JwtSecurityToken ?? throw new SecurityTokenException("Invalid token format");
65+
var payload = jsonToken.Payload;
66+
var claims = new[]
67+
{
68+
new Claim(ClaimTypes.NameIdentifier, payload["user_id"]?.ToString() ?? string.Empty),
69+
new Claim(ClaimTypes.Name, payload["name"]?.ToString() ?? string.Empty),
70+
new Claim("auth_type", "jwt")
71+
72+
// Add more claims as needed
73+
};
74+
75+
var identity = new ClaimsIdentity(claims, "AuthenticationTypes.Federation");
76+
context.User = new ClaimsPrincipal(identity);
77+
}
78+
catch (Exception)
79+
{
80+
// Token validation failed - but don't return error here
81+
// Let the authorization attributes handle it
82+
}
83+
}
84+
85+
await _next(context);
86+
}
87+
88+
/// <summary>
89+
/// Validates the provided API key against configured valid keys.
90+
/// </summary>
91+
/// <param name="apiKey">The API key to validate.</param>
92+
/// <returns>True if the API key is valid, false otherwise.</returns>
93+
private async Task<bool> ValidateApiKeyAsync(string apiKey)
94+
{
95+
// Get valid API keys from configuration
96+
string[] validApiKeys = _configuration.GetSection("Authentication:ApiKeys").Get<string[]>() ?? [];
97+
98+
// For development/testing
99+
string? devApiKey = _configuration["Authentication:DevApiKey"];
100+
101+
bool isOk = validApiKeys.Contains(apiKey) || (!string.IsNullOrWhiteSpace(devApiKey) && devApiKey == apiKey);
102+
103+
return await Task.FromResult(isOk);
104+
}
105+
}

0 commit comments

Comments
 (0)