I've been fighting with my API since it's not accepting my tokens. I generate the tokens via a class with its own signing key and credentials. Does anybody know what am I doing wrong and maybe this can help other members of the community?
What do I do: I ask a GET request with the generated API token. In https://danzai.pidepormi.com/products and it returns Unauthorized.
Example generated token (1 day lifetime): eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImFsZXhAbWljcm9tYXIubmV0IiwibmJmIjoxNjQ2OTExNDgxLCJleHAiOjE2NDY5OTc4ODEsImlhdCI6MTY0NjkxMTQ4MSwiaXNzIjoiZGFuemFpLW9yZGVyZm9ybWUtYXBpIiwiYXVkIjoiZGFuemFpLW9yZGVyZm9ybWUtYXBwIn0.GTGafndN-GH-45mQbktKPF7EtSI3BQkyOSkAMISSUUo
You can check the token is valid by putting it with this signature: Lnk&_sZYp@6rMgSm9Gl9vpzgO8m1?3JzpbCQ7U3y$=kR1n75*Rx6=p_$vd$aP2?7t!
in https://jwt.io/
I leave the classes involved in this case:
ProductController:
[Authorize]
[HttpGet("/products")]
public async Task<ActionResult<List<Product>>> GetProducts()
{
database = DatabaseModel.GetDatabase(configuration);
List<Product> productsToReturn = new();
productsToReturn = ProductMethods.GetProducts(database);
if(productsToReturn.Count > 0)
{
return Ok(productsToReturn);
}
else if(productsToReturn.Count == 0)
{
return NoContent();
}
else
{
return BadRequest();
}
}
Product class and ProductMethods:
public class Product
{
public int id { get; set; }
public string name { get; set; }
public string description { get; set; }
public string image_url { get; set; }
public bool available { get; set; }
public string family_name { get; set; }
public string subfamily_name { get; set; }
public List<Supplier> suppliers { get; set; }
public Supplier selectedSupplier { get; set; }
}
public static class ProductMethods
{
public static List<Product> GetProducts(IDataBase database)
{
try
{
List<Product> productsToReturn = new();
database.StartTransaction();
string SQLText = "SELECT * FROM OBTENERPRODUCTOS";
FbCommand SQLCommand = new FbCommand();
SQLCommand.CommandText = SQLText;
DataTable dataTableProducts = database.Select(SQLCommand);
database.CommitTransaction();
if (dataTableProducts.Rows.Count > 0)
{
foreach (DataRow dataRowProducts in dataTableProducts.Rows)
{
Product productToAdd = new();
Supplier supplierToAdd = new();
if (dataRowProducts["CODIGO"] != DBNull.Value) productToAdd.id = Convert.ToInt32(dataRowProducts["CODIGO"]);
if (dataRowProducts["DESCRIPCION"] != DBNull.Value) productToAdd.description = Convert.ToString(dataRowProducts["DESCRIPCION"]);
if (dataRowProducts["PRECIO"] != DBNull.Value) supplierToAdd.price = Convert.ToDouble(dataRowProducts["PRECIO"]);
if (dataRowProducts["NOMBRE_FAMILIA"] != DBNull.Value) productToAdd.family_name = Convert.ToString(dataRowProducts["NOMBRE_FAMILIA"]);
if (dataRowProducts["NOMBRE_SUBFAMILIA"] != DBNull.Value) productToAdd.subfamily_name = Convert.ToString(dataRowProducts["NOMBRE_SUBFAMILIA"]);
if (dataRowProducts["URL_IMAGEN"] != DBNull.Value) productToAdd.image_url = Convert.ToString(dataRowProducts["URL_IMAGEN"]);
if (dataRowProducts["ID_PROVEEDOR"] != DBNull.Value) supplierToAdd.id = Convert.ToInt32(dataRowProducts["ID_PROVEEDOR"]);
if (dataRowProducts["NOMBRE_PROVEEDOR"] != DBNull.Value) supplierToAdd.name = Convert.ToString(dataRowProducts["NOMBRE_PROVEEDOR"]);
if (dataRowProducts["ACTIVO"] != DBNull.Value) supplierToAdd.active = Convert.ToBoolean(dataRowProducts["ACTIVO"]);
productToAdd.suppliers.Add(supplierToAdd);
productsToReturn.Add(productToAdd);
}
return productsToReturn;
}
else
{
return productsToReturn;
}
}
catch (Exception ex)
{
Console.Error.WriteLine(ex.Message);
Console.Error.WriteLine(ex.InnerException);
database.RollBackTransaction();
throw;
}
}
}
AuthenticatedUser class:
public class AuthenticatedUser : IIdentity
{
public AuthenticatedUser(string authenticateType, bool isAuthenticated, string email)
{
AuthenticationType = authenticateType;
IsAuthenticated = isAuthenticated;
Name = email;
}
public string AuthenticationType { get; }
public bool IsAuthenticated { get; }
public string Name { get; }
}
}
Token class:
public class Token
{
public Token() { }
public string token { get; set; }
public DateTime expires { get; set; }
}
JwtToken class:
public class JwtToken
{
private const string SECRET_KEY = "Lnk&_sZYp@6rMgSm9Gl9vpzgO8m1?3JzpbCQ7U3y$=kR1n75*Rx6=p_$vd$aP2?7t!";
public static readonly SymmetricSecurityKey SIGNING_KEY = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(SECRET_KEY));
public static Token GenerateJwtToken(string email)
{
SigningCredentials credentials = new SigningCredentials(SIGNING_KEY, SecurityAlgorithms.HmacSha256);
AuthenticatedUser authenticatedUser = new(JwtBearerDefaults.AuthenticationScheme, true, email);
SecurityTokenDescriptor securityTokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(authenticatedUser),
Issuer = "danzai-orderforme-api",
Audience = "danzai-orderforme-app",
IssuedAt = DateTime.UtcNow,
SigningCredentials = credentials,
Expires = DateTime.UtcNow.AddMinutes(1440),
};
JwtSecurityTokenHandler securityTokenHandler = new JwtSecurityTokenHandler();
SecurityToken securityToken = securityTokenHandler.CreateToken(securityTokenDescriptor);
string tokenString = securityTokenHandler.WriteToken(securityToken);
Token tokenToReturn = new();
tokenToReturn.token = tokenString;
tokenToReturn.expires = securityToken.ValidTo;
return tokenToReturn;
}
public static string ReadTokenUser(String accessToken)
{
var tokenHandler = new JwtSecurityTokenHandler();
if (accessToken.Contains("Bearer ")) accessToken = accessToken.Split(' ')[1];
var token = tokenHandler.ReadToken(accessToken) as JwtSecurityToken;
string email = token.Claims.First(claim => claim.Type == "unique_name").Value;
return email;
}
}
And finally Program class:
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
StartupUtils.CopyAppSettings(args[0]);
string SECRET_KEY = "Lnk&_sZYp@6rMgSm9Gl9vpzgO8m1?3JzpbCQ7U3y$=kR1n75*Rx6=p_$vd$aP2?7t!";
SymmetricSecurityKey SIGNING_KEY = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(SECRET_KEY));
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = "JwtBearer";
options.DefaultChallengeScheme = "JwtBearer";
})
.AddJwtBearer("JwtBearer", jwtOptions =>
{
jwtOptions.TokenValidationParameters = new TokenValidationParameters()
{
IssuerSigningKey = SIGNING_KEY,
ValidateIssuer = true,
ValidateAudience = true,
ValidIssuer = "danzai-orderforme-api",
ValidAudience = "danzai-orderforme-app",
RequireSignedTokens = true,
ClockSkew = TimeSpan.Zero
};
});
builder.Services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "danzai-orderforme_api", Version = "v1" });
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
Description = "Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"",
Name = "Authorization",
In = ParameterLocation.Header,
Type = SecuritySchemeType.ApiKey,
Scheme = "bearer",
BearerFormat = "JWT"
});
c.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" }
},
new List<string>()
}
});
});
var app = builder.Build();
app.UseCors(options =>
{
//string[] allowedOrigins = { "*" };
//options.WithOrigins(allowedOrigins);
options.AllowAnyMethod();
options.AllowAnyHeader();
options.AllowCredentials();
options.SetIsOriginAllowed(origin => true);
});
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.UseAuthentication();
app.MapControllers();
app.Run();
CodePudding user response:
You just have to change line order for:
app.UseAuthorization();
app.UseAuthentication();
TO
app.UseAuthentication();
app.UseAuthorization();
That will work.