web-dev-qa-db-fra.com

Authentification personnalisée dans ASP.Net-Core

Je travaille sur une application Web qui doit s'intégrer à une base de données d'utilisateurs existante. J'aimerais quand même utiliser les attributs [Authorize], mais je ne veux pas utiliser le cadre Identity. Si je voulais utiliser le framework Identity, j'ajouterais quelque chose comme ceci dans le fichier startup.cs:

services.AddIdentity<ApplicationUser, IdentityRole>(options =>
{
    options.Password.RequireNonLetterOrDigit = false;
}).AddEntityFrameworkStores<ApplicationDbContext>()
  .AddDefaultTokenProviders();

Je suppose que je dois ajouter quelque chose ici, puis créer une sorte de classe qui implémente une interface spécifique? Quelqu'un peut-il me diriger dans la bonne direction? J'utilise RC1 de asp.net 5 en ce moment.

55
rgvassar

La création d'une authentification personnalisée dans ASP.NET Core peut être effectuée de différentes manières. Si vous souhaitez créer à partir de composants existants (mais ne souhaitez pas utiliser d'identité), consultez la catégorie "Sécurité" de la documentation sur docs.asp.net. https://docs.asp.net/en/latest/security/index.html

Quelques articles que vous pourriez trouver utiles:

tilisation de l'intergiciel de cookie sans identité ASP.NET

Autorisation basée sur une stratégie personnalisée

Et bien sûr, si cela échoue ou si les documents ne sont pas assez clairs, le code source est à https://github.com/aspnet/Security qui inclut quelques exemples.

49
natemcmaster

D'après ce que j'ai appris après plusieurs jours de recherche, voici le Guide pour ASP .Net Core MVC 2.x Authentification utilisateur personnalisée

Dans Startup.cs:

Ajoutez les lignes ci-dessous à la méthode ConfigureServices:

public void ConfigureServices(IServiceCollection services)
{

services.AddAuthentication(
    CookieAuthenticationDefaults.AuthenticationScheme
).AddCookie(CookieAuthenticationDefaults.AuthenticationScheme,
    options =>
    {
        options.LoginPath = "/Account/Login";
        options.LogoutPath = "/Account/Logout";
    });

    services.AddMvc();

    // authentication 
    services.AddAuthentication(options =>
    {
       options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    });

    services.AddTransient(
        m => new UserManager(
            Configuration
                .GetValue<string>(
                    DEFAULT_CONNECTIONSTRING //this is a string constant
                )
            )
        );
     services.AddDistributedMemoryCache();
}

gardez à l'esprit que dans le code ci-dessus, nous avons dit que si un utilisateur non authentifié demande une action annotée avec [Authorize], il force la redirection vers /Account/Login url.

Ajoutez les lignes ci-dessous à la méthode Configure:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseBrowserLink();
        app.UseDatabaseErrorPage();
    }
    else
    {
        app.UseExceptionHandler(ERROR_URL);
    }
     app.UseStaticFiles();
     app.UseAuthentication();
     app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: DEFAULT_ROUTING);
    });
}

Créez votre classe UserManager qui gérera également les connexions et la déconnexion. il devrait ressembler à l'extrait ci-dessous (notez que j'utilise dapper):

public class UserManager
{
    string _connectionString;

    public UserManager(string connectionString)
    {
        _connectionString = connectionString;
    }

    public async void SignIn(HttpContext httpContext, UserDbModel user, bool isPersistent = false)
    {
        using (var con = new SqlConnection(_connectionString))
        {
            var queryString = "sp_user_login";
            var dbUserData = con.Query<UserDbModel>(
                queryString,
                new
                {
                    UserEmail = user.UserEmail,
                    UserPassword = user.UserPassword,
                    UserCellphone = user.UserCellphone
                },
                commandType: CommandType.StoredProcedure
            ).FirstOrDefault();

            ClaimsIdentity identity = new ClaimsIdentity(this.GetUserClaims(dbUserData), CookieAuthenticationDefaults.AuthenticationScheme);
            ClaimsPrincipal principal = new ClaimsPrincipal(identity);

            await httpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal);
        }
    }

    public async void SignOut(HttpContext httpContext)
    {
        await httpContext.SignOutAsync();
    }

    private IEnumerable<Claim> GetUserClaims(UserDbModel user)
    {
        List<Claim> claims = new List<Claim>();

        claims.Add(new Claim(ClaimTypes.NameIdentifier, user.Id().ToString()));
        claims.Add(new Claim(ClaimTypes.Name, user.UserFirstName));
        claims.Add(new Claim(ClaimTypes.Email, user.UserEmail));
        claims.AddRange(this.GetUserRoleClaims(user));
        return claims;
    }

    private IEnumerable<Claim> GetUserRoleClaims(UserDbModel user)
    {
        List<Claim> claims = new List<Claim>();

        claims.Add(new Claim(ClaimTypes.NameIdentifier, user.Id().ToString()));
        claims.Add(new Claim(ClaimTypes.Role, user.UserPermissionType.ToString()));
        return claims;
    }
}

Alors peut-être que vous avez un AccountController qui a un Login Action qui devrait ressembler à ceci:

public class AccountController : Controller
{
    UserManager _userManager;

    public AccountController(UserManager userManager)
    {
        _userManager = userManager;
    }

    [HttpPost]
    public IActionResult LogIn(LogInViewModel form)
    {
        if (!ModelState.IsValid)
            return View(form);
         try
        {
            //authenticate
            var user = new UserDbModel()
            {
                UserEmail = form.Email,
                UserCellphone = form.Cellphone,
                UserPassword = form.Password
            };
            _userManager.SignIn(this.HttpContext, user);
             return RedirectToAction("Search", "Home", null);
         }
         catch (Exception ex)
         {
            ModelState.AddModelError("summary", ex.Message);
            return View(form);
         }
    }
}

Vous pouvez maintenant utiliser l'annotation [Authorize] sur n'importe quel Action ou Controller.

Ne hésitez pas à commenter des questions ou des bugs.

57
AmiNadimi