it-swarm.com.de

So schützen Sie eine Web-API mit ASP.NET 5 MVC 6

Ich habe eine schöne ASP.NET 5/MVC 6-App, die läuft. Im Wesentlichen für diesen Zweck ist es nur die normale Beispiel-App, die Sie erhalten, wenn Sie ein neues Projekt beginnen, um es einfach zu halten. Bisher kann ich:

  • Einen Benutzer registrieren
  • Anmeldung 
  • Ausloggen
  • Eine Seite schützen (Anmeldung erzwingen usw.)

Nun möchte ich einen API-Mechanismus für eine App bereitstellen, um sich anzumelden und ein Authentifizierungstoken zu erhalten. Im Besonderen arbeite ich an zwei mobilen Apps zum Testen, eine mit Angular/Cordova und eine mit Xamarin. 

Ich habe hoch und niedrig geschaut und kann anscheinend noch kein Beispiel finden, das zeigt, wie dies funktioniert. Jedes Beispiel, das ich bisher gefunden habe, setzt voraus, dass sich der Benutzer über das normale Webformular/Post-Zyklus anmeldet und dann zu einer Seite weitergeleitet wird, die Angular lädt, und das Authentifizierungstoken befindet sich bereits im Browser.

Der relevante Code aus der AccountController.cs-Datei für den MVC-Controller befindet sich unten. Was ich letztendlich möchte, ist die äquivalente Funktionalität, aber von einem reinen API-Aufruf, der es Angular/Xamarin ermöglicht, einen Benutzernamen/ein Kennwort zu senden und ein Authentifizierungs-Token oder einen Fehler zurückzuholen.

    // POST: /Account/Login
    [HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null)
    {
        ViewBag.ReturnUrl = returnUrl;
        if (ModelState.IsValid)
        {
            // This doesn't count login failures towards account lockout
            // To enable password failures to trigger account lockout, set shouldLockout: true
            var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: false);
            if (result.Succeeded)
            {
                return RedirectToLocal(returnUrl);
            }
            if (result.RequiresTwoFactor)
            {
                return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
            }
            if (result.IsLockedOut)
            {
                return View("Lockout");
            }
            else
            {
                ModelState.AddModelError(string.Empty, "Invalid login attempt.");
                return View(model);
            }
        }

        // If we got this far, something failed, redisplay form
        return View(model);
    }

Wie wird empfohlen, ein Web-API mit ASP.NET MVC 6 zu schützen?

21
Samurai Ken

Ich denke, der empfohlene Ansatz zum Sichern von WebApi2 ist ein Autorisierungsserver. Der Authorization Server kümmert sich um das Generieren von Token. Basierend auf this wurde der OAuth2-basierte Autorisierungsserver, der Teil von Katana3 ist, von Asp.Net 5 entfernt. 

Ich gehe davon aus, dass es sich bei Ihrer App noch nicht um eine Live-App handelt, da sich sowohl ASP.NET 5 als auch MVC 6 noch nicht in der endgültigen Veröffentlichungsphase befinden. Wenn Sie also Ihren Identitäts-/Authentifizierungsprozess ändern möchten, können Sie IdentityServer3 von Thinktecture verwenden. 

Dominick Baier hat auf ASP.NET 5 und MVC 6 [] über den The State of Security und den Stand der Dinge, wo IdSvr3 ins Spiel kommt, gebloggt. Dieses Blog enthält einen Link zu einem Github-Repository für den Beispiel-API-Controller sowie einen API-Client. Es hat auch ein Beispiel für eine MVC-Webanwendung. Und es kann mit Asp.Net Identity funktionieren.

UPDATE:

Wenn das für Sie nicht funktioniert, können Sie AspNet.Security.OpenIdConnect.Server versuchen. Beachten Sie, dass es auf Github offene Probleme gibt, daher können Probleme bei der Verwendung von Github auftreten. Beachten Sie auch die Abhängigkeiten, insbesondere azureadwebstacknightly

Bitte beachten Sie, dass sich ASP.NET 5 und MVC 6 in einer stabilen Betaversion befinden, sich aber noch in der beta -Version befinden. Es könnte sich noch ändern. 

IdSvr3 v2.0 befindet sich möglicherweise in der endgültigen Version, wird jedoch von einem separaten Team entwickelt. Und es wurde erst vor zwei Wochen veröffentlicht, so dass meiner Meinung nach, wie bei den meisten Programmen, Dinge auftreten können, die ihre Tests möglicherweise verpasst haben. Beachten Sie das ASP.NET-Team der letzten Woche, hat über die Version von IdSvr3 (v2.0) getwittert, so dass es scheint, als würden sie es unterstützen.

3
Frank Fajardo

Hier ist der Blog-Post, den ich versprochen hatte. Dies ist der erste Entwurf und wäre hilfreich für jemanden, der etwas Erfahrung mit ASP.NET MVC 5 hat: Bookstore - Web-API mit Autorisierung

Vollständige Quelle bei Github: https://github.com/kbajpai/bookstore

Die API mit Autorisierung:

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Http.Description;
using Bookstore.Models;

namespace Bookstore.Controllers
{
  public class BooksController : ApiController
  {
    private BooksDbContext db = new BooksDbContext();

    // GET: api/Books
    [Authorize(Roles="superuser,user")]
    public IQueryable<Book> GetBooks()
    {
      return db.Books;
    }

    // GET: api/Books/5
    [ResponseType(typeof(Book))]
    [Authorize(Roles = "superuser,user")]
    public async Task<IHttpActionResult> GetBook(string id)
    {
      Book book = await db.Books.FindAsync(id);
      if (book == null)
      {
        return NotFound();
      }

      return Ok(book);
    }

    // PUT: api/Books/5
    [ResponseType(typeof(void))]
    [Authorize(Roles = "superuser")]
    public async Task<IHttpActionResult> PutBook(string id, Book book)
    {
      if (!ModelState.IsValid)
      {
        return BadRequest(ModelState);
      }

      if (id != book.Id)
      {
        return BadRequest();
      }

      db.Entry(book).State = EntityState.Modified;

      try
      {
        await db.SaveChangesAsync();
      }
      catch (DbUpdateConcurrencyException)
      {
        if (!BookExists(id))
        {
          return NotFound();
        }
        else
        {
          throw;
        }
      }

      return StatusCode(HttpStatusCode.NoContent);
    }

    // POST: api/Books
    [Authorize(Roles = "superuser")]
    [ResponseType(typeof(Book))]
    public async Task<IHttpActionResult> PostBook(Book book)
    {
      if (!ModelState.IsValid)
      {
        return BadRequest(ModelState);
      }

      db.Books.Add(book);

      try
      {
        await db.SaveChangesAsync();
      }
      catch (DbUpdateException)
      {
        if (BookExists(book.Id))
        {
          return Conflict();
        }
        else
        {
          throw;
        }
      }

      return CreatedAtRoute("DefaultApi", new { id = book.Id }, book);
    }

    // DELETE: api/Books/5
    [Authorize(Roles = "superuser")]
    [ResponseType(typeof(Book))]
    public async Task<IHttpActionResult> DeleteBook(string id)
    {
      Book book = await db.Books.FindAsync(id);
      if (book == null)
      {
        return NotFound();
      }

      db.Books.Remove(book);
      await db.SaveChangesAsync();

      return Ok(book);
    }

    protected override void Dispose(bool disposing)
    {
      if (disposing)
      {
        db.Dispose();
      }
      base.Dispose(disposing);
    }

    private bool BookExists(string id)
    {
      return db.Books.Count(e => e.Id == id) > 0;
    }
  }
}
0
Kunal B.