web-dev-qa-db-fra.com

Comment protéger une API Web à l'aide de ASP.NET 5 MVC 6

J'ai une belle application ASP.NET 5/MVC 6 prête à fonctionner. Essentiellement, à cette fin, l’exemple typique d’application que vous obtenez lorsque vous démarrez un nouveau projet est simple. Jusqu'ici je peux:

  • Enregistrer un utilisateur
  • S'identifier 
  • Connectez - Out
  • Protéger une page (forcer la connexion, etc.)

Maintenant, ce que je voudrais, c'est fournir un mécanisme API permettant à une application de se connecter et d'obtenir un jeton d'authentification. Plus précisément, je travaille sur deux applications mobiles à tester, l'une utilisant Angular/Cordova et l'autre utilisant Xamarin. 

J'ai regardé haut et bas et je n'arrive pas à trouver un exemple qui montre comment faire fonctionner ce travail. Tous les exemples que je trouve jusqu'ici supposent que l'utilisateur se connectera via le cycle/formulaire Web normal et sera ensuite dirigé vers une page qui charge Angular et que le jeton d'authentification est déjà dans le navigateur.

Le code pertinent du fichier AccountController.cs pour le contrôleur MVC est ci-dessous. Ce que je veux en définitive, c’est la fonctionnalité équivalente, mais à partir d’un pur appel d’API qui permet à Angular/Xamarin de lui envoyer un nom d’utilisateur/mot de passe et de récupérer un jeton d’authentification ou un échec.

    // 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);
    }

Quelle est la méthode recommandée pour protéger une API Web à l'aide de ASP.NET MVC 6?

21
Samurai Ken

Voici l'article de blog que j'avais promis, il s'agit du premier brouillon et serait utile pour quelqu'un qui a déjà une certaine expérience de ASP.NET MVC 5: Librairie - API Web avec autorisation

Source complète sur Github: https://github.com/kbajpai/bookstore

L'API avec autorisation:

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.