tutorial net español asp c# asp.net authentication asp.net-core

c# - español - asp.net core authentication



Autenticación ASP.NET Core Web API (8)

Ahora, después de que me señalaron en la dirección correcta, aquí está mi solución completa:

Esta es la clase de middleware que se ejecuta en cada solicitud entrante y comprueba si la solicitud tiene las credenciales correctas. Si no hay credenciales presentes o si son incorrectas, el servicio responde con un error no autorizado 401 de inmediato.

public class AuthenticationMiddleware { private readonly RequestDelegate _next; public AuthenticationMiddleware(RequestDelegate next) { _next = next; } public async Task Invoke(HttpContext context) { string authHeader = context.Request.Headers["Authorization"]; if (authHeader != null && authHeader.StartsWith("Basic")) { //Extract credentials string encodedUsernamePassword = authHeader.Substring("Basic ".Length).Trim(); Encoding encoding = Encoding.GetEncoding("iso-8859-1"); string usernamePassword = encoding.GetString(Convert.FromBase64String(encodedUsernamePassword)); int seperatorIndex = usernamePassword.IndexOf('':''); var username = usernamePassword.Substring(0, seperatorIndex); var password = usernamePassword.Substring(seperatorIndex + 1); if(username == "test" && password == "test" ) { await _next.Invoke(context); } else { context.Response.StatusCode = 401; //Unauthorized return; } } else { // no authorization header context.Response.StatusCode = 401; //Unauthorized return; } } }

La extensión de middleware debe llamarse en el método Configure de la clase de inicio del servicio

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { loggerFactory.AddConsole(Configuration.GetSection("Logging")); loggerFactory.AddDebug(); app.UseMiddleware<AuthenticationMiddleware>(); app.UseMvc(); }

¡Y eso es todo! :)

Puede encontrar un muy buen recurso para middleware en .Net Core y autenticación aquí: https://www.exceptionnotfound.net/writing-custom-middleware-in-asp-net-core-1-0/

Tengo dificultades para configurar la autenticación en mi servicio web. El servicio se crea con la API web ASP.NET Core.

Todos mis clientes (aplicaciones WPF) deben usar las mismas credenciales para llamar a las operaciones del servicio web.

Después de investigar un poco, se me ocurrió la autenticación básica: enviar un nombre de usuario y una contraseña en el encabezado de la solicitud HTTP. Pero después de horas de investigación, me parece que la autenticación básica no es el camino a seguir en ASP.NET Core.

La mayoría de los recursos que encontré están implementando la autenticación usando OAuth o algún otro middleware. Pero eso parece ser demasiado grande para mi escenario, además de usar la parte de Identidad de ASP.NET Core.

Entonces, ¿cuál es la forma correcta de lograr mi objetivo: autenticación simple con nombre de usuario y contraseña en un servicio web ASP.NET Core?

¡Gracias por adelantado!


Como bien se dijo en publicaciones anteriores, una de las formas es implementar un middleware de autenticación básico personalizado. Encontré el mejor código de trabajo con explicación en este blog: autenticación básica con middleware personalizado

Remití el mismo blog pero tuve que hacer 2 adaptaciones:

  1. Mientras agrega el middleware en el archivo de inicio -> Configurar función, siempre agregue middleware personalizado antes de agregar app.UseMvc ().
  2. Mientras lee el nombre de usuario, la contraseña del archivo appsettings.json, agregue la propiedad de solo lectura estática en el archivo de inicio. Luego lea de appsettings.json. Finalmente, lea los valores desde cualquier parte del proyecto. Ejemplo:

