9 Replies
Program.cs
JwtService.cs
AccountController.cs
TestController.cs
appsettings.json
using System.IdentityModel.Tokens.Jwt;
using System.Text;
using LadaServ.Application.Common;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;
using TestAuth.WebApi;
using TestAuth.WebApi.Entities;
using TestAuth.WebApi.Services;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.Configure<MyOptions>(builder.Configuration.GetSection(nameof(MyOptions)));
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); // => remove default claims
builder.Services.AddAuthentication(options =>
{
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.SaveToken = true;
options.TokenValidationParameters = new()
{
ValidateIssuer = true,
ValidIssuer = builder.Configuration["MyOptions:JWT_ISSUER"],
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(
builder.Configuration["MyOptions:SECRET_KEY"]!))
};
});
builder.Services.AddAuthorization();
builder.Services.AddIdentity<AppUser, AppRole>()
.AddEntityFrameworkStores<AppDbContext>();
builder.Services.AddDbContext<AppDbContext>(options =>
{
options.UseSqlite(builder.Configuration.GetConnectionString("DefaultConnection"));
});
builder.Services.AddScoped<JwtService>();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
using System.IdentityModel.Tokens.Jwt;
using System.Text;
using LadaServ.Application.Common;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;
using TestAuth.WebApi;
using TestAuth.WebApi.Entities;
using TestAuth.WebApi.Services;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.Configure<MyOptions>(builder.Configuration.GetSection(nameof(MyOptions)));
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); // => remove default claims
builder.Services.AddAuthentication(options =>
{
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.SaveToken = true;
options.TokenValidationParameters = new()
{
ValidateIssuer = true,
ValidIssuer = builder.Configuration["MyOptions:JWT_ISSUER"],
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(
builder.Configuration["MyOptions:SECRET_KEY"]!))
};
});
builder.Services.AddAuthorization();
builder.Services.AddIdentity<AppUser, AppRole>()
.AddEntityFrameworkStores<AppDbContext>();
builder.Services.AddDbContext<AppDbContext>(options =>
{
options.UseSqlite(builder.Configuration.GetConnectionString("DefaultConnection"));
});
builder.Services.AddScoped<JwtService>();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using LadaServ.Application.Common;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using TestAuth.WebApi.Entities;
namespace TestAuth.WebApi.Services;
public class JwtService
{
private readonly UserManager<AppUser> _userManager;
private readonly IOptions<MyOptions> _options;
public JwtService(UserManager<AppUser> userManager, IOptions<MyOptions> options)
{
_userManager = userManager;
_options = options;
}
public async Task<string> GenerateJwtToken(AppUser user)
{
var claims = new Claim[]
{
new (JwtRegisteredClaimNames.NameId, user.Id.ToString()),
new (JwtRegisteredClaimNames.Email, user.Email!),
new (ClaimTypes.Role, user.Role.ToString()),
new (JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
};
var authSecret = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_options.Value.SECRET_KEY));
var tokenObject = new JwtSecurityToken(
issuer: _options.Value.JWT_ISSUER,
expires: DateTime.Now.AddDays(60),
claims: claims,
signingCredentials: new SigningCredentials(authSecret, SecurityAlgorithms.HmacSha256)
);
string token = new JwtSecurityTokenHandler().WriteToken(tokenObject);
return token;
}
}
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using LadaServ.Application.Common;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using TestAuth.WebApi.Entities;
namespace TestAuth.WebApi.Services;
public class JwtService
{
private readonly UserManager<AppUser> _userManager;
private readonly IOptions<MyOptions> _options;
public JwtService(UserManager<AppUser> userManager, IOptions<MyOptions> options)
{
_userManager = userManager;
_options = options;
}
public async Task<string> GenerateJwtToken(AppUser user)
{
var claims = new Claim[]
{
new (JwtRegisteredClaimNames.NameId, user.Id.ToString()),
new (JwtRegisteredClaimNames.Email, user.Email!),
new (ClaimTypes.Role, user.Role.ToString()),
new (JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
};
var authSecret = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_options.Value.SECRET_KEY));
var tokenObject = new JwtSecurityToken(
issuer: _options.Value.JWT_ISSUER,
expires: DateTime.Now.AddDays(60),
claims: claims,
signingCredentials: new SigningCredentials(authSecret, SecurityAlgorithms.HmacSha256)
);
string token = new JwtSecurityTokenHandler().WriteToken(tokenObject);
return token;
}
}
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using TestAuth.WebApi.DTOs;
using TestAuth.WebApi.Entities;
using TestAuth.WebApi.Services;
namespace TestAuth.WebApi.Controllers;
[ApiController]
[AllowAnonymous]
[Route("accounts")]
public class AccountController : ControllerBase
{
private readonly UserManager<AppUser> _userManager;
private readonly RoleManager<AppRole> _roleManager;
private readonly JwtService _jwtService;
public AccountController(UserManager<AppUser> userManager, RoleManager<AppRole> roleManager, JwtService jwtService)
{
_userManager = userManager;
_roleManager = roleManager;
_jwtService = jwtService;
}
[HttpPost]
public async Task<IActionResult> Register([FromBody] RegisterDto registerDto)
{
var user = new AppUser()
{
Role = RoleEnum.User,
Email = registerDto.Email
};
var result = await _userManager.CreateAsync(user, registerDto.Password!);
var roleExist = await _roleManager.RoleExistsAsync(user.Role.ToString());
if (!roleExist)
{
await _roleManager.CreateAsync(new AppRole { Name = user.Role.ToString() });
}
await _userManager.AddToRoleAsync(user, user.Role.ToString());
var token = await _jwtService.GenerateJwtToken(user!);
return new JsonResult(new { email = user.Email, token = token });
}
}
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using TestAuth.WebApi.DTOs;
using TestAuth.WebApi.Entities;
using TestAuth.WebApi.Services;
namespace TestAuth.WebApi.Controllers;
[ApiController]
[AllowAnonymous]
[Route("accounts")]
public class AccountController : ControllerBase
{
private readonly UserManager<AppUser> _userManager;
private readonly RoleManager<AppRole> _roleManager;
private readonly JwtService _jwtService;
public AccountController(UserManager<AppUser> userManager, RoleManager<AppRole> roleManager, JwtService jwtService)
{
_userManager = userManager;
_roleManager = roleManager;
_jwtService = jwtService;
}
[HttpPost]
public async Task<IActionResult> Register([FromBody] RegisterDto registerDto)
{
var user = new AppUser()
{
Role = RoleEnum.User,
Email = registerDto.Email
};
var result = await _userManager.CreateAsync(user, registerDto.Password!);
var roleExist = await _roleManager.RoleExistsAsync(user.Role.ToString());
if (!roleExist)
{
await _roleManager.CreateAsync(new AppRole { Name = user.Role.ToString() });
}
await _userManager.AddToRoleAsync(user, user.Role.ToString());
var token = await _jwtService.GenerateJwtToken(user!);
return new JsonResult(new { email = user.Email, token = token });
}
}
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using TestAuth.WebApi.Entities;
namespace TestAuth.WebApi.Controllers;
[ApiController]
[Route("test")]
public class TestController : ControllerBase
{
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[HttpGet("get1")]
public string Get1() => "authed";
[Authorize(Roles = nameof(RoleEnum.User))]
[HttpGet("get2")]
public string Get2() => "user";
[AllowAnonymous]
[HttpGet("get3")]
public string Get3() => "anonymous";
}
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using TestAuth.WebApi.Entities;
namespace TestAuth.WebApi.Controllers;
[ApiController]
[Route("test")]
public class TestController : ControllerBase
{
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[HttpGet("get1")]
public string Get1() => "authed";
[Authorize(Roles = nameof(RoleEnum.User))]
[HttpGet("get2")]
public string Get2() => "user";
[AllowAnonymous]
[HttpGet("get3")]
public string Get3() => "anonymous";
}
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"MyOptions": {
"JWT_ISSUER": "https://localhost:7267",
"SECRET_KEY": "my-32-character-ultra-secure-and-ultra-long-secret-AAAultra-long-secret-AAA"
},
"ConnectionStrings": {
"DefaultConnection": "Data Source=helloapp.db"
}
}
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"MyOptions": {
"JWT_ISSUER": "https://localhost:7267",
"SECRET_KEY": "my-32-character-ultra-secure-and-ultra-long-secret-AAAultra-long-secret-AAA"
},
"ConnectionStrings": {
"DefaultConnection": "Data Source=helloapp.db"
}
}
it seems that you are not specifying an
audience
while creating JWT token
specify it in new JwtSecurityToken
or disable it's validation in options.TokenValidationParameters
: ValidateAudience = false
DAMN
it worked finally
thx, what does even audience stands for?
for consumer of the token
issuer is something who creates the token (
auth service
) and audience (or multiple audiences) is something that should verify the user authentication and claims (roles, for example)
both are not required btw
the only thing that is essential for JWT to work is valid signature
even expiration date is not required, but highly recommendedso audience need frontend server url?
yes
like something that provides some services for an authenticated user
without dealing with his credentials
ok, thx
it is not required to be a url though
it can be any string
and issuer can also be any string
but usually it is a url, yes
it is all up to you how to organize this stuff and I already mentioned that it is not required at all
Was this issue resolved? If so, run
/close
- otherwise I will mark this as stale and this post will be archived until there is new activity.