Asp. net Core 3.1 MVC
Я пытался настроить вызовы api для своего веб-приложения, использующего идентификационные данные котельной пластины. Когда я вызываю api из приложения windows, получаю html для страницы входа, а ApiAuthenticationHandler.HandleAuthenticateAsyn c () никогда не вызывается. Я не уверен, что мне не хватает. Я не могу найти хороших примеров.
Класс запуска:
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.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddAuthentication(options =>
{
options.AddScheme<ApiAuthenticationHandler>("API","API");
});
services.AddAuthorization(options =>
{
options.FallbackPolicy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build();
});
services.AddDefaultIdentity<IdentityUser>(options =>
{
options.SignIn.RequireConfirmedAccount = true;
options.Password.RequiredLength = 8;
options.Password.RequireDigit = true;
options.Password.RequireNonAlphanumeric = false;
options.Password.RequireUppercase = false;
options.Password.RequireLowercase = true;
options.Password.RequiredUniqueChars = 1;
options.Lockout.MaxFailedAccessAttempts = 10;
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
options.User.RequireUniqueEmail = true;
})
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddTransient<IEmailSender, EmailSender>();
services.Configure<AuthMessageSenderOptions>(Configuration);
services.AddControllersWithViews(options => {
options.RespectBrowserAcceptHeader = true;
}).AddSessionStateTempDataProvider();
services.AddSession();
services.AddRazorPages();
services.Configure<CookiePolicyOptions>(options =>{options.CheckConsentNeeded = context => true; options.MinimumSameSitePolicy = SameSiteMode.None;});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseSession();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
endpoints.MapRazorPages();
});
}
ApiAuthenticationHandler:
public class ApiAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
private readonly UserManager<IdentityUser> _userManager;
private readonly ApplicationDbContext _context;
public const string AuthTypeName = "Basic ";
private const string _authHeaderName = "Authorization";
public ApiAuthenticationHandler(
IOptionsMonitor<AuthenticationSchemeOptions> options,
ILoggerFactory logger,
UrlEncoder encoder,
ISystemClock clock,
UserManager<IdentityUser> userManager,
ApplicationDbContext context)
: base(options, logger, encoder, clock)
{
_userManager = userManager;
_context = context;
}
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
try
{
var authHeader = Request.Headers.Keys.Contains(_authHeaderName) ? (string)Request.Headers[_authHeaderName] : null;
if (authHeader == null)
{
return AuthenticateResult.Fail("Missing Authorization Header");
}
string encodedAuth = (authHeader != null && authHeader.StartsWith(AuthTypeName)) ? authHeader.Substring(AuthTypeName.Length).Trim() : null;
if (string.IsNullOrEmpty(encodedAuth))
{
return AuthenticateResult.Fail("Invalid Authorization Header");
}
var (username, password) = DecodeUserIdAndPassword(encodedAuth);
// Authenticate credentials against database
var founduser = await _context.FetchUser(username);
if (!await _userManager.CheckPasswordAsync(founduser, password))
{
return AuthenticateResult.Fail("Invalid Username or Password");
}
// Populate user: adjust claims as needed
var claims = new[] { new Claim(ClaimTypes.Name, username, ClaimValueTypes.String, AuthTypeName) };
var principal = new ClaimsPrincipal(new ClaimsIdentity(claims, AuthTypeName));
var ticket = new AuthenticationTicket(principal, Scheme.Name);
return AuthenticateResult.Success(ticket);
}
catch
{
// log and reject
return AuthenticateResult.Fail("Invalid Authorization Header");
}
}
private static (string userid, string password) DecodeUserIdAndPassword(string encodedAuth)
{
var userpass = Encoding.UTF8.GetString(Convert.FromBase64String(encodedAuth));
var separator = userpass.IndexOf(':');
if (separator == -1)
return (null, null);
return (userpass.Substring(0, separator), userpass.Substring(separator + 1));
}
}
Контроллер Api
[Route("[Controller]")]
[ApiController]
public class SrcController : ControllerBase
{
private readonly ApplicationDbContext _context;
private readonly UserManager<IdentityUser> _userManager;
public SrcController( UserManager<IdentityUser> userManager, ApplicationDbContext context)
{
_context = context;
_userManager = userManager;
}
[HttpGet]
[Authorize(AuthenticationSchemes ="API")]
public string ServerTime(string id = null) {
return DateTime.Now.ToString();
}
// POST: Src?...
[HttpPost]
public async Task<IActionResult> AddSrcCustomer(string id = null, string name = null, string address = null, string city = null, string state = null, string zip = null, bool? active = null)
{
if (string.IsNullOrEmpty(id)) return BadRequest();
if (string.IsNullOrEmpty(name)) return BadRequest();
if (string.IsNullOrEmpty(address)) return BadRequest();
if (!Char.IsDigit(address, 0)) return BadRequest();
if (string.IsNullOrEmpty(city)) return BadRequest();
if (string.IsNullOrEmpty(state)) return BadRequest();
if (string.IsNullOrEmpty(zip)) return BadRequest();
if (!active.HasValue) return BadRequest();
var cust = await _context.FetchSingleSrc(UserID,id);
if (cust == null)
{
cust = new SrcCustomer
{
User = UserID,
CustID = id,
Name = name,
Address = address,
City = city,
State = state,
Zip = zip,
Active = active.Value,
Posted = DateTime.Now,
ID = Guid.NewGuid()
};
_context.SrcCustomer.Add(cust);
}
else {
cust.CustID = id;
cust.Name = name;
cust.Address = address;
cust.City = city;
cust.State = state;
cust.Zip = zip;
cust.Active = active.Value;
cust.Posted = DateTime.Now;
_context.Update(cust);
}
await _context.SaveChangesAsync();
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!SrcCustomerExists(cust.ID))
{
return NotFound();
}
else
{
throw;
}
}
return CreatedAtAction("Src", cust);
}
private bool SrcCustomerExists(Guid id)
{
return _context.SrcCustomer.Any(e => e.ID == id);
}
private Guid UserID { get { return Guid.Parse(_userManager.GetUserId(User)); } }
}