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?
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?
Share Improve this question edited Mar 21 at 10:22 Tiny Wang 16.5k2 gold badges18 silver badges38 bronze badges asked Mar 20 at 13:57 user29547398user29547398 153 bronze badges 3- Do you mean you have several applications, the one you showed above is responsible for allowing users to enter user name & password and generating access token, then users with different roles/permission should have different tokens to visit allowed APIs. Am I right? – Tiny Wang Commented Mar 21 at 9:20
- a cookie can contain a JWT... "http only" is an attribute of a cookie. So JWT can be sent via cookie, or via a custom header... but if sent as a custom header, it's usually not sent as a cookie. (and isn't what would normally be called "http only"...) – browsermator Commented Mar 24 at 21:04
- Validation usually involves verifying the signature of the JWT. The method the client uses to send the JWT doesn't really matter there. It's just that cookies are sent in a more automatic way. – browsermator Commented Mar 24 at 21:15
1 Answer
Reset to default 0We need to split requirements first.
In your scenario, micro-services should be several asp 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);
}