I set an Identity Server for Auth for my Microservices app.
program.cs
using System.Security.Claims;
using AuthMicroservice;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddCors(options =>
{
options.AddPolicy("AllowLocalhost", builder =>
{
builder.WithOrigins("http://localhost:3000")
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials();
});
});
builder.Services.AddAuthorization();
builder.Services.AddAuthentication(IdentityConstants.ApplicationScheme)
.AddCookie(IdentityConstants.ApplicationScheme)
.AddBearerToken(IdentityConstants.BearerScheme);
builder.Services.AddIdentityCore<User>()
.AddEntityFrameworkStores<AppDbContext>()
.AddApiEndpoints();
builder.Services.AddDbContext<AppDbContext>(options =>
options.UseNpgsql(builder.Configuration.GetConnectionString("UsersDb")));
WebApplication app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
app.ApplyMigrations();
}
app.UseHttpsRedirection();
app.UseCors("AllowLocalhost");
app.MapGet("users/me", async (ClaimsPrincipal claims, AppDbContext context) =>
{
string userId = claims.Claims.First(c => c.Type == ClaimTypes.NameIdentifier).Value;
return await context.Users.FindAsync(userId);
})
.RequireAuthorization();
app.MapIdentityApi<User>();
app.Run();
and db context is
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
namespace AuthMicroservice;
public class AppDbContext : IdentityDbContext<User>
{
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
{
}
}
I get full Auth with automatic endpoints with cookies. But for microservices, i want to use Token JWTs.
How to use Identity Server automatic endpoints, but instead of creating cookies, creating http-only tokens? How to validate these tokens in other microservices?
We need to split requirements first.
In your scenario, micro-services should be several asp.net core web API applications, they should be able to receive and validate the access token contained in the request header and return 401/403/correct response. And the Identity Server provides UI to allow users to sign in with thier UserName/Password then generate access token based on user roles/permissions. The token should be stored somewhere based on your business, if you are writing js to call micro-service API, we might store access token in cookie/local storage.
Therefore, what we need to determine is what kind of authorization you are planning to use. For example, JWT auth. Then we need to add token generation codes into your Identity Server application, and add authorization mechanism into your API project. You can refer to this case to see how to generate access token and how to set your API project to validate a token.
In short, the service below should be injected into micro-service app and the generation method should be called after users signed in. You shall need Microsoft.AspNetCore.Authentication.JwtBearer
package.
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
var key = new SymmetricSecurityKey(securityService.Key);
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = false,
ValidateAudience = false,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = builder.Configuration["Jwt:Issuer"],
ValidAudience = builder.Configuration["Jwt:Issuer"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("ThisismySecretKey")),
ClockSkew = TimeSpan.Zero
};
});
private string generateJwt() {
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Jwt:Key"]));
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
var claims = new[] {
new Claim(JwtRegisteredClaimNames.Sub, "user_name"),
new Claim(JwtRegisteredClaimNames.Email, "user_email"),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim("role","admin"),
new Claim(ClaimTypes.NameIdentifier,"admin")
};
var token = new JwtSecurityToken(_config["Jwt:Issuer"],
_config["Jwt:Issuer"],
claims,
expires: DateTime.Now.AddMinutes(120),
signingCredentials: credentials);
return new JwtSecurityTokenHandler().WriteToken(token);
}