I am trying to implement a rest api using the dotNET framework. I am experiencing a problem with the "/secure" endpoint, getting 404 as a response message whether I login or not.
If I don't use IdentityUser class and if I use the /login endpoint which is commented out in the code, the "/secure" endpoint works correctly, getting 401 if not logged in and 200 after logged in.
Also, can you explain me if i need to use builder.Services.AddControllers()?
Thank you all!
using System.IdentityModel.Tokens.Jwt;using System.Security.Claims;using System.Text;using ApiLogin;using ApiLogin.Api;using ApiLogin.Database;using ApiLogin.Handlers;using Microsoft.AspNetCore.Authentication.JwtBearer;using Microsoft.AspNetCore.Authorization;using Microsoft.AspNetCore.Identity;using Microsoft.EntityFrameworkCore;using Microsoft.IdentityModel.Tokens;var builder = WebApplication.CreateBuilder(args);builder.Services.AddDbContext<ApplicationContext>(opt => opt.UseInMemoryDatabase("TodoList"));// // Register Identity servicesbuilder.Services.AddIdentity<IdentityUser, IdentityRole>().AddEntityFrameworkStores<ApplicationContext>().AddDefaultTokenProviders();// Id, Version, Pathvar api = new Api("api-v0", "v0", "/v0");// Swagger// builder.Services.AddControllers();builder.Services.AddEndpointsApiExplorer();builder.Services.AddSwaggerGen((options) => { options.SwaggerDoc(api.Id, new() { Title = api.Id, Version = api.Version });});// Authenticationvar key = Encoding.ASCII.GetBytes("YourSuperSecretKeyThatIsAtLeast32BytesLong!");builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = false, ValidateAudience = false, ValidateLifetime = true, ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey(key) }; });builder.Services.AddAuthorization();var app = builder.Build();app.UsePathBase("/api");// Authenticationapp.UseAuthentication();app.UseAuthorization();// Endpointvar endpoint = app.MapGroup(api.Path).WithGroupName(api.Id);// ApiV0.MapEndpoints(endpoint);var todoItems = endpoint.MapGroup("todoitems").WithTags("ToDoItems");_ = todoItems.MapGet("/", ListTodos.Handle);// Authentication// Endpoint definition// endpoint.MapPost("/login", (LoginModel model) => {// if (model.Username == "testuser" && model.Password == "Password123!") {// var tokenHandler = new JwtSecurityTokenHandler();// var tokenDescriptor = new SecurityTokenDescriptor {// Subject = new ClaimsIdentity(new Claim[] { new Claim(ClaimTypes.Name, model.Username) }),// Expires = DateTime.UtcNow.AddDays(7),// SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)// };// var token = tokenHandler.CreateToken(tokenDescriptor);// var tokenString = tokenHandler.WriteToken(token);// return TypedResults.Ok(new { Token = tokenString });// }// return Results.Unauthorized();// });endpoint.MapPost("/register", async (RegisterModel model, UserManager<IdentityUser> userManager) => { var user = new IdentityUser { UserName = model.Username, Email = model.Email }; var result = await userManager.CreateAsync(user, model.Password); if (result.Succeeded) { return TypedResults.Ok(); } return Results.BadRequest(result.Errors);});endpoint.MapPost("/login", async (LoginModel model, UserManager<IdentityUser> userManager, SignInManager<IdentityUser> signInManager) => { var user = await userManager.FindByNameAsync(model.Username); if (user != null && await userManager.CheckPasswordAsync(user, model.Password)) { var tokenHandler = new JwtSecurityTokenHandler(); var tokenDescriptor = new SecurityTokenDescriptor { Subject = new ClaimsIdentity(new Claim[] { new Claim(ClaimTypes.Name, user.UserName!) }), Expires = DateTime.UtcNow.AddDays(7), SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature) }; var token = tokenHandler.CreateToken(tokenDescriptor); var tokenString = tokenHandler.WriteToken(token); return TypedResults.Ok(new { Token = tokenString }); } return Results.Unauthorized();});endpoint.MapGet("/secure", [Authorize] () => "This is a secure endpoint");// Swagger UIif (app.Environment.IsDevelopment()) { _ = app.UseSwagger(); _ = app.UseSwaggerUI(options => { options.SwaggerEndpoint($"{api.Id}/swagger.yaml", api.Id); });}await app.RunAsync();
Application Context
using ApiLogin.Database.Entities;using Microsoft.AspNetCore.Identity;using Microsoft.AspNetCore.Identity.EntityFrameworkCore;using Microsoft.EntityFrameworkCore;namespace ApiLogin.Database;public class ApplicationContext : IdentityDbContext<IdentityUser> { public DbSet<Todo> Todos => Set<Todo>(); public ApplicationContext() { } public ApplicationContext(DbContextOptions<ApplicationContext> options) : base(options) { }}