Аутентификация базового веб-API ASP.NET
Я пытаюсь настроить аутентификацию в своем веб-сервисе.
Служба создается с помощью ASP.NET Core web api.
Все мои клиенты (приложения WPF) должны использовать одни и те же учетные данные для вызова операций веб-службы.
После некоторых исследований я приступил к базовой аутентификации - отправке имени пользователя и пароля в заголовке HTTP-запроса.
Но после нескольких часов исследований мне кажется, что базовая аутентификация - это не путь в ASP.NET Core.
Большинство ресурсов, которые я нашел, используют аутентификацию с использованием OAuth или другого промежуточного программного обеспечения. Но это, по-моему, слишком велико для моего сценария, а также использование части Identity в ASP.NET Core.
Итак, какой правильный путь для достижения моей цели - простая аутентификация с именем пользователя и паролем в веб-службе ASP.NET Core?
Спасибо заранее!
Ответы
Ответ 1
Вы можете реализовать промежуточное программное обеспечение, которое обрабатывает обычную проверку подлинности.
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);
}
Этот код написан в бета-версии ядра asp.net. Надеюсь, что это поможет.
Ответ 2
Теперь, после того как я указал в правильном направлении, здесь мое полное решение:
Это класс промежуточного программного обеспечения, который выполняется для каждого входящего запроса и проверяет, имеет ли запрос правильные учетные данные. Если учетные данные отсутствуют или если они ошибочны, служба немедленно отвечает неавторизованной ошибкой 401.
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;
}
}
}
Расширение промежуточного программного обеспечения необходимо вызвать в методе Configure для класса запуска
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
app.UseMiddleware<AuthenticationMiddleware>();
app.UseMvc();
}
И это все!:)
Очень хороший ресурс для промежуточного программного обеспечения в .Net Core и аутентификации можно найти здесь:
https://www.exceptionnotfound.net/writing-custom-middleware-in-asp-net-core-1-0/
Ответ 3
Чтобы использовать это только для определенных контроллеров, например, используйте это:
app.UseWhen(x => (x.Request.Path.StartsWithSegments("/api", StringComparison.OrdinalIgnoreCase)),
builder =>
{
builder.UseMiddleware<AuthenticationMiddleware>();
});
Ответ 4
Я думаю, что вы можете использовать JWT (Json Web Tokens).
Сначала вам нужно установить пакет System.IdentityModel.Tokens.Jwt:
$ dotnet add package System.IdentityModel.Tokens.Jwt
Вам понадобится добавить контроллер для генерации токена и аутентификации, как этот:
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);
}
}
После этого обновите класс Startup.cs, чтобы он выглядел следующим образом:
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();
}
}
И что теперь осталось добавить атрибут [Authorize]
в нужные вам контроллеры или действия.
Вот ссылка на полный прямой учебник.
http://www.blinkingcaret.com/2017/09/06/secure-web-api-in-asp-net-core/
Ответ 5
Я реализовал BasicAuthenticationHandler
для базовой аутентификации, чтобы вы могли использовать его со стандартными атрибутами Authorize
и 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(':', StringComparison.OrdinalIgnoreCase);
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;
}
}
Регистрация на Startup.cs - app.UseMiddleware<BasicAuthenticationMiddleware>();
. С помощью этого кода вы можете ограничить любой контроллер стандартным атрибутом Autorize:
[Authorize(ActiveAuthenticationSchemes = "Basic")]
[Route("api/[controller]")]
public class ValuesController : Controller
и используйте атрибут AllowAnonymous
, если вы применяете фильтр авторизации на уровне приложения.
Ответ 6
В этом публичном репозитории Github
https://github.com/boskjoett/BasicAuthWebApi
Вы можете увидеть простой пример веб-API ASP.NET Core 2.2 с конечными точками, защищенными базовой аутентификацией.
Ответ 7
Как справедливо сказано в предыдущих статьях, одним из способов является внедрение специального промежуточного программного обеспечения для базовой аутентификации. Я нашел лучший рабочий код с объяснением в этом блоге:
Базовая аутентификация с пользовательским промежуточным программным обеспечением
Я ссылался на тот же блог, но мне пришлось сделать две адаптации:
- При добавлении промежуточного программного обеспечения в файл запуска → настроить функцию, всегда добавляйте пользовательское промежуточное программное обеспечение перед добавлением app.UseMvc().
При чтении имени пользователя и пароля из файла appsettings.json добавьте статическое свойство только для чтения в файл запуска. Тогда читайте из appsettings.json. Наконец, прочитайте значения из любой точки проекта. Пример:
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;
}
Ответ 8
ASP.NET Core 2.0 с угловым
https://fullstackmark.com/post/13/jwt-authentication-with-aspnet-core-2-web-api-angular-5-net-core-identity-and-facebook-login
Убедитесь, что вы используете тип фильтра аутентификации
[Authorize (AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]