    public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } public static string UserNameFromAppSettings { get; private set; } public static string PasswordFromAppSettings { get; private set; } //set username and password from appsettings.json UserNameFromAppSettings = Configuration.GetSection("BasicAuth").GetSection("UserName").Value; PasswordFromAppSettings = Configuration.GetSection("BasicAuth").GetSection("Password").Value; }


Creo que puedes ir con JWT (Json Web Tokens).

Primero debe instalar el paquete System.IdentityModel.Tokens.Jwt:

$ dotnet add package System.IdentityModel.Tokens.Jwt

Deberá agregar un controlador para la generación y autenticación de tokens como este:

public class TokenController : Controller { [Route("/token")] [HttpPost] public IActionResult Create(string username, string password) { if (IsValidUserAndPasswordCombination(username, password)) return new ObjectResult(GenerateToken(username)); return BadRequest(); } private bool IsValidUserAndPasswordCombination(string username, string password) { return !string.IsNullOrEmpty(username) && username == password; } private string GenerateToken(string username) { var claims = new Claim[] { new Claim(ClaimTypes.Name, username), new Claim(JwtRegisteredClaimNames.Nbf, new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds().ToString()), new Claim(JwtRegisteredClaimNames.Exp, new DateTimeOffset(DateTime.Now.AddDays(1)).ToUnixTimeSeconds().ToString()), }; var token = new JwtSecurityToken( new JwtHeader(new SigningCredentials( new SymmetricSecurityKey(Encoding.UTF8.GetBytes("Secret Key You Devise")), SecurityAlgorithms.HmacSha256)), new JwtPayload(claims)); return new JwtSecurityTokenHandler().WriteToken(token); } }

Después de esa actualización, la clase Startup.cs se verá a continuación:

namespace WebAPISecurity { public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddMvc(); services.AddAuthentication(options => { options.DefaultAuthenticateScheme = "JwtBearer"; options.DefaultChallengeScheme = "JwtBearer"; }) .AddJwtBearer("JwtBearer", jwtBearerOptions => { jwtBearerOptions.TokenValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("Secret Key You Devise")), ValidateIssuer = false, //ValidIssuer = "The name of the issuer", ValidateAudience = false, //ValidAudience = "The name of the audience", ValidateLifetime = true, //validate the expiration and not before values in the token ClockSkew = TimeSpan.FromMinutes(5) //5 minute tolerance for the expiration date }; }); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseAuthentication(); app.UseMvc(); } }

Y eso es todo, lo que queda ahora es poner el atributo [Authorize] en los Controladores o Acciones que desee.

Aquí hay un enlace de un tutorial completo y directo.

http://www.blinkingcaret.com/2017/09/06/secure-web-api-in-asp-net-core/



He implementado BasicAuthenticationHandler para la autenticación básica para que pueda usarlo con los atributos estándar Authorize y AllowAnonymous .

public class BasicAuthenticationHandler : AuthenticationHandler<BasicAuthenticationOptions> { protected override Task<AuthenticateResult> HandleAuthenticateAsync() { var authHeader = (string)this.Request.Headers["Authorization"]; if (!string.IsNullOrEmpty(authHeader) && authHeader.StartsWith("basic", StringComparison.OrdinalIgnoreCase)) { //Extract credentials string encodedUsernamePassword = authHeader.Substring("Basic ".Length).Trim(); Encoding encoding = Encoding.GetEncoding("iso-8859-1"); string usernamePassword = encoding.GetString(Convert.FromBase64String(encodedUsernamePassword)); int seperatorIndex = usernamePassword.IndexOf('':''); var username = usernamePassword.Substring(0, seperatorIndex); var password = usernamePassword.Substring(seperatorIndex + 1); //you also can use this.Context.Authentication here if (username == "test" && password == "test") { var user = new GenericPrincipal(new GenericIdentity("User"), null); var ticket = new AuthenticationTicket(user, new AuthenticationProperties(), Options.AuthenticationScheme); return Task.FromResult(AuthenticateResult.Success(ticket)); } else { return Task.FromResult(AuthenticateResult.Fail("No valid user.")); } } this.Response.Headers["WWW-Authenticate"]= "Basic realm=/"yourawesomesite.net/""; return Task.FromResult(AuthenticateResult.Fail("No credentials.")); } } public class BasicAuthenticationMiddleware : AuthenticationMiddleware<BasicAuthenticationOptions> { public BasicAuthenticationMiddleware( RequestDelegate next, IOptions<BasicAuthenticationOptions> options, ILoggerFactory loggerFactory, UrlEncoder encoder) : base(next, options, loggerFactory, encoder) { } protected override AuthenticationHandler<BasicAuthenticationOptions> CreateHandler() { return new BasicAuthenticationHandler(); } } public class BasicAuthenticationOptions : AuthenticationOptions { public BasicAuthenticationOptions() { AuthenticationScheme = "Basic"; AutomaticAuthenticate = true; } }

Registro en Startup.cs - app.UseMiddleware<BasicAuthenticationMiddleware>(); . Con este código, puede restringir cualquier controlador con el atributo estándar Autorizar:

[Authorize(ActiveAuthenticationSchemes = "Basic")] [Route("api/[controller]")] public class ValuesController : Controller

y use el atributo AllowAnonymous si aplica el filtro de autorización en el nivel de la aplicación.


Para usar esto solo para controladores específicos, por ejemplo, use esto:

app.UseWhen(x => (x.Request.Path.StartsWithSegments("/api", StringComparison.OrdinalIgnoreCase)), builder => { builder.UseMiddleware<AuthenticationMiddleware>(); });


Puede implementar un middleware que maneje la autenticación básica.

public async Task Invoke(HttpContext context) { var authHeader = context.Request.Headers.Get("Authorization"); if (authHeader != null && authHeader.StartsWith("basic", StringComparison.OrdinalIgnoreCase)) { var token = authHeader.Substring("Basic ".Length).Trim(); System.Console.WriteLine(token); var credentialstring = Encoding.UTF8.GetString(Convert.FromBase64String(token)); var credentials = credentialstring.Split('':''); if(credentials[0] == "admin" && credentials[1] == "admin") { var claims = new[] { new Claim("name", credentials[0]), new Claim(ClaimTypes.Role, "Admin") }; var identity = new ClaimsIdentity(claims, "Basic"); context.User = new ClaimsPrincipal(identity); } } else { context.Response.StatusCode = 401; context.Response.Headers.Set("WWW-Authenticate", "Basic realm=/"dotnetthoughts.net/""); } await _next(context); }

Este código está escrito en una versión beta de asp.net core. Espero eso ayude.