From 00acb66e39f7b178d58f3f0ec298aec73d7aced9 Mon Sep 17 00:00:00 2001 From: HombreLaser Date: Tue, 15 Nov 2022 21:52:57 -0600 Subject: Añadida autenticación MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/launch.json | 46 +++++++++++++++++++++++++++ .vscode/tasks.json | 41 ++++++++++++++++++++++++ Controllers/MessageController.cs | 17 ++++++++++ Controllers/UsersController.cs | 49 ++++++++++++++++++++--------- Controllers/WeatherForecastController.cs | 3 ++ DTOs/LoginRequest.cs | 8 +++++ DTOs/UserDTO.cs | 8 ++--- Program.cs | 54 ++++++++++++++++++++++++++------ appsettings.Development.json | 4 +++ 9 files changed, 201 insertions(+), 29 deletions(-) create mode 100644 .vscode/launch.json create mode 100644 .vscode/tasks.json create mode 100644 Controllers/MessageController.cs create mode 100644 DTOs/LoginRequest.cs diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..d055f55 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,46 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": ".NET Core Launch (console)", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "build", + "program": "${workspaceFolder}/bin/Debug/net7.0/IdentityAPI.dll", + "args": [], + "cwd": "${workspaceFolder}", + "stopAtEntry": false, + "console": "integratedTerminal" + }, + { + // Use IntelliSense to find out which attributes exist for C# debugging + // Use hover for the description of the existing attributes + // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md + "name": ".NET Core Launch (web)", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "build", + // If you have changed target frameworks, make sure to update the program path. + "program": "${workspaceFolder}/bin/Debug/net7.0/IdentityAPI.dll", + "args": [], + "cwd": "${workspaceFolder}", + "stopAtEntry": false, + // Enable launching a web browser when ASP.NET Core starts. For more information: https://aka.ms/VSCode-CS-LaunchJson-WebBrowser + "serverReadyAction": { + "action": "openExternally", + "pattern": "\\bNow listening on:\\s+(https?://\\S+)" + }, + "env": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "sourceFileMap": { + "/Views": "${workspaceFolder}/Views" + } + }, + { + "name": ".NET Core Attach", + "type": "coreclr", + "request": "attach" + } + ] +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..5e018c1 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,41 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "command": "dotnet", + "type": "process", + "args": [ + "build", + "${workspaceFolder}/IdentityAPI.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "publish", + "command": "dotnet", + "type": "process", + "args": [ + "publish", + "${workspaceFolder}/IdentityAPI.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "watch", + "command": "dotnet", + "type": "process", + "args": [ + "watch", + "run", + "--project", + "${workspaceFolder}/IdentityAPI.csproj" + ], + "problemMatcher": "$msCompile" + } + ] +} \ No newline at end of file diff --git a/Controllers/MessageController.cs b/Controllers/MessageController.cs new file mode 100644 index 0000000..bacaf5c --- /dev/null +++ b/Controllers/MessageController.cs @@ -0,0 +1,17 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.AspNetCore.Authorization; + +namespace IdentityAPI.Controllers { + [ApiController] + [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] + [Route("api/message")] + public class MessageController : ControllerBase { + public MessageController() {} + + [HttpGet] + public async Task Show() { + return Ok(new { message = "Authentication succesful" }); + } + } +} \ No newline at end of file diff --git a/Controllers/UsersController.cs b/Controllers/UsersController.cs index 52c9105..d5dded5 100644 --- a/Controllers/UsersController.cs +++ b/Controllers/UsersController.cs @@ -8,7 +8,7 @@ using Microsoft.EntityFrameworkCore; using System.Text; using System.Security.Claims; using IdentityAPI.Models; -using IdentityAPI.DTO; +using IdentityAPI.DTOs; namespace IdentityAPI.Controllers { [Route("api/users")] @@ -24,30 +24,49 @@ namespace IdentityAPI.Controllers { _manager = manager; } - [HttpPost("signup")] - public async Task PostUser(UserDTO data) { - var user = new IdentityUser { UserName = data.UserName, Email = data.Email }; - var result = await _manager.CreateAsync(user, data.Password); + [HttpPost("signup")] + public async Task SignUp(UserDTO data) { + var user = new IdentityUser { UserName = data.UserName, Email = data.Email }; + var result = await _manager.CreateAsync(user, data.Password); - if(result.Succeeded) - return Ok(new { Token = GenerateToken(user) }); + if(result.Succeeded) + return Ok(new { Token = GenerateToken(user) }); return StatusCode(422, new { error = "The provided user is invalid" }); } - private string GenerateToken(IdentityUser user) { + [HttpPost("login")] + public async Task Login(LoginRequest data) { + if(data != null && data.Email != null && data.Password != null) { + var user = await _manager.FindByEmailAsync(data.Email); + + if(user == null) + return StatusCode(404, new { error = "Nonexistent user" }); + + var result = await _manager.CheckPasswordAsync(user, data.Password); + + if(result) + return Ok(new { Token = GenerateToken(user)} ); + + return StatusCode(401, new { error = "Wrong credentials" }); + } + + return StatusCode(400, new { error = "Invalid request body" }); + } + + private string GenerateToken(IdentityUser user) { var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Jwt:Key"])); - var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); + var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); var expiration = DateTime.UtcNow.AddMinutes(30); - var issuer = _configuration["Jwt:Issuer"]; + //var issuer = _configuration["Jwt:Issuer"]; var claims = new List { - new Claim("sid", user.Id), - new Claim("username", user.UserName), - new Claim("email", user.Email) - }; + new Claim("sid", user.Id), + new Claim("username", user.UserName), + new Claim("email", user.Email) + }; var descriptor = new JwtSecurityToken(issuer: null, audience: null, claims: claims, expires: expiration, signingCredentials: creds); return new JwtSecurityTokenHandler().WriteToken(descriptor); } } -} +} \ No newline at end of file diff --git a/Controllers/WeatherForecastController.cs b/Controllers/WeatherForecastController.cs index 801ee5e..f7fdcdf 100644 --- a/Controllers/WeatherForecastController.cs +++ b/Controllers/WeatherForecastController.cs @@ -1,8 +1,11 @@ using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.AspNetCore.Authorization; namespace IdentityAPI.Controllers; [ApiController] +[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] [Route("[controller]")] public class WeatherForecastController : ControllerBase { diff --git a/DTOs/LoginRequest.cs b/DTOs/LoginRequest.cs new file mode 100644 index 0000000..9bbef43 --- /dev/null +++ b/DTOs/LoginRequest.cs @@ -0,0 +1,8 @@ +namespace IdentityAPI.DTOs { + public class LoginRequest { + #nullable enable + public string? Email { get; set; } + public string? Password { get; set; } + #nullable disable + } +} \ No newline at end of file diff --git a/DTOs/UserDTO.cs b/DTOs/UserDTO.cs index 9336817..963c3fe 100644 --- a/DTOs/UserDTO.cs +++ b/DTOs/UserDTO.cs @@ -1,9 +1,9 @@ -namespace IdentityAPI.DTO { +namespace IdentityAPI.DTOs { public class UserDTO { - #nullable enable + #nullable enable public string? UserName { get; set; } - public string? Email { get; set; } + public string? Email { get; set; } public string? Password { get; set; } - #nullable disable + #nullable disable } } diff --git a/Program.cs b/Program.cs index 28b00d9..a69992d 100644 --- a/Program.cs +++ b/Program.cs @@ -2,6 +2,7 @@ using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.IdentityModel.Tokens; +using Microsoft.OpenApi.Models; using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using System.Text; @@ -15,19 +16,52 @@ builder.Services.AddControllers(); builder.Services.AddDbContext(o => o.UseNpgsql(builder.Configuration.GetConnectionString("ApplicationDbContext"))); builder.Services.AddIdentity() // .AddRoles() - .AddEntityFrameworkStores(); + .AddEntityFrameworkStores() + .AddDefaultTokenProviders(); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); -builder.Services.AddSwaggerGen(); +builder.Services.AddSwaggerGen(c => { + c.SwaggerDoc("v1", new OpenApiInfo { Title = "IdentityAPI", Version = "v1" }); + + c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme + { + Name = "Authorization", + Type = SecuritySchemeType.ApiKey, + Scheme = "Bearer", + BearerFormat = "JWT", + In = ParameterLocation.Header + }); + + c.AddSecurityRequirement(new OpenApiSecurityRequirement + { + { + new OpenApiSecurityScheme + { + Reference = new OpenApiReference + { + Type = ReferenceType.SecurityScheme, + Id = "Bearer" + } + }, + new String[]{} + } + }); + }); // Autenticación con JSON web tokens. -builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) - .AddJwtBearer(options => { - options.TokenValidationParameters = new TokenValidationParameters { - ValidateLifetime = true, - ValidateIssuer = true, - ValidIssuer = builder.Configuration["Jwt:Issuer"], - IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"])) - }; +builder.Services.AddAuthorization(); +builder.Services.AddAuthentication(options => { + options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; + options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; + options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme; + }) + .AddJwtBearer(options => { + options.TokenValidationParameters = new TokenValidationParameters { + ValidateIssuer = false, + ValidateAudience = false, + ValidateLifetime = true, + IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"])), + ClockSkew = TimeSpan.Zero + }; }); builder.Services.Configure(options => { diff --git a/appsettings.Development.json b/appsettings.Development.json index 0c208ae..588f258 100644 --- a/appsettings.Development.json +++ b/appsettings.Development.json @@ -4,5 +4,9 @@ "Default": "Information", "Microsoft.AspNetCore": "Warning" } + }, + "Jwt": { + "Key": "3aa68fb64d638cd66a0485fce8fcdb49", + "Issuer": "jwtissuer.com" } } -- cgit v1.2.3