Я борюсь с тем, как настроить аутентификацию в моем веб-сервисе. Служба построена с использованием веб-API ASP.NET Core.
Все мои клиенты (приложения WPF) должны использовать одни и те же учетные данные для вызова операций веб-службы.
После некоторого исследования я придумал базовую аутентификацию - отправку имени пользователя и пароля в заголовке HTTP-запроса. Но после нескольких часов исследований мне кажется, что обычная проверка подлинности - не лучший вариант в ASP.NET Core.
Большинство найденных мной ресурсов реализуют аутентификацию с использованием OAuth или другого промежуточного программного обеспечения. Но это кажется слишком большим для моего сценария, как и для использования идентификационной части ASP.NET Core.
Итак, как правильно достичь моей цели - простой аутентификации с использованием имени пользователя и пароля в веб-службе ASP.NET Core?
Заранее спасибо!
источник
Теперь, когда меня указали в правильном направлении, вот мое полное решение:
Это промежуточный класс, который выполняется при каждом входящем запросе и проверяет, имеет ли запрос правильные учетные данные. Если учетные данные отсутствуют или неверны, служба немедленно отвечает с ошибкой 401 Unauthorized .
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/
источник
Чтобы использовать это только для определенных контроллеров, например, используйте это:
app.UseWhen(x => (x.Request.Path.StartsWithSegments("/api", StringComparison.OrdinalIgnoreCase)), builder => { builder.UseMiddleware<AuthenticationMiddleware>(); });
источник
Я думаю, вы можете пойти с 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/
источник
Я реализовал
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
если вы применяете фильтр авторизации на уровне приложения.источник
В этом общедоступном репозитории Github https://github.com/boskjoett/BasicAuthWebApi вы можете увидеть простой пример веб-API ASP.NET Core 2.2 с конечными точками, защищенными базовой аутентификацией.
источник
Как правильно сказано в предыдущих сообщениях, один из способов - реализовать собственное промежуточное ПО для базовой аутентификации. В этом блоге я нашел лучший рабочий код с объяснением: Basic Auth с настраиваемым промежуточным ПО
Я сослался на тот же блог, но мне пришлось сделать две адаптации:
При чтении имени пользователя и пароля из файла 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; }
источник
Вы можете использовать
ActionFilterAttribute
public class BasicAuthAttribute : ActionFilterAttribute { public string BasicRealm { get; set; } protected NetworkCredential Nc { get; set; } public BasicAuthAttribute(string user,string pass) { this.Nc = new NetworkCredential(user,pass); } public override void OnActionExecuting(ActionExecutingContext filterContext) { var req = filterContext.HttpContext.Request; var auth = req.Headers["Authorization"].ToString(); if (!String.IsNullOrEmpty(auth)) { var cred = System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(auth.Substring(6))) .Split(':'); var user = new {Name = cred[0], Pass = cred[1]}; if (user.Name == Nc.UserName && user.Pass == Nc.Password) return; } filterContext.HttpContext.Response.Headers.Add("WWW-Authenticate", String.Format("Basic realm=\"{0}\"", BasicRealm ?? "Ryadel")); filterContext.Result = new UnauthorizedResult(); } }
и добавьте атрибут в свой контроллер
[BasicAuth("USR", "MyPassword")]
источник
ASP.NET Core 2.0 с Angular
https://fullstackmark.com/post/13/jwt-authentication-with-aspnet-core-2-web-api-angular-5-net-core-identity-and-facebook-login
Обязательно используйте тип фильтра аутентификации
[Авторизовать (AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
источник